busabase-sdk 0.60.0 → 0.71.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as AssetTextStatus, A as NodeVO, At as GalleryCardSize, B as UpdatePreviewFileCredentialDTO, Bt as ViewSortVO, C as CommentVO, Ct as ListFormsDTO, D as MentionInboxItemVO, Dt as AssetAttachmentRef, E as LookupRollup, Et as UpdateFormDTO, F as SearchResponseVO, Ft as VIEW_FIELD_MAX_WIDTH, G as VaultItemKind, Gt as cloudContract, H as VaultAccessPolicy, Ht as ViewVO, I as SearchResultKind, It as VIEW_FIELD_MIN_WIDTH, J as VaultScopeType, Jt as CREATABLE_NODE_TYPES, K as VaultItemVO, Kt as NodeIcon, L as SearchResultVO, Lt as ViewConfigVO, M as OperationVO, Mt as GanttScale, N as ReviewVO, Nt as RecordLinkVO, O as MentionInboxPageVO, Ot as BaseFieldVO, P as ReviewVerdict, Pt as RecordVO, Q as AssetDetailVO, R as SourceAttributionVO, Rt as ViewFilterOperator, S as CommentSubjectType, St as FormVO, T as FieldType, Tt as SubmitFormDTO, U as VaultEnvironment, Ut as AttachmentRef, V as UpdateVaultSettingsDTO, Vt as ViewType, W as VaultItemInput, Wt as CloudContract, X as FileNodeMetadata, Xt as NodeType, Y as VaultSettingsVO, Yt as CreatableNodeType, Z as FileNodeVO, Zt as OperationKind, _ as ChangeRequestVO, _t as FormFieldBindingVO, a as createBusabaseClient, at as FilePreviewConfigurationStatus, b as CommentMentionTargetType, bt as FormSubmitResultVO, c as AuditAction, ct as FilePreviewUnavailableReason, d as ChangeRequestBatchFailureVO, dt as FileTreeNodeVO, et as AssetUsageVO, f as ChangeRequestCountsVO, ft as FileTreeReadFileVO, g as ChangeRequestTargetType, gt as FormBoundFieldVO, h as ChangeRequestStatus, ht as CreateFormDTO, i as ResolvedConfig, it as FilePreviewConfigVO, j as OperationStatus, jt as GalleryCoverFit, k as NodeSearchResultVO, kt as BaseVO, l as AuditEventVO, lt as FilePreviewVO, m as ChangeRequestReviewBatchResultVO, mt as ActivityItemVO, n as BusabaseConfig, nt as GrepInputDTO, o as resolveConfig, ot as FilePreviewCredentialSource, p as ChangeRequestMergeBatchResultVO, pt as NodeDetailVO, q as VaultRuntimeEnv, qt as NodeIconSchema, r as DEFAULT_BASE_URL, rt as GrepResultVO, s as AgentTaskVO, st as FilePreviewProvider, t as BusabaseClient, tt as AssetVO, u as BusabaseSourceChannel, ut as FileTreeFileVO, v as CommentMentionDispatchStatus, vt as FormPageSourceVO, w as CommitVO, wt as ListFormsVO, x as CommentMentionVO, xt as FormThemeVO, y as CommentMentionInputDTO, yt as FormShareVO, z as UserRefVO, zt as ViewFilterVO } from "./client-SAiQFoug.js";
1
+ import { $ as AssetTextStatus, A as NodeVO, At as GalleryCardSize, B as UpdatePreviewFileCredentialDTO, Bt as ViewSortVO, C as CommentVO, Ct as ListFormsDTO, D as MentionInboxItemVO, Dt as AssetAttachmentRef, E as LookupRollup, Et as UpdateFormDTO, F as SearchResponseVO, Ft as VIEW_FIELD_MAX_WIDTH, G as VaultItemKind, Gt as cloudContract, H as VaultAccessPolicy, Ht as ViewVO, I as SearchResultKind, It as VIEW_FIELD_MIN_WIDTH, J as VaultScopeType, Jt as CREATABLE_NODE_TYPES, K as VaultItemVO, Kt as NodeIcon, L as SearchResultVO, Lt as ViewConfigVO, M as OperationVO, Mt as GanttScale, N as ReviewVO, Nt as RecordLinkVO, O as MentionInboxPageVO, Ot as BaseFieldVO, P as ReviewVerdict, Pt as RecordVO, Q as AssetDetailVO, R as SourceAttributionVO, Rt as ViewFilterOperator, S as CommentSubjectType, St as FormVO, T as FieldType, Tt as SubmitFormDTO, U as VaultEnvironment, Ut as AttachmentRef, V as UpdateVaultSettingsDTO, Vt as ViewType, W as VaultItemInput, Wt as CloudContract, X as FileNodeMetadata, Xt as NodeType, Y as VaultSettingsVO, Yt as CreatableNodeType, Z as FileNodeVO, Zt as OperationKind, _ as ChangeRequestVO, _t as FormFieldBindingVO, a as createBusabaseClient, at as FilePreviewConfigurationStatus, b as CommentMentionTargetType, bt as FormSubmitResultVO, c as AuditAction, ct as FilePreviewUnavailableReason, d as ChangeRequestBatchFailureVO, dt as FileTreeNodeVO, et as AssetUsageVO, f as ChangeRequestCountsVO, ft as FileTreeReadFileVO, g as ChangeRequestTargetType, gt as FormBoundFieldVO, h as ChangeRequestStatus, ht as CreateFormDTO, i as ResolvedConfig, it as FilePreviewConfigVO, j as OperationStatus, jt as GalleryCoverFit, k as NodeSearchResultVO, kt as BaseVO, l as AuditEventVO, lt as FilePreviewVO, m as ChangeRequestReviewBatchResultVO, mt as ActivityItemVO, n as BusabaseConfig, nt as GrepInputDTO, o as resolveConfig, ot as FilePreviewCredentialSource, p as ChangeRequestMergeBatchResultVO, pt as NodeDetailVO, q as VaultRuntimeEnv, qt as NodeIconSchema, r as DEFAULT_BASE_URL, rt as GrepResultVO, s as AgentTaskVO, st as FilePreviewProvider, t as BusabaseClient, tt as AssetVO, u as BusabaseSourceChannel, ut as FileTreeFileVO, v as CommentMentionDispatchStatus, vt as FormPageSourceVO, w as CommitVO, wt as ListFormsVO, x as CommentMentionVO, xt as FormThemeVO, y as CommentMentionInputDTO, yt as FormShareVO, z as UserRefVO, zt as ViewFilterVO } from "./client-DUJ67kpK.js";
2
2
  import { z } from "zod";
3
3
  //#region src/url.d.ts
4
4
  /**
@@ -114,6 +114,53 @@ declare const toFilesOnlyGrepResult: (result: UnifiedGrepResultVO) => GrepResult
114
114
  /** Call unified grep as files-only while preserving the former asset helper result shape. */
115
115
  declare const grepAssets: (client: Pick<BusabaseClient, "grep">, input: GrepInputDTO) => Promise<GrepResultVO>;
116
116
  //#endregion
117
+ //#region src/asset-upload.d.ts
118
+ /** An uploaded file, as the rest of the SDK needs to refer to it. */
119
+ interface BusabaseUploadedAsset {
120
+ /** What a file-tree operation references. Absent on hosts with no Asset library. */
121
+ assetId?: string;
122
+ /** What a record's attachment cell references. */
123
+ attachmentId: string;
124
+ /** Publicly resolvable URL — safe to embed in Markdown. */
125
+ url: string;
126
+ fileName: string;
127
+ mimeType: string;
128
+ size: number;
129
+ /** `sha256:<hex>`, when this runtime could compute one. */
130
+ contentHash?: string;
131
+ }
132
+ interface UploadAssetOptions {
133
+ fileName: string;
134
+ mimeType: string;
135
+ /** Optional grouping hint the server records alongside the asset. */
136
+ context?: string;
137
+ spaceId?: string;
138
+ }
139
+ /** The slice of the client an upload needs — keeps this testable with a stub. */
140
+ type AssetUploadClient = Pick<BusabaseClient, "assets">;
141
+ /**
142
+ * SHA-256 of the bytes, or `undefined` where WebCrypto is unavailable.
143
+ *
144
+ * Undefined is a real answer, not a failure: the hash only buys deduplication,
145
+ * so a runtime without WebCrypto uploads the bytes it would otherwise have
146
+ * skipped. Failing the upload over a missing optimization would be worse.
147
+ */
148
+ declare function hashBytes(bytes: Uint8Array): Promise<string | undefined>;
149
+ /**
150
+ * Upload bytes and get back every id the rest of the SDK might need.
151
+ *
152
+ * @example
153
+ * ```ts
154
+ * const asset = await uploadAsset(client, png, {
155
+ * fileName: "user-journey.png",
156
+ * mimeType: "image/png",
157
+ * });
158
+ * // asset.assetId -> reference it from a Skill/Drive/AirApp file operation
159
+ * // asset.url -> embed it in Markdown
160
+ * ```
161
+ */
162
+ declare function uploadAsset(client: AssetUploadClient, bytes: Uint8Array, options: UploadAssetOptions, fetchImpl?: typeof fetch): Promise<BusabaseUploadedAsset>;
163
+ //#endregion
117
164
  //#region src/record-get.d.ts
118
165
  interface RecordByFieldInput {
119
166
  baseId: string;
@@ -403,6 +450,25 @@ declare class Busabase {
403
450
  * ```
404
451
  */
405
452
  putText(assetId: string, text: string): Promise<Awaited<ReturnType<BusabaseClient["assets"]["putText"]>>>;
453
+ /**
454
+ * Put a file into this Space's Asset library in one call, and get back every
455
+ * id the rest of the SDK asks for: `assetId` for a file-tree entry,
456
+ * `attachmentId` for a record's attachment cell, `url` to embed in Markdown.
457
+ *
458
+ * Hides the three-step flow (`assets.createUploadUrl` → PUT →
459
+ * `assets.confirm`) and its dedup short-circuit, the same way `putText`
460
+ * does for text slots.
461
+ *
462
+ * @example
463
+ * ```ts
464
+ * const shot = await bb.uploadAsset(png, {
465
+ * fileName: "user-journey.png",
466
+ * mimeType: "image/png",
467
+ * });
468
+ * body += `![user journey](${shot.url})`;
469
+ * ```
470
+ */
471
+ uploadAsset(bytes: Uint8Array, options: UploadAssetOptions): Promise<BusabaseUploadedAsset>;
406
472
  /** Service health — reaches the server without requiring auth. */
407
473
  health(): import("@orpc/client").ClientPromiseResult<{
408
474
  status: string;
@@ -427,4 +493,4 @@ declare class Busabase {
427
493
  }>>>>;
428
494
  }
429
495
  //#endregion
430
- export { type ActivityItemVO, type AgentTaskVO, type FileTreeFileVO as AirAppFileVO, type FileTreeFileVO as DriveFileVO, type FileTreeFileVO, type FileTreeFileVO as SkillFileVO, type FileTreeReadFileVO as AirAppReadFileVO, type FileTreeReadFileVO as DriveReadFileVO, type FileTreeReadFileVO, type FileTreeReadFileVO as SkillReadFileVO, type FileTreeNodeVO as AirAppVO, type FileTreeNodeVO as DriveVO, type FileTreeNodeVO, type FileTreeNodeVO as SkillVO, type AssetAttachmentRef, type AssetDetailVO, type AssetTextStatus, type AssetUsageVO, type AssetVO, type AttachmentRef, type AuditAction, type AuditEventVO, type BaseFieldVO, type BaseVO, Busabase, type BusabaseAssetsClient, BusabaseChangeRequestsClient, type BusabaseClient, type BusabaseConfig, type BusabaseRecordsClient, type BusabaseSourceChannel, CREATABLE_NODE_TYPES, type ChangeRequestBatchFailureVO, type ChangeRequestCountsVO, type ChangeRequestMergeBatchResultVO, type ChangeRequestReviewBatchResultVO, type ChangeRequestStatus, type ChangeRequestTargetType, type ChangeRequestVO, type CloudContract, type CommentMentionDispatchStatus, type CommentMentionInputDTO, type CommentMentionTargetType, type CommentMentionVO, type CommentSubjectType, type CommentVO, type CommitVO, type CreatableNodeType, type CreateFormDTO, DEFAULT_BASE_URL, type FieldType, type FileNodeMetadata, type FileNodeVO, type FilePreviewConfigVO, type FilePreviewConfigurationStatus, type FilePreviewCredentialSource, type FilePreviewProvider, type FilePreviewUnavailableReason, type FilePreviewVO, type FormBoundFieldVO, type FormFieldBindingVO, type FormPageSourceVO, type FormShareVO, type FormSubmitResultVO, type FormThemeVO, type FormVO, type GalleryCardSize, type GalleryCoverFit, type GanttScale, type ListFormsDTO, type ListFormsVO, type LookupRollup, type MentionInboxItemVO, type MentionInboxPageVO, type NodeDetailVO, type NodeIcon, type NodeIconSchema, type NodeSearchResultVO, type NodeType, type NodeVO, type NodeWebUrlInput, type OperationKind, type OperationStatus, type OperationVO, type RecordByFieldInput, type RecordLinkVO, type RecordVO, type ResolvedConfig, type ReviewVO, type ReviewVerdict, type SearchResponseVO, type SearchResultKind, type SearchResultVO, type SourceAttributionVO, type SubmitFormDTO, type UpdateFormDTO, type UpdatePreviewFileCredentialDTO, type UpdateVaultSettingsDTO, type UserRefVO, type VIEW_FIELD_MAX_WIDTH, type VIEW_FIELD_MIN_WIDTH, type VaultAccessPolicy, type VaultEnvironment, type VaultItemInput, type VaultItemKind, type VaultItemVO, type VaultRuntimeEnv, type VaultScopeType, type VaultSettingsVO, type ViewConfigVO, type ViewFilterOperator, type ViewFilterVO, type ViewSortVO, type ViewType, type ViewVO, cloudContract, createBusabaseClient, getRecordByField, grepAssets, nodeWebUrl, normalizeBaseUrl, resolveConfig, toFilesOnlyGrepResult, toUnifiedFilesGrepInput };
496
+ export { type ActivityItemVO, type AgentTaskVO, type FileTreeFileVO as AirAppFileVO, type FileTreeFileVO as DriveFileVO, type FileTreeFileVO, type FileTreeFileVO as SkillFileVO, type FileTreeReadFileVO as AirAppReadFileVO, type FileTreeReadFileVO as DriveReadFileVO, type FileTreeReadFileVO, type FileTreeReadFileVO as SkillReadFileVO, type FileTreeNodeVO as AirAppVO, type FileTreeNodeVO as DriveVO, type FileTreeNodeVO, type FileTreeNodeVO as SkillVO, type AssetAttachmentRef, type AssetDetailVO, type AssetTextStatus, type AssetUsageVO, type AssetVO, type AttachmentRef, type AuditAction, type AuditEventVO, type BaseFieldVO, type BaseVO, Busabase, type BusabaseAssetsClient, BusabaseChangeRequestsClient, type BusabaseClient, type BusabaseConfig, type BusabaseRecordsClient, type BusabaseSourceChannel, type BusabaseUploadedAsset, CREATABLE_NODE_TYPES, type ChangeRequestBatchFailureVO, type ChangeRequestCountsVO, type ChangeRequestMergeBatchResultVO, type ChangeRequestReviewBatchResultVO, type ChangeRequestStatus, type ChangeRequestTargetType, type ChangeRequestVO, type CloudContract, type CommentMentionDispatchStatus, type CommentMentionInputDTO, type CommentMentionTargetType, type CommentMentionVO, type CommentSubjectType, type CommentVO, type CommitVO, type CreatableNodeType, type CreateFormDTO, DEFAULT_BASE_URL, type FieldType, type FileNodeMetadata, type FileNodeVO, type FilePreviewConfigVO, type FilePreviewConfigurationStatus, type FilePreviewCredentialSource, type FilePreviewProvider, type FilePreviewUnavailableReason, type FilePreviewVO, type FormBoundFieldVO, type FormFieldBindingVO, type FormPageSourceVO, type FormShareVO, type FormSubmitResultVO, type FormThemeVO, type FormVO, type GalleryCardSize, type GalleryCoverFit, type GanttScale, type ListFormsDTO, type ListFormsVO, type LookupRollup, type MentionInboxItemVO, type MentionInboxPageVO, type NodeDetailVO, type NodeIcon, type NodeIconSchema, type NodeSearchResultVO, type NodeType, type NodeVO, type NodeWebUrlInput, type OperationKind, type OperationStatus, type OperationVO, type RecordByFieldInput, type RecordLinkVO, type RecordVO, type ResolvedConfig, type ReviewVO, type ReviewVerdict, type SearchResponseVO, type SearchResultKind, type SearchResultVO, type SourceAttributionVO, type SubmitFormDTO, type UpdateFormDTO, type UpdatePreviewFileCredentialDTO, type UpdateVaultSettingsDTO, type UploadAssetOptions, type UserRefVO, type VIEW_FIELD_MAX_WIDTH, type VIEW_FIELD_MIN_WIDTH, type VaultAccessPolicy, type VaultEnvironment, type VaultItemInput, type VaultItemKind, type VaultItemVO, type VaultRuntimeEnv, type VaultScopeType, type VaultSettingsVO, type ViewConfigVO, type ViewFilterOperator, type ViewFilterVO, type ViewSortVO, type ViewType, type ViewVO, cloudContract, createBusabaseClient, getRecordByField, grepAssets, hashBytes, nodeWebUrl, normalizeBaseUrl, resolveConfig, toFilesOnlyGrepResult, toUnifiedFilesGrepInput, uploadAsset };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as TemplateRiskLevelSchema } from "./template-D10kjpd-.js";
1
+ import { i as uploadAsset, n as TemplateRiskLevelSchema, r as hashBytes } from "./template-DRMp6tKv.js";
2
2
  import { t as normalizeBaseUrl } from "./url-B8GMXalA.js";
3
3
  import { ORPCError, createORPCClient } from "@orpc/client";
4
4
  import { OpenAPILink } from "@orpc/openapi-client/fetch";
@@ -164,6 +164,15 @@ const AgentSessionVOSchema = z.object({
164
164
  */
165
165
  modelOption: AgentSessionModelOptionVOSchema.nullable().default(null)
166
166
  });
167
+ const ListAgentSessionsPagedInputSchema = z.object({
168
+ slug: z.string().min(1),
169
+ limit: z.number().int().min(1).max(50).default(20),
170
+ cursor: z.string().min(1).optional()
171
+ });
172
+ const AgentSessionsPageVOSchema = z.object({
173
+ items: AgentSessionVOSchema.array(),
174
+ nextCursor: z.string().nullable()
175
+ });
167
176
  /** One connected agent backend visible in the requested workspace scope. */
168
177
  const AgentConnectionVOSchema = z.object({
169
178
  slug: z.string(),
@@ -171,6 +180,8 @@ const AgentConnectionVOSchema = z.object({
171
180
  transport: AgentTransportSchema,
172
181
  sessionCount: z.number().int().nonnegative(),
173
182
  latest: AgentSessionVOSchema.nullable(),
183
+ /** Whether Busabase can start another conversation with this agent right now. */
184
+ connected: z.boolean(),
174
185
  /** Controls owner-only actions such as deleting the saved OAuth grant. */
175
186
  ownedByCurrentUser: z.boolean()
176
187
  });
@@ -216,6 +227,9 @@ slug: z.string().min(1) });
216
227
  const DisconnectAgentInputSchema = z.object({
217
228
  /** The exact connected-agent slug shown by the sessions/catalog surfaces. */
218
229
  slug: z.string().min(1) });
230
+ const DeleteAgentHistoryInputSchema = z.object({
231
+ /** Deletes only the current actor's sessions for this agent in the active space. */
232
+ slug: z.string().min(1) });
219
233
  /**
220
234
  * A base64 payload the browser attached.
221
235
  *
@@ -268,6 +282,10 @@ const agentsContract = {
268
282
  /** Connectable backends. Availability is resolved per request, not cached in the client. */
269
283
  catalog: oc.output(AgentCatalogEntryVOSchema.array()),
270
284
  disconnect: oc.input(DisconnectAgentInputSchema).output(z.object({
285
+ ok: z.boolean(),
286
+ endedSessionCount: z.number().int().nonnegative()
287
+ })),
288
+ deleteHistory: oc.input(DeleteAgentHistoryInputSchema).output(z.object({
271
289
  ok: z.boolean(),
272
290
  deletedSessionCount: z.number().int().nonnegative()
273
291
  })),
@@ -276,11 +294,15 @@ const agentsContract = {
276
294
  list: oc.input(ListAgentConnectionsInputSchema).output(AgentConnectionVOSchema.array()) },
277
295
  sessions: {
278
296
  list: oc.output(AgentSessionVOSchema.array()),
297
+ listPaged: oc.input(ListAgentSessionsPagedInputSchema).output(AgentSessionsPageVOSchema),
279
298
  create: oc.input(CreateAgentSessionInputSchema).output(AgentSessionVOSchema),
280
299
  /**
281
- * Send a message. A terminal session returns `accepted: false` instead of
282
- * relying on error text; `promptRecorded` tells the caller whether automatic
283
- * continuation can resend without duplicating a server echo.
300
+ * Accept a message for asynchronous execution. `accepted: true` means the
301
+ * prompt is durable and the turn slot is owned; progress and completion
302
+ * arrive through `subscribe`, so this RPC never spans the whole agent run.
303
+ * A terminal session returns `accepted: false` instead of relying on error
304
+ * text; `promptRecorded` tells the caller whether automatic continuation
305
+ * can resend without duplicating a server echo.
284
306
  */
285
307
  prompt: oc.input(PromptAgentSessionInputSchema).output(z.discriminatedUnion("accepted", [z.object({
286
308
  accepted: z.literal(true),
@@ -447,6 +469,7 @@ const fieldTypeSchema = z.enum([
447
469
  "html",
448
470
  "attachment",
449
471
  "relation",
472
+ "member",
450
473
  "number",
451
474
  "date",
452
475
  "checkbox",
@@ -553,8 +576,7 @@ const baseSchema = z.object({
553
576
  requiredApprovals: z.number()
554
577
  }),
555
578
  createdAt: z.string(),
556
- fields: z.array(baseFieldSchema),
557
- metadata: z.record(z.string(), z.unknown()).default({})
579
+ fields: z.array(baseFieldSchema)
558
580
  });
559
581
  const createBaseInputSchema = z.object({
560
582
  parentNodeId: z.string().optional().describe("Parent node id. Must be a folder or the space root; container-incapable node types (Base, Doc, AirApp, etc.) cannot hold children."),
@@ -968,22 +990,34 @@ const formNodeType = {
968
990
  label: "Form",
969
991
  icon: "form",
970
992
  /**
971
- * `hidden` until a Form can be created from a create surface at all.
993
+ * No longer `hidden`. The two conditions that hid it are both met:
994
+ *
995
+ * 1. The New-item flow ASKS FOR THE TARGET BASE — `create-node-modal.tsx`
996
+ * renders a "Writes into" Base picker (plus the field checklist) whenever
997
+ * `form` is the selected type, and keeps its submit disabled until one is
998
+ * chosen, the same way it already does for `file` and its asset.
999
+ * 2. A MATERIALIZER WRITES THE CONFIG ROW — `materializeFormNode`
1000
+ * (busabase-core `domains/form/logic/form-ops.ts`) inserts the
1001
+ * `busabase_forms` row inside the merge transaction, from the
1002
+ * `node_create` operation's `metadata.targetBaseId` / `metadata.formBindings`.
1003
+ * Both create paths run it, so a Form merged after review is configured
1004
+ * exactly like one created immediately.
972
1005
  *
973
- * `busabase_forms.target_base_id` is NOT NULL and `form` registers no
974
- * `node_create` materializer, so a Form built through the generic New-item
975
- * flow (which only collects name/slug/description) is a node row with no form
976
- * config behind it — it opens to a dead end, every time, for everyone. The
977
- * type stays fully `creatable` so `forms.create` (which does take a target
978
- * Base) and the REST/MCP surface are untouched; it just no longer offers an
979
- * entry point that cannot succeed. Drop this once the New-item flow asks for
980
- * the target Base and a materializer writes the config row.
1006
+ * A Form that still arrives unconfigured (an API caller that sent only the
1007
+ * generic node fields) is no longer a dead end either: the detail view's
1008
+ * "not set up yet" state now carries a "Connect this form to a Base" action.
1009
+ *
1010
+ * `hidden` is read by THREE create surfaces — web's `create-node-modal.tsx`,
1011
+ * `node-agent-prompts.ts`, and React Native's
1012
+ * `apps/busabase-mobile/.../CreateNodeModal.tsx`. Mobile has no Base picker,
1013
+ * so it names `form` in its own `UNSUPPORTED_TYPES` set (alongside `file`,
1014
+ * which is excluded there for the same "can't collect the required input"
1015
+ * reason) rather than re-creating the dead end on another platform.
981
1016
  */
982
1017
  capabilities: {
983
1018
  hasDetail: true,
984
1019
  creatable: true,
985
- publicAccess: "submit",
986
- hidden: true
1020
+ publicAccess: "submit"
987
1021
  },
988
1022
  operations: []
989
1023
  };
@@ -1311,6 +1345,25 @@ const nodeShareSchema = z.object({
1311
1345
  expiresAt: z.string().nullable(),
1312
1346
  updatedAt: z.string()
1313
1347
  });
1348
+ const sharedNodeSchema = z.object({
1349
+ nodeId: z.string(),
1350
+ name: z.string(),
1351
+ slug: z.string(),
1352
+ type: z.enum(NODE_TYPES),
1353
+ icon: NodeIconSchema.nullable().default(null),
1354
+ capability: z.enum(["read", "submit"]),
1355
+ hasPassword: z.boolean(),
1356
+ expiresAt: z.string().nullable(),
1357
+ /**
1358
+ * When this share ROW was first created — NOT "public continuously since".
1359
+ * `disableNodeShare` flips `scope` to `"none"` and keeps the row, so a node
1360
+ * that was shared, revoked, and shared again still reports the original
1361
+ * date. There is no column recording when `scope` last became `"public"`,
1362
+ * so the UI says "first shared {time}" rather than claiming an exposure
1363
+ * window the data cannot support. Adding that column is the follow-up.
1364
+ */
1365
+ createdAt: z.string()
1366
+ });
1314
1367
  const listNodesInputSchema = z.object({
1315
1368
  parentId: z.string().nullable().optional().describe("Node to start from. Omit or null to start from the space root."),
1316
1369
  depth: z.coerce.number().int().min(1).max(5).optional().describe("How many levels beneath the start point to eagerly include (default 2 once either field is set). Capped at 5."),
@@ -1705,6 +1758,43 @@ const searchResponseSchema = z.object({
1705
1758
  */
1706
1759
  contentTruncated: z.boolean().default(false)
1707
1760
  });
1761
+ /**
1762
+ * Payload-free interaction events for search quality measurement.
1763
+ *
1764
+ * Every object is strict on purpose: accepting and stripping an accidental
1765
+ * `query` property would make the transport look privacy-safe while callers
1766
+ * were still sending search text over the wire.
1767
+ */
1768
+ const searchInteractionInputSchema = z.discriminatedUnion("event", [
1769
+ z.object({
1770
+ event: z.literal("result_click"),
1771
+ sessionId: z.string().uuid(),
1772
+ surface: z.enum(["quick", "advanced"]),
1773
+ position: z.number().int().min(1).max(100),
1774
+ resultKind: z.enum([
1775
+ "record",
1776
+ "change_request",
1777
+ "base",
1778
+ "file",
1779
+ "node"
1780
+ ])
1781
+ }).strict(),
1782
+ z.object({
1783
+ event: z.literal("quick_to_advanced"),
1784
+ sessionId: z.string().uuid(),
1785
+ surface: z.literal("quick"),
1786
+ resultCount: z.number().int().min(0).max(100)
1787
+ }).strict(),
1788
+ z.object({
1789
+ event: z.literal("results_shown"),
1790
+ sessionId: z.string().uuid(),
1791
+ surface: z.enum(["quick", "advanced"]),
1792
+ resultCount: z.number().int().min(0).max(100),
1793
+ durationMs: z.number().int().min(0).max(12e4),
1794
+ hasMore: z.boolean()
1795
+ }).strict()
1796
+ ]);
1797
+ const searchInteractionResponseSchema = z.object({ accepted: z.literal(true) });
1708
1798
  const liveEventSchema = z.object({
1709
1799
  kind: z.enum([
1710
1800
  "change_request.created",
@@ -1935,6 +2025,8 @@ const SearchSortSchema = z.enum([
1935
2025
  ]);
1936
2026
  const searchInputSchema = z.object({
1937
2027
  query: z.string().default("").describe("Full-text query. An empty string matches nothing."),
2028
+ mode: z.enum(["quick", "full"]).optional().default("full").describe("Search depth. `quick` skips live file-body scans for typeahead; `full` preserves complete search behavior."),
2029
+ surface: z.enum(["quick", "advanced"]).optional().describe("Optional first-party UI surface for aggregate quality metrics. API/CLI callers should omit it."),
1938
2030
  limit: z.coerce.number().int().min(1).max(100).optional().default(20).describe("Results per page. Capped at 100; note the default is 20, not 50."),
1939
2031
  offset: z.coerce.number().int().min(0).optional().default(0).describe("0-indexed skip count. This endpoint pages by offset, not by cursor."),
1940
2032
  /**
@@ -2031,7 +2123,21 @@ const authInfoSchema = z.object({
2031
2123
  /** Cloud only: the server created this user's first Space during this exact request. */
2032
2124
  createdSpace: z.boolean().optional(),
2033
2125
  /** Cloud only: this auto-created Space still needs its idempotent starter initialization. */
2034
- bootstrapRequired: z.boolean().optional()
2126
+ bootstrapRequired: z.boolean().optional(),
2127
+ /** Cloud only: effective permission ceiling of the credential used for this request. */
2128
+ credentialPermissionLevel: z.enum([
2129
+ "read",
2130
+ "changeRequest",
2131
+ "write",
2132
+ "manage"
2133
+ ]).optional(),
2134
+ /** Cloud only: credential ceiling capped by the selected Space membership role. */
2135
+ effectivePermissionLevel: z.enum([
2136
+ "read",
2137
+ "changeRequest",
2138
+ "write",
2139
+ "manage"
2140
+ ]).optional()
2035
2141
  });
2036
2142
  //#endregion
2037
2143
  //#region ../../packages/busabase-contract/src/domains/filetree/contract.ts
@@ -2832,6 +2938,7 @@ const recordSchema = z.object({
2832
2938
  status: z.enum(["active", "archived"]),
2833
2939
  createdBy: z.string(),
2834
2940
  createdByUser: userRefSchema.nullable().optional().default(null),
2941
+ fieldUsers: z.record(z.string(), userRefSchema).optional().default({}),
2835
2942
  archivedAt: z.string().nullable(),
2836
2943
  createdAt: z.string(),
2837
2944
  updatedAt: z.string(),
@@ -5201,6 +5308,7 @@ const busabaseContractRoutes = {
5201
5308
  summary: "Search Busabase",
5202
5309
  successDescription: "Paginated search results across records, change requests, Bases, File nodes, and Assets."
5203
5310
  }).input(searchInputSchema).output(searchResponseSchema),
5311
+ searchMetrics: { report: oc.input(searchInteractionInputSchema).output(searchInteractionResponseSchema) },
5204
5312
  grep: oc.route({
5205
5313
  method: "POST",
5206
5314
  path: "/grep",
@@ -5403,6 +5511,13 @@ const busabaseContractRoutes = {
5403
5511
  })).output(z.object({ removed: z.boolean() }))
5404
5512
  },
5405
5513
  share: {
5514
+ list: oc.route({
5515
+ method: "GET",
5516
+ path: "/node-shares",
5517
+ tags: ["Nodes", "Sharing"],
5518
+ summary: "List every node in the space carrying its own live public share",
5519
+ successDescription: "One row per node that someone explicitly published and that is still live — `scope: \"public\"` and unexpired — joined to just enough of the node (name, slug, type, icon) to render and open it. Rows the caller cannot see are omitted (same node-visibility ACL as `nodes.list`), and the stored share password is never returned, only a `hasPassword` flag. Deliberately does NOT include nodes that are merely reachable because an ANCESTOR is shared: this is the list of grants a person made, each revocable on its own with `nodes.share.disable`, which is the same set the workbench sidebar marks with a globe (`NodeVO.shared`)."
5520
+ }).output(z.array(sharedNodeSchema)),
5406
5521
  get: oc.route({
5407
5522
  method: "GET",
5408
5523
  path: "/nodes/{nodeId}/share",
@@ -5531,6 +5646,18 @@ const busabaseContractRoutes = {
5531
5646
  summary: "List agent revision tasks",
5532
5647
  successDescription: "Change requests awaiting an external agent (request-changes or @ai mentions)."
5533
5648
  }).output(z.array(agentTaskSchema)) },
5649
+ spaces: {
5650
+ /**
5651
+ * The member roster of the space this request is scoped to — the people a
5652
+ * `member` field's picker may offer.
5653
+ *
5654
+ * RPC-only by design (no `.route(...)`). A procedure WITH a path is
5655
+ * published into `/api/v1` and into every agent's MCP tool catalog; a
5656
+ * workspace member directory belongs in neither. Resolution is delegated to
5657
+ * the host (`BusabaseContext.listMembers`), because membership lives in the
5658
+ * host, not in this engine.
5659
+ */
5660
+ members: oc.output(z.array(userRefSchema)) },
5534
5661
  live: { subscribe: oc.output(eventIterator(liveEventSchema)) },
5535
5662
  bases: baseContract,
5536
5663
  fileTrees: fileTreeContract,
@@ -6089,6 +6216,27 @@ var Busabase = class {
6089
6216
  storageKey: upload.storageKey
6090
6217
  });
6091
6218
  }
6219
+ /**
6220
+ * Put a file into this Space's Asset library in one call, and get back every
6221
+ * id the rest of the SDK asks for: `assetId` for a file-tree entry,
6222
+ * `attachmentId` for a record's attachment cell, `url` to embed in Markdown.
6223
+ *
6224
+ * Hides the three-step flow (`assets.createUploadUrl` → PUT →
6225
+ * `assets.confirm`) and its dedup short-circuit, the same way `putText`
6226
+ * does for text slots.
6227
+ *
6228
+ * @example
6229
+ * ```ts
6230
+ * const shot = await bb.uploadAsset(png, {
6231
+ * fileName: "user-journey.png",
6232
+ * mimeType: "image/png",
6233
+ * });
6234
+ * body += `![user journey](${shot.url})`;
6235
+ * ```
6236
+ */
6237
+ uploadAsset(bytes, options) {
6238
+ return uploadAsset(this.client, bytes, options, this.config.fetch ?? fetch);
6239
+ }
6092
6240
  /** Service health — reaches the server without requiring auth. */
6093
6241
  health() {
6094
6242
  return this.client.system.health();
@@ -6099,4 +6247,4 @@ var Busabase = class {
6099
6247
  }
6100
6248
  };
6101
6249
  //#endregion
6102
- export { Busabase, CREATABLE_NODE_TYPES, DEFAULT_BASE_URL, cloudContract, createBusabaseClient, getRecordByField, grepAssets, nodeWebUrl, normalizeBaseUrl, resolveConfig, toFilesOnlyGrepResult, toUnifiedFilesGrepInput };
6250
+ export { Busabase, CREATABLE_NODE_TYPES, DEFAULT_BASE_URL, cloudContract, createBusabaseClient, getRecordByField, grepAssets, hashBytes, nodeWebUrl, normalizeBaseUrl, resolveConfig, toFilesOnlyGrepResult, toUnifiedFilesGrepInput, uploadAsset };
@@ -1,4 +1,82 @@
1
1
  import { z } from "zod";
2
+ //#region src/asset-upload.ts
3
+ /**
4
+ * SHA-256 of the bytes, or `undefined` where WebCrypto is unavailable.
5
+ *
6
+ * Undefined is a real answer, not a failure: the hash only buys deduplication,
7
+ * so a runtime without WebCrypto uploads the bytes it would otherwise have
8
+ * skipped. Failing the upload over a missing optimization would be worse.
9
+ */
10
+ async function hashBytes(bytes) {
11
+ const subtle = globalThis.crypto?.subtle;
12
+ if (!subtle) return void 0;
13
+ const buffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
14
+ const digest = await subtle.digest("SHA-256", buffer);
15
+ return `sha256:${Array.from(new Uint8Array(digest)).map((byte) => byte.toString(16).padStart(2, "0")).join("")}`;
16
+ }
17
+ /**
18
+ * Upload bytes and get back every id the rest of the SDK might need.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * const asset = await uploadAsset(client, png, {
23
+ * fileName: "user-journey.png",
24
+ * mimeType: "image/png",
25
+ * });
26
+ * // asset.assetId -> reference it from a Skill/Drive/AirApp file operation
27
+ * // asset.url -> embed it in Markdown
28
+ * ```
29
+ */
30
+ async function uploadAsset(client, bytes, options, fetchImpl = fetch) {
31
+ const { fileName, mimeType, context, spaceId } = options;
32
+ if (!bytes.byteLength) throw new Error(`uploadAsset: ${fileName} is empty — there are no bytes to upload`);
33
+ const contentHash = await hashBytes(bytes);
34
+ const upload = await client.assets.createUploadUrl({
35
+ fileName,
36
+ mimeType,
37
+ sizeBytes: bytes.byteLength,
38
+ ...context ? { context } : {},
39
+ ...spaceId ? { spaceId } : {},
40
+ ...contentHash ? { contentHash } : {}
41
+ });
42
+ if (upload.duplicate && upload.attachmentId) return {
43
+ ...upload.assetId ? { assetId: upload.assetId } : {},
44
+ attachmentId: upload.attachmentId,
45
+ url: upload.publicUrl,
46
+ fileName,
47
+ mimeType,
48
+ size: bytes.byteLength,
49
+ ...contentHash ? { contentHash } : {}
50
+ };
51
+ const response = await fetchImpl(upload.uploadUrl, {
52
+ method: "PUT",
53
+ headers: { "content-type": mimeType },
54
+ body: bytes
55
+ });
56
+ if (!response.ok) {
57
+ const detail = await response.text().catch(() => "");
58
+ throw new Error(`uploadAsset: presigned upload of ${fileName} failed (${response.status} ${response.statusText})${detail ? `: ${detail}` : ""}`);
59
+ }
60
+ const confirmed = await client.assets.confirm({
61
+ storageKey: upload.storageKey,
62
+ fileName,
63
+ mimeType,
64
+ sizeBytes: bytes.byteLength,
65
+ ...context ? { context } : {},
66
+ ...spaceId ? { spaceId } : {},
67
+ ...contentHash ? { contentHash } : {}
68
+ });
69
+ return {
70
+ ...confirmed.assetId ? { assetId: confirmed.assetId } : {},
71
+ attachmentId: confirmed.attachmentId,
72
+ url: confirmed.publicUrl,
73
+ fileName,
74
+ mimeType,
75
+ size: bytes.byteLength,
76
+ ...contentHash ? { contentHash } : {}
77
+ };
78
+ }
79
+ //#endregion
2
80
  //#region ../../packages/busabase-contract/src/domains/skill/frontmatter.ts
3
81
  /**
4
82
  * `SKILL.md` frontmatter — the generic shape, independent of Busabase.
@@ -157,4 +235,4 @@ z.object({
157
235
  ["isTemplateSkill"]: z.literal(true)
158
236
  });
159
237
  //#endregion
160
- export { TemplateRiskLevelSchema as n, APP_ROOT_RESOURCE_KEY as t };
238
+ export { uploadAsset as i, TemplateRiskLevelSchema as n, hashBytes as r, APP_ROOT_RESOURCE_KEY as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "busabase-sdk",
3
- "version": "0.60.0",
3
+ "version": "0.71.0",
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",
@@ -67,9 +67,9 @@
67
67
  "tsx": "^4.20.5",
68
68
  "typescript": "^7.0.2",
69
69
  "vitest": "^4.1.11",
70
- "open-domains": "0.0.2",
71
- "busabase-contract": "0.60.0",
72
- "openlib": "0.1.1"
70
+ "openlib": "0.1.1",
71
+ "busabase-contract": "0.71.0",
72
+ "open-domains": "0.0.2"
73
73
  },
74
74
  "engines": {
75
75
  "node": ">=24.18.0"