busabase-sdk 0.1.0 → 0.9.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/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createORPCClient } from '@orpc/client';
2
2
  import { OpenAPILink } from '@orpc/openapi-client/fetch';
3
- import { oc } from '@orpc/contract';
3
+ import { oc, eventIterator } from '@orpc/contract';
4
4
  import { z } from 'zod';
5
5
 
6
6
  // src/client.ts
@@ -44,36 +44,24 @@ var RequestUploadUrlVOSchema = z.object({
44
44
  */
45
45
  duplicate: z.boolean().optional(),
46
46
  /** Existing attachment id — present only when `duplicate` is true. */
47
- attachmentId: z.string().optional()
47
+ attachmentId: z.string().optional(),
48
+ /** Host-specific logical asset id, when the app maps uploads into an Asset library. */
49
+ assetId: z.string().optional()
48
50
  });
49
51
  var ConfirmUploadVOSchema = z.object({
50
52
  success: z.boolean(),
51
53
  attachmentId: z.string(),
54
+ /** Host-specific logical asset id, when the app maps uploads into an Asset library. */
55
+ assetId: z.string().optional(),
52
56
  storageKey: z.string(),
53
57
  publicUrl: z.string()
54
58
  });
55
-
56
- // ../../packages/open-domains/attachments/contract.ts
57
- var attachmentsContract = oc.router({
58
- createUploadUrl: oc.route({
59
- method: "POST",
60
- path: "/attachments/upload-urls",
61
- tags: ["Attachments"],
62
- summary: "Request upload URL",
63
- successDescription: "Presigned (or dev) upload URL plus the public URL the file will resolve to."
64
- }).input(RequestUploadUrlInputSchema).output(RequestUploadUrlVOSchema),
65
- confirm: oc.route({
66
- method: "POST",
67
- path: "/attachments/confirmations",
68
- tags: ["Attachments"],
69
- summary: "Confirm upload",
70
- successDescription: "Recorded attachment row and its public URL."
71
- }).input(ConfirmUploadInputSchema).output(ConfirmUploadVOSchema)
72
- });
73
59
  var AssetVOSchema = z.object({
74
60
  id: z.string(),
75
61
  attachmentId: z.string(),
76
62
  name: z.string(),
63
+ contentKind: z.enum(["text", "binary"]),
64
+ metadata: z.record(z.string(), z.unknown()).default({}),
77
65
  fileName: z.string(),
78
66
  mimeType: z.string(),
79
67
  size: z.number().int().nonnegative(),
@@ -84,15 +72,20 @@ var AssetVOSchema = z.object({
84
72
  createdAt: z.string()
85
73
  });
86
74
  var AssetUsageVOSchema = z.object({
75
+ ownerType: z.enum(["drive", "skill", "base", "doc", "file_node"]),
87
76
  nodeId: z.string(),
88
77
  nodeName: z.string(),
89
78
  nodeType: z.string(),
90
79
  /** Node slug, so the UI can link to the owning Base/Doc (`/{type}/{slug}`). */
91
80
  nodeSlug: z.string(),
81
+ /** Drive/Skill mounted path, or null when the usage is not path-based. */
82
+ path: z.string().nullable(),
92
83
  /** Base record id, or null for whole-node usages (e.g. a Doc body). */
93
84
  recordId: z.string().nullable(),
94
85
  /** Attachment field slug, or null for whole-node usages. */
95
86
  fieldSlug: z.string().nullable(),
87
+ /** Doc block id, or null when the usage is not block-based. */
88
+ blockId: z.string().nullable(),
96
89
  createdAt: z.string()
97
90
  });
98
91
  var AssetDetailVOSchema = z.object({
@@ -101,7 +94,26 @@ var AssetDetailVOSchema = z.object({
101
94
  });
102
95
 
103
96
  // ../../packages/busabase-contract/src/domains/assets/contract.ts
97
+ var UpdateAssetMetadataInputSchema = z.object({
98
+ assetId: z.string(),
99
+ metadata: z.record(z.string(), z.unknown()),
100
+ mode: z.enum(["merge", "replace"]).optional().default("merge")
101
+ });
104
102
  var assetsContract = {
103
+ createUploadUrl: oc.route({
104
+ method: "POST",
105
+ path: "/assets/upload-urls",
106
+ tags: ["Assets"],
107
+ summary: "Request asset upload URL",
108
+ successDescription: "Presigned (or dev) upload URL plus the public URL and asset id when identical bytes are already in the library."
109
+ }).input(RequestUploadUrlInputSchema).output(RequestUploadUrlVOSchema),
110
+ confirm: oc.route({
111
+ method: "POST",
112
+ path: "/assets/confirmations",
113
+ tags: ["Assets"],
114
+ summary: "Confirm asset upload",
115
+ successDescription: "Recorded the file and ensured its Busabase Asset library entry."
116
+ }).input(ConfirmUploadInputSchema).output(ConfirmUploadVOSchema),
105
117
  list: oc.route({
106
118
  method: "GET",
107
119
  path: "/assets",
@@ -116,6 +128,13 @@ var assetsContract = {
116
128
  summary: "Get asset detail",
117
129
  successDescription: "Asset metadata plus every place it is referenced (where-used)."
118
130
  }).input(z.object({ assetId: z.string() })).output(AssetDetailVOSchema),
131
+ updateMetadata: oc.route({
132
+ method: "PATCH",
133
+ path: "/assets/{assetId}/metadata",
134
+ tags: ["Assets"],
135
+ summary: "Update asset metadata",
136
+ successDescription: "Updated AI-readable metadata for a file, such as summary, extracted text, tags, source URL, or schema-specific hints."
137
+ }).input(UpdateAssetMetadataInputSchema).output(AssetDetailVOSchema),
119
138
  delete: oc.route({
120
139
  method: "DELETE",
121
140
  path: "/assets/{assetId}",
@@ -160,7 +179,9 @@ var fieldTypeSchema = z.enum([
160
179
  "auto_number",
161
180
  "ai_summary",
162
181
  "ai_tags",
163
- "code"
182
+ "code",
183
+ "json",
184
+ "yaml"
164
185
  ]);
165
186
  var fieldOptionsSchema = z.object({
166
187
  ai: z.object({
@@ -195,7 +216,10 @@ var fieldOptionsSchema = z.object({
195
216
  currency: z.string().optional(),
196
217
  locale: z.string().optional()
197
218
  }).optional(),
198
- targetBaseId: z.string().optional()
219
+ targetBaseId: z.string().optional().describe("Relation target Base id (bse_\u2026). Or pass targetBaseSlug to name it by slug."),
220
+ targetBaseSlug: z.string().optional().describe(
221
+ "Relation target Base by slug \u2014 a convenience alias for targetBaseId, resolved server-side (active bases in the current space). If both are given, targetBaseId wins."
222
+ )
199
223
  }).default({});
200
224
  var baseFieldSchema = z.object({
201
225
  id: z.string(),
@@ -394,6 +418,52 @@ var docNodeType = {
394
418
  ]
395
419
  };
396
420
 
421
+ // ../../packages/busabase-contract/src/domains/filetree/definition.ts
422
+ var fileTreeOperations = (type) => [
423
+ {
424
+ kind: `${type}_file_create`,
425
+ label: "Create file",
426
+ tone: "border-emerald-200 bg-emerald-50 text-emerald-800"
427
+ },
428
+ {
429
+ kind: `${type}_file_update`,
430
+ label: "Update file",
431
+ tone: "border-blue-200 bg-blue-50 text-blue-800"
432
+ },
433
+ {
434
+ kind: `${type}_file_delete`,
435
+ label: "Delete file",
436
+ tone: "border-rose-200 bg-rose-50 text-rose-800"
437
+ },
438
+ {
439
+ kind: `${type}_metadata_update`,
440
+ label: `Update ${type}`,
441
+ tone: "border-violet-200 bg-violet-50 text-violet-800"
442
+ }
443
+ ];
444
+ var makeFileTreeNodeType = (config) => ({
445
+ type: config.type,
446
+ label: config.label,
447
+ icon: config.icon,
448
+ capabilities: { hasDetail: true, creatable: true },
449
+ operations: fileTreeOperations(config.type)
450
+ });
451
+
452
+ // ../../packages/busabase-contract/src/domains/drive/definition.ts
453
+ var driveNodeType = makeFileTreeNodeType({
454
+ type: "drive",
455
+ label: "Drive",
456
+ icon: "hard-drive"});
457
+
458
+ // ../../packages/busabase-contract/src/domains/file-node/definition.ts
459
+ var fileNodeType = {
460
+ type: "file",
461
+ label: "File",
462
+ icon: "file",
463
+ capabilities: { hasDetail: true, creatable: true },
464
+ operations: []
465
+ };
466
+
397
467
  // ../../packages/busabase-contract/src/domains/folder/definition.ts
398
468
  var folderNodeType = {
399
469
  type: "folder",
@@ -404,34 +474,10 @@ var folderNodeType = {
404
474
  };
405
475
 
406
476
  // ../../packages/busabase-contract/src/domains/skill/definition.ts
407
- var skillNodeType = {
477
+ var skillNodeType = makeFileTreeNodeType({
408
478
  type: "skill",
409
479
  label: "Skill",
410
- icon: "sparkles",
411
- capabilities: { hasDetail: true, creatable: true },
412
- operations: [
413
- {
414
- kind: "skill_file_create",
415
- label: "Create file",
416
- tone: "border-emerald-200 bg-emerald-50 text-emerald-800"
417
- },
418
- {
419
- kind: "skill_file_update",
420
- label: "Update file",
421
- tone: "border-blue-200 bg-blue-50 text-blue-800"
422
- },
423
- {
424
- kind: "skill_file_delete",
425
- label: "Delete file",
426
- tone: "border-rose-200 bg-rose-50 text-rose-800"
427
- },
428
- {
429
- kind: "skill_metadata_update",
430
- label: "Update skill",
431
- tone: "border-violet-200 bg-violet-50 text-violet-800"
432
- }
433
- ]
434
- };
480
+ icon: "sparkles"});
435
481
 
436
482
  // ../../packages/busabase-contract/src/domains/registry.ts
437
483
  var GENERIC_NODE_OPERATIONS = [
@@ -457,6 +503,8 @@ var BUILTIN_NODE_TYPES = [
457
503
  folderNodeType,
458
504
  baseNodeType,
459
505
  skillNodeType,
506
+ driveNodeType,
507
+ fileNodeType,
460
508
  docNodeType
461
509
  ];
462
510
  for (const definition of BUILTIN_NODE_TYPES) {
@@ -493,10 +541,10 @@ var nodeSchema = z.lazy(
493
541
  name: z.string(),
494
542
  description: z.string(),
495
543
  metadata: z.object({
496
- storagePrefix: z.string().optional(),
497
544
  entryFile: z.string().optional(),
498
545
  visibility: z.enum(["private", "workspace", "public"]).optional(),
499
- version: z.string().optional()
546
+ version: z.string().optional(),
547
+ assetId: z.string().optional()
500
548
  }).default({}),
501
549
  position: z.number(),
502
550
  createdAt: z.string(),
@@ -505,6 +553,13 @@ var nodeSchema = z.lazy(
505
553
  children: z.array(nodeSchema)
506
554
  })
507
555
  );
556
+ var userRefSchema = z.object({
557
+ id: z.string(),
558
+ name: z.string().nullable(),
559
+ email: z.string().nullable(),
560
+ image: z.string().nullable(),
561
+ role: z.string().nullable().optional()
562
+ });
508
563
  var commitSchema = z.object({
509
564
  id: z.string(),
510
565
  baseId: z.string().nullable(),
@@ -516,6 +571,7 @@ var commitSchema = z.object({
516
571
  operation: z.enum(OPERATION_KINDS),
517
572
  message: z.string(),
518
573
  author: z.string(),
574
+ authorUser: userRefSchema.nullable().optional().default(null),
519
575
  createdAt: z.string()
520
576
  });
521
577
  var operationSchema = z.object({
@@ -551,6 +607,7 @@ var reviewSchema = z.object({
551
607
  id: z.string(),
552
608
  changeRequestId: z.string(),
553
609
  reviewerId: z.string(),
610
+ reviewer: userRefSchema.nullable().optional().default(null),
554
611
  verdict: z.enum(["approved", "rejected"]),
555
612
  reason: z.string().nullable(),
556
613
  visibleOperationHeads: z.record(z.string(), z.string()),
@@ -566,6 +623,7 @@ var commentSchema = z.object({
566
623
  operationId: z.string().nullable(),
567
624
  commitId: z.string().nullable(),
568
625
  authorId: z.string(),
626
+ author: userRefSchema.nullable().optional().default(null),
569
627
  body: z.string(),
570
628
  mentionsAi: z.boolean(),
571
629
  createdAt: z.string(),
@@ -586,6 +644,7 @@ var changeRequestSchema = z.object({
586
644
  "conflict"
587
645
  ]),
588
646
  submittedBy: z.string(),
647
+ submittedByUser: userRefSchema.nullable().optional().default(null),
589
648
  sourceMeta: z.record(z.string(), z.unknown()),
590
649
  reviewPolicySnapshot: z.record(z.string(), z.unknown()),
591
650
  mergeSummary: z.record(z.string(), z.unknown()),
@@ -609,7 +668,7 @@ var agentTaskSchema = z.object({
609
668
  });
610
669
  var searchResultSchema = z.object({
611
670
  id: z.string(),
612
- kind: z.enum(["record", "change_request", "base"]),
671
+ kind: z.enum(["record", "change_request", "base", "file"]),
613
672
  title: z.string(),
614
673
  body: z.string(),
615
674
  eyebrow: z.string(),
@@ -623,6 +682,23 @@ var searchResponseSchema = z.object({
623
682
  hasMore: z.boolean(),
624
683
  results: z.array(searchResultSchema)
625
684
  });
685
+ var liveEventSchema = z.object({
686
+ kind: z.enum([
687
+ "change_request.created",
688
+ "change_request.updated",
689
+ "change_request.deleted",
690
+ "change_request.reviewed",
691
+ "change_request.merged"
692
+ ]),
693
+ spaceId: z.string(),
694
+ actorId: z.string(),
695
+ changeRequestId: z.string(),
696
+ baseId: z.string().nullable(),
697
+ nodeIds: z.array(z.string()),
698
+ recordIds: z.array(z.string()),
699
+ viewIds: z.array(z.string()),
700
+ operationCount: z.number()
701
+ });
626
702
  var auditActionSchema = z.enum([
627
703
  "record.viewed",
628
704
  "change_request.created",
@@ -637,14 +713,18 @@ var auditActionSchema = z.enum([
637
713
  "field.created",
638
714
  "doc.created",
639
715
  "doc.updated",
716
+ "file.created",
640
717
  "skill.created",
718
+ "drive.created",
641
719
  "asset.deleted",
720
+ "asset.metadata_updated",
642
721
  "node.purged"
643
722
  ]);
644
723
  var auditEventSchema = z.object({
645
724
  id: z.string(),
646
725
  action: auditActionSchema,
647
726
  actorId: z.string(),
727
+ actor: userRefSchema.nullable().optional().default(null),
648
728
  baseId: z.string().nullable(),
649
729
  recordId: z.string().nullable(),
650
730
  changeRequestId: z.string().nullable(),
@@ -666,7 +746,13 @@ var createAuditEventInputSchema = z.object({
666
746
  var nodeOperationInputSchema = z.discriminatedUnion("kind", [
667
747
  z.object({
668
748
  kind: z.literal("create"),
749
+ ref: z.string().min(1).optional().describe(
750
+ 'Optional in-change-request temp id for this node. A later operation can set parentNodeRef to this value to nest under it \u2014 e.g. create a folder with ref "growth", then create Bases with parentNodeRef "growth", all in one change request.'
751
+ ),
669
752
  parentNodeId: z.string().optional(),
753
+ parentNodeRef: z.string().min(1).optional().describe(
754
+ "Parent this node under a node an EARLIER operation in the same change request created (matched by its ref). Mutually exclusive with parentNodeId."
755
+ ),
670
756
  nodeType: z.enum(CREATABLE_NODE_TYPES),
671
757
  slug: z.string().min(1).regex(/^[a-z0-9-]+$/),
672
758
  name: z.string().min(1),
@@ -701,7 +787,9 @@ var nodeOperationInputSchema = z.discriminatedUnion("kind", [
701
787
  z.object({
702
788
  kind: z.literal("move"),
703
789
  nodeId: z.string(),
704
- parentNodeId: z.string(),
790
+ // Exactly one of parentNodeId / parentNodeRef (a ref created earlier in this CR).
791
+ parentNodeId: z.string().optional(),
792
+ parentNodeRef: z.string().min(1).optional(),
705
793
  position: z.number().int().optional()
706
794
  })
707
795
  ]);
@@ -710,6 +798,9 @@ var createNodeChangeRequestInputSchema = z.object({
710
798
  'Explanation shown to the human reviewer. Write a conventional-commit style subject \u2014 imperative verb + what + why, e.g. "Reorganize marketing docs under a Campaigns folder".'
711
799
  ),
712
800
  submittedBy: z.string().optional().default("local-producer"),
801
+ autoMerge: z.boolean().optional().default(false).describe(
802
+ "Whether to approve and merge this structural node change immediately. Defaults to false so node Change Request creation is review-first unless explicitly requested."
803
+ ),
713
804
  operations: z.array(nodeOperationInputSchema).min(1)
714
805
  });
715
806
  var createDeleteChangeRequestInputSchema = z.object({
@@ -791,6 +882,7 @@ var recordSchema = z.object({
791
882
  parentCommitId: z.string().nullable(),
792
883
  status: z.enum(["active", "archived"]),
793
884
  createdBy: z.string(),
885
+ createdByUser: userRefSchema.nullable().optional().default(null),
794
886
  archivedAt: z.string().nullable(),
795
887
  createdAt: z.string(),
796
888
  updatedAt: z.string(),
@@ -816,6 +908,15 @@ var createChangeRequestInputSchema = z.object({
816
908
  ),
817
909
  submittedBy: z.string().optional().default("local-producer")
818
910
  });
911
+ var createBulkChangeRequestInputSchema = z.object({
912
+ records: z.array(z.record(z.string(), z.unknown())).min(1).max(1e3).describe(
913
+ "Field-value maps, one per record to create, each keyed by field slug. All records are proposed as a SINGLE change request (one review, one merge) \u2014 use this to import/seed many rows at once instead of one change request per record. Capped at 1000; for very large loads prefer a dedicated import job. Always give each record's PRIMARY field a short human-readable value."
914
+ ),
915
+ message: z.string().optional().default("Bulk create records").describe(
916
+ 'Explanation shown to the human reviewer for the whole batch \u2014 e.g. "Import 240 June webinar leads".'
917
+ ),
918
+ submittedBy: z.string().optional().default("local-producer")
919
+ });
819
920
  var recordFieldFilterInputSchema = z.object({
820
921
  baseId: z.string().optional(),
821
922
  fieldSlug: z.string().min(1),
@@ -874,6 +975,7 @@ var viewSchema = z.object({
874
975
  config: viewConfigSchema,
875
976
  status: z.enum(["active", "archived"]),
876
977
  createdBy: z.string(),
978
+ createdByUser: userRefSchema.nullable().optional().default(null),
877
979
  archivedAt: z.string().nullable(),
878
980
  createdAt: z.string(),
879
981
  updatedAt: z.string()
@@ -967,6 +1069,13 @@ var baseContract = {
967
1069
  summary: "Create Change Request in Base",
968
1070
  successDescription: "Created change request for review."
969
1071
  }).input(createChangeRequestInputSchema.extend({ baseId: z.string() })).output(changeRequestSchema),
1072
+ createBulkChangeRequest: oc.route({
1073
+ method: "POST",
1074
+ path: "/bases/{baseId}/records/bulk-change-request",
1075
+ tags: ["Bases", "Change Requests"],
1076
+ summary: "Create bulk record Change Request in Base",
1077
+ successDescription: "Created one change request proposing many record creates."
1078
+ }).input(createBulkChangeRequestInputSchema.extend({ baseId: z.string() })).output(changeRequestSchema),
970
1079
  createField: oc.route({
971
1080
  method: "POST",
972
1081
  path: "/bases/{baseId}/fields",
@@ -1192,67 +1301,65 @@ var docContract = {
1192
1301
  successDescription: "Created a change request that proposes a new Doc body."
1193
1302
  }).input(createDocChangeRequestInputSchema.extend({ nodeId: z.string() })).output(changeRequestSchema)
1194
1303
  };
1195
- var folderSchema = z.object({
1196
- node: nodeSchema,
1197
- children: z.array(nodeSchema)
1198
- });
1199
- var folderContract = {
1200
- list: oc.route({
1201
- method: "GET",
1202
- path: "/folders",
1203
- tags: ["Folders"],
1204
- summary: "List Folder nodes",
1205
- successDescription: "Folder nodes with their direct children."
1206
- }).output(z.array(folderSchema)),
1207
- get: oc.route({
1208
- method: "GET",
1209
- path: "/folders/{nodeId}",
1210
- tags: ["Folders"],
1211
- summary: "Get Folder node",
1212
- successDescription: "Folder node and its direct children."
1213
- }).input(z.object({ nodeId: z.string() })).output(folderSchema)
1214
- };
1215
- var skillFileSchema = z.object({
1304
+ var fileTreeFileSchema = z.object({
1216
1305
  path: z.string(),
1217
1306
  name: z.string(),
1218
- type: z.enum(["file", "folder"]),
1219
1307
  size: z.number(),
1220
- updatedAt: z.string().nullable()
1221
- });
1222
- var skillSchema = z.object({
1308
+ updatedAt: z.string().nullable(),
1309
+ mimeType: z.string().nullable(),
1310
+ assetId: z.string(),
1311
+ displayName: z.string().nullable()
1312
+ });
1313
+ var assetFileInputSchema = z.object({
1314
+ path: z.string().min(1),
1315
+ assetId: z.string().min(1),
1316
+ displayName: z.string().optional(),
1317
+ mimeType: z.string().optional()
1318
+ }).strict();
1319
+ var textFileInputSchema = z.object({
1320
+ path: z.string().min(1),
1321
+ content: z.string().default(""),
1322
+ mimeType: z.string().optional()
1323
+ }).strict();
1324
+ var assetFileOperationInputSchema = z.object({
1325
+ kind: z.enum(["create", "update"]),
1326
+ path: z.string().min(1),
1327
+ assetId: z.string().min(1),
1328
+ displayName: z.string().optional(),
1329
+ mimeType: z.string().optional(),
1330
+ baseContentHash: z.string().optional()
1331
+ }).strict();
1332
+ var textFileOperationInputSchema = z.object({
1333
+ kind: z.enum(["create", "update"]),
1334
+ path: z.string().min(1),
1335
+ content: z.string(),
1336
+ mimeType: z.string().optional(),
1337
+ baseContentHash: z.string().optional()
1338
+ }).strict();
1339
+ var fileTreeNodeSchema = z.object({
1223
1340
  node: nodeSchema,
1224
- storagePrefix: z.string(),
1225
1341
  entryFile: z.string(),
1226
1342
  visibility: z.enum(["private", "workspace", "public"]),
1227
1343
  version: z.string(),
1228
- files: z.array(skillFileSchema)
1344
+ files: z.array(fileTreeFileSchema)
1229
1345
  });
1230
- var createSkillInputSchema = z.object({
1346
+ var createFileTreeInputSchema = z.object({
1231
1347
  parentNodeId: z.string().optional(),
1232
1348
  slug: z.string().min(1).regex(/^[a-z0-9-]+$/),
1233
1349
  name: z.string().min(1),
1234
1350
  description: z.string().optional().default(""),
1235
1351
  visibility: z.enum(["private", "workspace", "public"]).optional().default("private"),
1236
1352
  version: z.string().optional().default("0.1.0"),
1237
- files: z.array(
1238
- z.object({
1239
- path: z.string().min(1),
1240
- content: z.string().default("")
1241
- })
1242
- ).optional().default([])
1353
+ files: z.array(z.union([assetFileInputSchema, textFileInputSchema])).optional().default([])
1243
1354
  });
1244
- var skillFileOperationInputSchema = z.discriminatedUnion("kind", [
1245
- z.object({
1246
- kind: z.enum(["create", "update"]),
1247
- path: z.string().min(1),
1248
- content: z.string(),
1249
- baseContentHash: z.string().optional()
1250
- }),
1355
+ var fileTreeFileOperationInputSchema = z.union([
1356
+ assetFileOperationInputSchema,
1357
+ textFileOperationInputSchema,
1251
1358
  z.object({
1252
1359
  kind: z.literal("delete"),
1253
1360
  path: z.string().min(1),
1254
1361
  baseContentHash: z.string().optional()
1255
- }),
1362
+ }).strict(),
1256
1363
  z.object({
1257
1364
  kind: z.literal("metadata_update"),
1258
1365
  metadata: z.object({
@@ -1260,68 +1367,152 @@ var skillFileOperationInputSchema = z.discriminatedUnion("kind", [
1260
1367
  visibility: z.enum(["private", "workspace", "public"]).optional(),
1261
1368
  version: z.string().optional()
1262
1369
  }).default({})
1263
- })
1370
+ }).strict()
1264
1371
  ]);
1265
- var createSkillChangeRequestInputSchema = z.object({
1266
- message: z.string().optional().default("Update skill").describe(
1267
- 'Explanation shown to the human reviewer. Write a conventional-commit style subject \u2014 imperative verb + what + why, e.g. "Rewrite SKILL.md quickstart for the new auth flow".'
1372
+ var createFileTreeChangeRequestInputSchema = z.object({
1373
+ message: z.string().optional().default("Update file tree").describe(
1374
+ 'Explanation shown to the human reviewer. Write a conventional-commit style subject \u2014 imperative verb + what + why, e.g. "Rewrite README.md quickstart for the new auth flow".'
1268
1375
  ),
1269
1376
  submittedBy: z.string().optional().default("local-producer"),
1270
- operations: z.array(skillFileOperationInputSchema).min(1)
1377
+ operations: z.array(fileTreeFileOperationInputSchema).min(1)
1378
+ });
1379
+ var makeFileTreeContract = (routeBase, tag) => {
1380
+ const label = tag.endsWith("s") ? tag.slice(0, -1) : tag;
1381
+ const basePath = `/${routeBase}`;
1382
+ return {
1383
+ list: oc.route({
1384
+ method: "GET",
1385
+ path: basePath,
1386
+ tags: [tag],
1387
+ summary: `List ${label} nodes`,
1388
+ successDescription: `${label} nodes with their Asset-backed file trees.`
1389
+ }).output(z.array(fileTreeNodeSchema)),
1390
+ create: oc.route({
1391
+ method: "POST",
1392
+ path: basePath,
1393
+ tags: [tag],
1394
+ summary: `Create ${label} node`,
1395
+ successDescription: `Created ${label} node and initialized file tree.`
1396
+ }).input(createFileTreeInputSchema).output(fileTreeNodeSchema),
1397
+ get: oc.route({
1398
+ method: "GET",
1399
+ path: `${basePath}/{nodeId}`,
1400
+ tags: [tag],
1401
+ summary: `Get ${label} node`,
1402
+ successDescription: `${label} node detail and file tree.`
1403
+ }).input(z.object({ nodeId: z.string() })).output(fileTreeNodeSchema),
1404
+ listFiles: oc.route({
1405
+ method: "GET",
1406
+ path: `${basePath}/{nodeId}/files`,
1407
+ tags: [tag],
1408
+ summary: `List ${label} files`,
1409
+ successDescription: `Asset-backed files mounted under the ${label} node.`
1410
+ }).input(z.object({ nodeId: z.string() })).output(z.array(fileTreeFileSchema)),
1411
+ readFile: oc.route({
1412
+ method: "GET",
1413
+ path: `${basePath}/{nodeId}/files/{+filePath}`,
1414
+ tags: [tag],
1415
+ summary: `Read ${label} file`,
1416
+ successDescription: `${label} file content and content hash.`
1417
+ }).input(z.object({ nodeId: z.string(), filePath: z.string() })).output(
1418
+ z.object({
1419
+ nodeId: z.string(),
1420
+ path: z.string(),
1421
+ encoding: z.enum(["utf8", "url"]),
1422
+ content: z.string(),
1423
+ mimeType: z.string(),
1424
+ assetId: z.string(),
1425
+ displayName: z.string().nullable(),
1426
+ assetUrl: z.string().nullable(),
1427
+ contentHash: z.string()
1428
+ })
1429
+ ),
1430
+ createChangeRequest: oc.route({
1431
+ method: "POST",
1432
+ path: `${basePath}/{nodeId}/change-requests`,
1433
+ tags: [tag, "Change Requests"],
1434
+ summary: `Create ${label} change request`,
1435
+ successDescription: `Created file-tree change request for a ${label} node.`
1436
+ }).input(createFileTreeChangeRequestInputSchema.extend({ nodeId: z.string() })).output(changeRequestSchema)
1437
+ };
1438
+ };
1439
+
1440
+ // ../../packages/busabase-contract/src/domains/drive/contract.ts
1441
+ var driveContract = makeFileTreeContract("drives", "Drives");
1442
+ z.object({
1443
+ assetId: z.string()
1444
+ });
1445
+ var FileNodeVOSchema = z.object({
1446
+ node: nodeSchema,
1447
+ asset: AssetVOSchema
1448
+ });
1449
+
1450
+ // ../../packages/busabase-contract/src/domains/file-node/contract.ts
1451
+ var createFileNodeInputSchema = z.object({
1452
+ parentNodeId: z.string().optional(),
1453
+ slug: z.string().min(1).regex(/^[a-z0-9-]+$/),
1454
+ name: z.string().min(1),
1455
+ description: z.string().optional().default(""),
1456
+ assetId: z.string().min(1)
1271
1457
  });
1272
- var skillContract = {
1458
+ var fileContract = {
1273
1459
  list: oc.route({
1274
1460
  method: "GET",
1275
- path: "/skills",
1276
- tags: ["Skills"],
1277
- summary: "List Skill nodes",
1278
- successDescription: "Skill nodes with their storage-backed file trees."
1279
- }).output(z.array(skillSchema)),
1461
+ path: "/files",
1462
+ tags: ["Files"],
1463
+ summary: "List File nodes",
1464
+ successDescription: "Workspace File nodes with their backing Asset metadata."
1465
+ }).output(z.array(FileNodeVOSchema)),
1280
1466
  create: oc.route({
1281
1467
  method: "POST",
1282
- path: "/skills",
1283
- tags: ["Skills"],
1284
- summary: "Create Skill node",
1285
- successDescription: "Created Skill node and initialized file tree."
1286
- }).input(createSkillInputSchema).output(skillSchema),
1468
+ path: "/files",
1469
+ tags: ["Files"],
1470
+ summary: "Create File node",
1471
+ successDescription: "Created a first-class File node that references an Asset."
1472
+ }).input(createFileNodeInputSchema).output(FileNodeVOSchema),
1287
1473
  get: oc.route({
1288
1474
  method: "GET",
1289
- path: "/skills/{nodeId}",
1290
- tags: ["Skills"],
1291
- summary: "Get Skill node",
1292
- successDescription: "Skill node detail and file tree."
1293
- }).input(z.object({ nodeId: z.string() })).output(skillSchema),
1294
- listFiles: oc.route({
1475
+ path: "/files/{nodeId}",
1476
+ tags: ["Files"],
1477
+ summary: "Get File node",
1478
+ successDescription: "File node detail and backing Asset metadata."
1479
+ }).input(z.object({ nodeId: z.string() })).output(FileNodeVOSchema)
1480
+ };
1481
+ var folderSchema = z.object({
1482
+ node: nodeSchema,
1483
+ children: z.array(nodeSchema)
1484
+ });
1485
+ var folderContract = {
1486
+ list: oc.route({
1295
1487
  method: "GET",
1296
- path: "/skills/{nodeId}/files",
1297
- tags: ["Skills"],
1298
- summary: "List Skill files",
1299
- successDescription: "Storage-backed files under the Skill node prefix."
1300
- }).input(z.object({ nodeId: z.string() })).output(z.array(skillFileSchema)),
1301
- readFile: oc.route({
1488
+ path: "/folders",
1489
+ tags: ["Folders"],
1490
+ summary: "List Folder nodes",
1491
+ successDescription: "Folder nodes with their direct children."
1492
+ }).output(z.array(folderSchema)),
1493
+ get: oc.route({
1302
1494
  method: "GET",
1303
- path: "/skills/{nodeId}/files/{+filePath}",
1304
- tags: ["Skills"],
1305
- summary: "Read Skill file",
1306
- successDescription: "Skill file content and content hash."
1307
- }).input(z.object({ nodeId: z.string(), filePath: z.string() })).output(
1308
- z.object({
1309
- nodeId: z.string(),
1310
- path: z.string(),
1311
- content: z.string(),
1312
- contentHash: z.string()
1313
- })
1314
- ),
1315
- createChangeRequest: oc.route({
1316
- method: "POST",
1317
- path: "/skills/{nodeId}/change-requests",
1318
- tags: ["Skills", "Change Requests"],
1319
- summary: "Create Skill change request",
1320
- successDescription: "Created file-tree change request for a Skill node."
1321
- }).input(createSkillChangeRequestInputSchema.extend({ nodeId: z.string() })).output(changeRequestSchema)
1495
+ path: "/folders/{nodeId}",
1496
+ tags: ["Folders"],
1497
+ summary: "Get Folder node",
1498
+ successDescription: "Folder node and its direct children."
1499
+ }).input(z.object({ nodeId: z.string() })).output(folderSchema)
1322
1500
  };
1323
1501
 
1502
+ // ../../packages/busabase-contract/src/domains/skill/contract.ts
1503
+ var skillContract = makeFileTreeContract("skills", "Skills");
1504
+
1324
1505
  // ../../packages/busabase-contract/src/contract/busabase.ts
1506
+ var changeRequestBatchResultSchema = z.object({
1507
+ results: z.array(
1508
+ z.object({
1509
+ changeRequestId: z.string(),
1510
+ ok: z.boolean(),
1511
+ status: z.string().optional(),
1512
+ error: z.string().optional()
1513
+ })
1514
+ )
1515
+ });
1325
1516
  var busabaseContractRoutes = {
1326
1517
  auth: {
1327
1518
  verify: oc.route({
@@ -1337,7 +1528,7 @@ var busabaseContractRoutes = {
1337
1528
  path: "/search",
1338
1529
  tags: ["Search"],
1339
1530
  summary: "Search Busabase",
1340
- successDescription: "Paginated search results across records, change requests, and Bases."
1531
+ successDescription: "Paginated search results across records, change requests, Bases, File nodes, and Assets."
1341
1532
  }).input(searchInputSchema).output(searchResponseSchema),
1342
1533
  nodes: {
1343
1534
  list: oc.route({
@@ -1410,11 +1601,17 @@ var busabaseContractRoutes = {
1410
1601
  successDescription: "Change requests awaiting an external agent (request-changes or @ai mentions)."
1411
1602
  }).output(z.array(agentTaskSchema))
1412
1603
  },
1604
+ live: {
1605
+ // RPC-only by design: no `.route(...)`, so OpenAPI generation and MCP tool
1606
+ // discovery skip this long-lived Event Iterator while `/api/rpc` stays typed.
1607
+ subscribe: oc.output(eventIterator(liveEventSchema))
1608
+ },
1413
1609
  bases: baseContract,
1414
1610
  skills: skillContract,
1611
+ drives: driveContract,
1612
+ files: fileContract,
1415
1613
  docs: docContract,
1416
1614
  folders: folderContract,
1417
- attachments: attachmentsContract,
1418
1615
  assets: assetsContract,
1419
1616
  changeRequests: {
1420
1617
  list: oc.route({
@@ -1438,6 +1635,17 @@ var busabaseContractRoutes = {
1438
1635
  summary: "Review change request",
1439
1636
  successDescription: "Reviewed change request."
1440
1637
  }).input(reviewChangeRequestInputSchema.extend({ changeRequestId: z.string() })).output(changeRequestSchema),
1638
+ reviewMany: oc.route({
1639
+ method: "POST",
1640
+ path: "/change-requests/reviews",
1641
+ tags: ["Change Requests"],
1642
+ summary: "Review many change requests",
1643
+ successDescription: "Per-change-request review results (failures isolated \u2014 one bad id does not abort the rest)."
1644
+ }).input(
1645
+ reviewChangeRequestInputSchema.extend({
1646
+ changeRequestIds: z.array(z.string()).min(1).max(100)
1647
+ })
1648
+ ).output(changeRequestBatchResultSchema),
1441
1649
  close: oc.route({
1442
1650
  method: "POST",
1443
1651
  path: "/change-requests/{changeRequestId}/close",
@@ -1457,7 +1665,14 @@ var busabaseContractRoutes = {
1457
1665
  record: recordSchema.nullable(),
1458
1666
  view: viewSchema.nullable()
1459
1667
  })
1460
- )
1668
+ ),
1669
+ mergeMany: oc.route({
1670
+ method: "POST",
1671
+ path: "/change-requests/merge",
1672
+ tags: ["Change Requests"],
1673
+ summary: "Merge many change requests",
1674
+ successDescription: "Per-change-request merge results (each merged in its own transaction; failures isolated)."
1675
+ }).input(z.object({ changeRequestIds: z.array(z.string()).min(1).max(100) })).output(changeRequestBatchResultSchema)
1461
1676
  },
1462
1677
  operations: {
1463
1678
  revise: oc.route({
@@ -1688,12 +1903,18 @@ var Busabase = class {
1688
1903
  get agent() {
1689
1904
  return this.client.agent;
1690
1905
  }
1691
- get attachments() {
1692
- return this.client.attachments;
1906
+ get assets() {
1907
+ return this.client.assets;
1693
1908
  }
1694
1909
  get skills() {
1695
1910
  return this.client.skills;
1696
1911
  }
1912
+ get drives() {
1913
+ return this.client.drives;
1914
+ }
1915
+ get files() {
1916
+ return this.client.files;
1917
+ }
1697
1918
  get docs() {
1698
1919
  return this.client.docs;
1699
1920
  }