busa-sdk 0.9.3 → 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.d.ts +10122 -5137
  2. package/dist/index.js +433 -15
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -56,6 +56,7 @@ var ConfirmUploadVOSchema = z.object({
56
56
  storageKey: z.string(),
57
57
  publicUrl: z.string()
58
58
  });
59
+ var AssetTextStatusSchema = z.enum(["missing", "present", "none", "stale"]);
59
60
  var AssetVOSchema = z.object({
60
61
  id: z.string(),
61
62
  attachmentId: z.string(),
@@ -69,6 +70,8 @@ var AssetVOSchema = z.object({
69
70
  contentHash: z.string().nullable(),
70
71
  /** How many places reference this asset (Base records + Doc bodies). */
71
72
  usageCount: z.number().int().nonnegative(),
73
+ /** Drive Grep Retrieval text-slot status — see {@link AssetTextStatusSchema}. */
74
+ textStatus: AssetTextStatusSchema,
72
75
  createdAt: z.string()
73
76
  });
74
77
  var AssetUsageVOSchema = z.object({
@@ -92,6 +95,108 @@ var AssetDetailVOSchema = z.object({
92
95
  asset: AssetVOSchema,
93
96
  usages: z.array(AssetUsageVOSchema)
94
97
  });
98
+ var PutTextInputSchema = z.object({
99
+ assetId: z.string(),
100
+ /** Inline text body, ≤ 1 MB. For larger text, use `createTextUploadUrl` + bind by `storageKey`. */
101
+ text: z.string().optional(),
102
+ /** Bind a presigned-uploaded text object (a temp `asset-texts/pending/*.txt` key). */
103
+ storageKey: z.string().optional(),
104
+ /**
105
+ * Claimed content hash for the `storageKey` bind path (`sha256:<hex>`, echoing
106
+ * `createTextUploadUrl`'s input like `open-domains/attachments`' confirm step).
107
+ * The server always computes the ACTUAL hash from the bytes during the
108
+ * confirm scan and rejects a mismatch (hash-poisoning defense) — this field
109
+ * is only an optional early-mismatch check, never trusted for addressing.
110
+ */
111
+ contentHash: z.string().optional(),
112
+ /** Mark as having no extractable text (e.g. a scanned, image-only PDF). */
113
+ none: z.boolean().optional()
114
+ });
115
+ var AssetTextVOSchema = z.object({
116
+ assetId: z.string(),
117
+ textStatus: AssetTextStatusSchema,
118
+ lineCount: z.number().int().nonnegative(),
119
+ charCount: z.number().int().nonnegative(),
120
+ byteCount: z.number().int().nonnegative()
121
+ });
122
+ var CreateTextUploadUrlInputSchema = z.object({
123
+ assetId: z.string(),
124
+ sizeBytes: z.number().int().positive(),
125
+ /** Optional claim, mirrors `RequestUploadUrlDTO.contentHash` (never trusted for addressing). */
126
+ contentHash: z.string().optional()
127
+ });
128
+ var CreateTextUploadUrlVOSchema = z.object({
129
+ uploadUrl: z.string(),
130
+ storageKey: z.string(),
131
+ expiresIn: z.number().int().nonnegative()
132
+ });
133
+ var GrepScopeSchema = z.object({
134
+ assetIds: z.array(z.string()).optional(),
135
+ /** Drive/Skill mounted path prefix (matches `busabase_asset_usages.path`). */
136
+ drivePath: z.string().optional(),
137
+ mimeTypes: z.array(z.string()).optional()
138
+ });
139
+ var GREP_DEFAULT_MAX_MATCHES = 100;
140
+ var GREP_HARD_MAX_MATCHES = 1e3;
141
+ var GREP_DEFAULT_CONTEXT_LINES = 0;
142
+ var GREP_MAX_CONTEXT_LINES = 10;
143
+ var GrepInputSchema = z.object({
144
+ pattern: z.string().min(1),
145
+ /** JS RegExp flags, e.g. `"i"` for case-insensitive. `g`/`y` are ignored (grep always scans every match per line). */
146
+ flags: z.string().optional().default(""),
147
+ scope: GrepScopeSchema.optional(),
148
+ maxMatches: z.coerce.number().int().min(1).max(GREP_HARD_MAX_MATCHES).optional().default(GREP_DEFAULT_MAX_MATCHES),
149
+ contextLines: z.coerce.number().int().min(0).max(GREP_MAX_CONTEXT_LINES).optional().default(GREP_DEFAULT_CONTEXT_LINES)
150
+ });
151
+ var GrepMatchVOSchema = z.object({
152
+ assetId: z.string(),
153
+ fileName: z.string(),
154
+ /** Drive/Skill mounted path, or "" when the asset isn't path-mounted (e.g. a File node). */
155
+ drivePath: z.string(),
156
+ line: z.number().int().positive(),
157
+ /** 1-based character column (not byte offset) of the match start within the line. */
158
+ column: z.number().int().positive(),
159
+ /** The matching line, truncated if it exceeds the long-line guard. */
160
+ text: z.string(),
161
+ before: z.array(z.string()),
162
+ after: z.array(z.string())
163
+ });
164
+ var GrepResultVOSchema = z.object({
165
+ matches: z.array(GrepMatchVOSchema),
166
+ filesScanned: z.number().int().nonnegative(),
167
+ /** Asset ids in scope with no text yet (contentKind text-or-writable-binary, no row). */
168
+ missing: z.array(z.string()),
169
+ /** Asset ids in scope whose derived text is stale (source replaced since it was written). */
170
+ stale: z.array(z.string()),
171
+ /** Count of assets in scope explicitly marked `none` (no extractable text). */
172
+ unsearchable: z.number().int().nonnegative(),
173
+ /**
174
+ * Asset ids whose scan was attempted but failed (storage error, corrupt
175
+ * cache file, object deleted mid-flight) — NOT counted in `filesScanned`.
176
+ * Honest coverage: these were not actually searched, so a caller must not
177
+ * treat their absence from `matches` as a clean "no match".
178
+ */
179
+ errored: z.array(z.string()),
180
+ /**
181
+ * Count of in-scope, present-and-searchable assets the scan never even
182
+ * reached because the deadline or `maxMatches` budget ran out first. Only
183
+ * nonzero when `truncated` is true.
184
+ */
185
+ notReached: z.number().int().nonnegative(),
186
+ truncated: z.boolean()
187
+ });
188
+ var ReadTextLinesInputSchema = z.object({
189
+ assetId: z.string(),
190
+ startLine: z.coerce.number().int().min(1),
191
+ endLine: z.coerce.number().int().min(1)
192
+ });
193
+ var ReadLinesVOSchema = z.object({
194
+ lines: z.array(z.string()),
195
+ startLine: z.number().int().positive(),
196
+ endLine: z.number().int().positive(),
197
+ totalLines: z.number().int().nonnegative(),
198
+ truncated: z.boolean()
199
+ });
95
200
 
96
201
  // ../../packages/busabase-contract/src/domains/assets/contract.ts
97
202
  var UpdateAssetMetadataInputSchema = z.object({
@@ -133,7 +238,7 @@ var assetsContract = {
133
238
  path: "/assets/{assetId}/metadata",
134
239
  tags: ["Assets"],
135
240
  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."
241
+ successDescription: "Updated AI-readable metadata for a file, such as summary, tags, source URL, or schema-specific hints. Large text does not live here \u2014 see putText / grep / readTextLines."
137
242
  }).input(UpdateAssetMetadataInputSchema).output(AssetDetailVOSchema),
138
243
  delete: oc.route({
139
244
  method: "DELETE",
@@ -141,7 +246,39 @@ var assetsContract = {
141
246
  tags: ["Assets"],
142
247
  summary: "Delete asset",
143
248
  successDescription: "Removed the asset and, if no other row references its bytes, the stored object. Refused while the asset is still referenced (where-used)."
144
- }).input(z.object({ assetId: z.string() })).output(z.object({ deleted: z.boolean() }))
249
+ }).input(z.object({ assetId: z.string() })).output(z.object({ deleted: z.boolean() })),
250
+ // ── Drive Grep Retrieval ─────────────────────────────────────────────────
251
+ // Busabase stores, indexes, and searches text; it never generates it. Text
252
+ // always arrives via putText — an agent's own extractor, or (future) an
253
+ // Outgoing-Hook-triggered service — never a bundled parser/OCR library.
254
+ putText: oc.route({
255
+ method: "PUT",
256
+ path: "/assets/{assetId}/text",
257
+ tags: ["Assets"],
258
+ summary: "Write (or mark none) an asset's text slot",
259
+ successDescription: "Text slot updated: inline body (\u22641MB), or bound from a presigned upload (server-verified content hash, hash-poisoning-safe), or marked `none` for files with no extractable text. Direct write, audit-logged, not ChangeRequest-gated."
260
+ }).input(PutTextInputSchema).output(AssetTextVOSchema),
261
+ createTextUploadUrl: oc.route({
262
+ method: "POST",
263
+ path: "/assets/text/upload-urls",
264
+ tags: ["Assets"],
265
+ summary: "Request a presigned upload URL for large text",
266
+ successDescription: "Presigned (or dev) upload URL for a temporary text object; PUT the bytes there, then call putText with the returned storageKey to bind, verify, and content-address it."
267
+ }).input(CreateTextUploadUrlInputSchema).output(CreateTextUploadUrlVOSchema),
268
+ grep: oc.route({
269
+ method: "POST",
270
+ path: "/assets/grep",
271
+ tags: ["Assets"],
272
+ summary: "Search every text-bearing asset in scope",
273
+ successDescription: "Streaming regex/literal matches with real file + line + column numbers and context, across every asset with text \u2014 any size, no 256KB cap. Honest coverage: missing/stale/unsearchable/errored name assets that were not (fully or successfully) searched, notReached counts present assets the scan never got to, and truncated flags a capped response."
274
+ }).input(GrepInputSchema).output(GrepResultVOSchema),
275
+ readTextLines: oc.route({
276
+ method: "GET",
277
+ path: "/assets/{assetId}/text/lines",
278
+ tags: ["Assets"],
279
+ summary: "Read an exact line range from an asset's text",
280
+ successDescription: "Lines [startLine, endLine] (range capped at 2000 lines / ~2MB response) read via a storage byte-range request \u2014 the server never loads the whole object, even for a multi-GB file."
281
+ }).input(ReadTextLinesInputSchema).output(ReadLinesVOSchema)
145
282
  };
146
283
  var i18n = {
147
284
  locales: ["en", "zh-CN", "zh-TW", "ja", "ko", "de", "fr", "es", "pt"]};
@@ -263,7 +400,12 @@ var createBaseInputSchema = z.object({
263
400
  required: z.boolean().default(false),
264
401
  options: fieldOptionsSchema.optional().default({})
265
402
  })
266
- ).default([])
403
+ ).default([]),
404
+ // Review-first by default: without `autoMerge: true`, this proposes the Base
405
+ // as a pending ChangeRequest (status "in_review") instead of creating it
406
+ // immediately. Pass `autoMerge: true` only for callers that don't need human
407
+ // review (seed/migration scripts, an explicit no-review agent task).
408
+ autoMerge: z.boolean().optional().default(false)
267
409
  });
268
410
  var createBaseFieldInputSchema = z.object({
269
411
  name: fieldNameSchema,
@@ -695,7 +837,14 @@ var liveEventSchema = z.object({
695
837
  "change_request.updated",
696
838
  "change_request.deleted",
697
839
  "change_request.reviewed",
698
- "change_request.merged"
840
+ "change_request.merged",
841
+ // Fired only when a CONTENT change request freshly enters human review
842
+ // (record_* ops created via record-ops.ts) — never for structural ops
843
+ // that auto-merge instantly (those still fire "change_request.created"
844
+ // via the audit funnel, but nothing needs reviewing). Consumed by
845
+ // `use-live-sync.ts` to pop a desktop Notification, and by
846
+ // busabase-cloud's host hook to persist an inbox notification row.
847
+ "change_request.pending_review"
699
848
  ]),
700
849
  spaceId: z.string(),
701
850
  actorId: z.string(),
@@ -725,6 +874,8 @@ var auditActionSchema = z.enum([
725
874
  "drive.created",
726
875
  "asset.deleted",
727
876
  "asset.metadata_updated",
877
+ "asset.text_written",
878
+ "asset.text_marked_none",
728
879
  "node.purged"
729
880
  ]);
730
881
  var auditEventSchema = z.object({
@@ -1003,6 +1154,12 @@ var listRecordsResponseSchema = z.object({
1003
1154
  records: z.array(recordSchema),
1004
1155
  nextCursor: z.string().nullable()
1005
1156
  });
1157
+ var listArchivedRecordsPagedInputSchema = z.object({
1158
+ baseId: z.string(),
1159
+ limit: z.coerce.number().int().min(1).max(100).optional().default(50),
1160
+ /** Opaque base64 cursor (createdAt-keyed) for keyset pagination. */
1161
+ cursor: z.string().optional()
1162
+ });
1006
1163
  var countRecordsInputSchema = z.object({
1007
1164
  baseId: z.string().optional()
1008
1165
  }).optional().default({});
@@ -1101,13 +1258,20 @@ var baseContract = {
1101
1258
  summary: "List archived records for a Base",
1102
1259
  successDescription: "Records that have been archived (soft-deleted) from a Base."
1103
1260
  }).input(z.object({ baseId: z.string() })).output(z.array(recordSchema)),
1261
+ listArchivedRecordsPaged: oc.route({
1262
+ method: "GET",
1263
+ path: "/bases/{baseId}/records/archived/paged",
1264
+ tags: ["Records"],
1265
+ summary: "List archived records for a Base with keyset pagination",
1266
+ successDescription: "A page of archived (soft-deleted) records plus an opaque nextCursor (null at the end)."
1267
+ }).input(listArchivedRecordsPagedInputSchema).output(listRecordsResponseSchema),
1104
1268
  create: oc.route({
1105
1269
  method: "POST",
1106
1270
  path: "/bases",
1107
1271
  tags: ["Bases"],
1108
1272
  summary: "Create Base",
1109
- successDescription: "Created Base."
1110
- }).input(createBaseInputSchema).output(baseSchema),
1273
+ successDescription: "Review-first by default: a pending ChangeRequest proposing the Base. Returns the materialized Base instead when `autoMerge: true` is passed."
1274
+ }).input(createBaseInputSchema).output(z.union([baseSchema, changeRequestSchema])),
1111
1275
  createChangeRequest: oc.route({
1112
1276
  method: "POST",
1113
1277
  path: "/bases/{baseId}/change-requests",
@@ -1305,7 +1469,12 @@ var createDocInputSchema = z.object({
1305
1469
  slug: z.string().min(1).regex(/^[a-z0-9-]+$/),
1306
1470
  name: z.string().min(1),
1307
1471
  description: z.string().optional().default(""),
1308
- body: z.string().optional().default("")
1472
+ body: z.string().optional().default(""),
1473
+ // Review-first by default: without `autoMerge: true`, this proposes the Doc
1474
+ // as a pending ChangeRequest (status "in_review") instead of creating it
1475
+ // immediately. Pass `autoMerge: true` only for callers that don't need human
1476
+ // review (seed/migration scripts, an explicit no-review agent task).
1477
+ autoMerge: z.boolean().optional().default(false)
1309
1478
  });
1310
1479
  var updateDocInputSchema = z.object({
1311
1480
  body: z.string()
@@ -1330,8 +1499,8 @@ var docContract = {
1330
1499
  path: "/docs",
1331
1500
  tags: ["Docs"],
1332
1501
  summary: "Create Doc node",
1333
- successDescription: "Created Doc node and initialized its body."
1334
- }).input(createDocInputSchema).output(docSchema),
1502
+ successDescription: "Review-first by default: a pending ChangeRequest proposing the Doc. Returns the materialized Doc node instead when `autoMerge: true` is passed."
1503
+ }).input(createDocInputSchema).output(z.union([docSchema, changeRequestSchema])),
1335
1504
  get: oc.route({
1336
1505
  method: "GET",
1337
1506
  path: "/docs/{nodeId}",
@@ -1403,7 +1572,12 @@ var createFileTreeInputSchema = z.object({
1403
1572
  description: z.string().optional().default(""),
1404
1573
  visibility: z.enum(["private", "workspace", "public"]).optional().default("private"),
1405
1574
  version: z.string().optional().default("0.1.0"),
1406
- files: z.array(z.union([assetFileInputSchema, textFileInputSchema])).optional().default([])
1575
+ files: z.array(z.union([assetFileInputSchema, textFileInputSchema])).optional().default([]),
1576
+ // Review-first by default: without `autoMerge: true`, this proposes the node
1577
+ // as a pending ChangeRequest (status "in_review") instead of creating it
1578
+ // immediately. Pass `autoMerge: true` only for callers that don't need human
1579
+ // review (seed/migration scripts, an explicit no-review agent task).
1580
+ autoMerge: z.boolean().optional().default(false)
1407
1581
  });
1408
1582
  var fileTreeFileOperationInputSchema = z.union([
1409
1583
  assetFileOperationInputSchema,
@@ -1445,8 +1619,8 @@ var makeFileTreeContract = (routeBase, tag) => {
1445
1619
  path: basePath,
1446
1620
  tags: [tag],
1447
1621
  summary: `Create ${label} node`,
1448
- successDescription: `Created ${label} node and initialized file tree.`
1449
- }).input(createFileTreeInputSchema).output(fileTreeNodeSchema),
1622
+ successDescription: `Review-first by default: a pending ChangeRequest proposing the ${label} node. Returns the materialized ${label} node instead when \`autoMerge: true\` is passed.`
1623
+ }).input(createFileTreeInputSchema).output(z.union([fileTreeNodeSchema, changeRequestSchema])),
1450
1624
  get: oc.route({
1451
1625
  method: "GET",
1452
1626
  path: `${basePath}/{nodeId}`,
@@ -1506,7 +1680,12 @@ var createFileNodeInputSchema = z.object({
1506
1680
  slug: z.string().min(1).regex(/^[a-z0-9-]+$/),
1507
1681
  name: z.string().min(1),
1508
1682
  description: z.string().optional().default(""),
1509
- assetId: z.string().min(1)
1683
+ assetId: z.string().min(1),
1684
+ // Review-first by default: without `autoMerge: true`, this proposes the File
1685
+ // node as a pending ChangeRequest (status "in_review") instead of creating it
1686
+ // immediately. Pass `autoMerge: true` only for callers that don't need human
1687
+ // review (seed/migration scripts, an explicit no-review agent task).
1688
+ autoMerge: z.boolean().optional().default(false)
1510
1689
  });
1511
1690
  var fileContract = {
1512
1691
  list: oc.route({
@@ -1521,8 +1700,8 @@ var fileContract = {
1521
1700
  path: "/files",
1522
1701
  tags: ["Files"],
1523
1702
  summary: "Create File node",
1524
- successDescription: "Created a first-class File node that references an Asset."
1525
- }).input(createFileNodeInputSchema).output(FileNodeVOSchema),
1703
+ successDescription: "Review-first by default: a pending ChangeRequest proposing the File node. Returns the materialized File node instead when `autoMerge: true` is passed."
1704
+ }).input(createFileNodeInputSchema).output(z.union([FileNodeVOSchema, changeRequestSchema])),
1526
1705
  get: oc.route({
1527
1706
  method: "GET",
1528
1707
  path: "/files/{nodeId}",
@@ -1630,6 +1809,197 @@ var vaultContract = {
1630
1809
  successDescription: "Removed local Vault secrets and variables."
1631
1810
  }).output(VaultSuccessSchema)
1632
1811
  };
1812
+ var WebhookEventTypeSchema = z.enum(["record.created", "ai_mention", "changes_requested"]);
1813
+ z.enum(["webhook", "notify_agent", "run_snippet"]);
1814
+ var WebhookDeliveryStatusSchema = z.enum(["success", "failed", "skipped"]);
1815
+ var WebhookHttpConfigSchema = z.object({
1816
+ targetUrl: z.string().url(),
1817
+ secret: z.string().min(1).max(256).optional(),
1818
+ headers: z.record(z.string(), z.string()).optional()
1819
+ });
1820
+ var WebhookSnippetConfigSchema = z.object({
1821
+ code: z.string().min(1).max(2e4),
1822
+ timeoutMs: z.number().int().min(100).max(5e3).default(2e3)
1823
+ });
1824
+ var WebhookHttpConfigVOSchema = z.object({
1825
+ targetUrl: z.string().url(),
1826
+ hasSecret: z.boolean(),
1827
+ headers: z.record(z.string(), z.string()).optional()
1828
+ });
1829
+ var WebhookSnippetConfigVOSchema = WebhookSnippetConfigSchema;
1830
+ var webhookRuleCommonInputFields = {
1831
+ name: z.string().min(1).max(200),
1832
+ eventType: WebhookEventTypeSchema,
1833
+ baseId: z.string().nullable().optional(),
1834
+ enabled: z.boolean().default(true)
1835
+ };
1836
+ var WebhookRuleInputSchema = z.discriminatedUnion("actionKind", [
1837
+ z.object({
1838
+ ...webhookRuleCommonInputFields,
1839
+ actionKind: z.literal("webhook"),
1840
+ config: WebhookHttpConfigSchema
1841
+ }),
1842
+ z.object({
1843
+ ...webhookRuleCommonInputFields,
1844
+ actionKind: z.literal("notify_agent"),
1845
+ config: WebhookHttpConfigSchema
1846
+ }),
1847
+ z.object({
1848
+ ...webhookRuleCommonInputFields,
1849
+ actionKind: z.literal("run_snippet"),
1850
+ config: WebhookSnippetConfigSchema
1851
+ })
1852
+ ]);
1853
+ var WebhookRuleUpdateInputSchema = z.discriminatedUnion("actionKind", [
1854
+ z.object({
1855
+ id: z.string(),
1856
+ ...webhookRuleCommonInputFields,
1857
+ actionKind: z.literal("webhook"),
1858
+ config: WebhookHttpConfigSchema
1859
+ }),
1860
+ z.object({
1861
+ id: z.string(),
1862
+ ...webhookRuleCommonInputFields,
1863
+ actionKind: z.literal("notify_agent"),
1864
+ config: WebhookHttpConfigSchema
1865
+ }),
1866
+ z.object({
1867
+ id: z.string(),
1868
+ ...webhookRuleCommonInputFields,
1869
+ actionKind: z.literal("run_snippet"),
1870
+ config: WebhookSnippetConfigSchema
1871
+ })
1872
+ ]);
1873
+ var webhookRuleVOCommonFields = {
1874
+ id: z.string(),
1875
+ spaceId: z.string(),
1876
+ baseId: z.string().nullable(),
1877
+ name: z.string(),
1878
+ eventType: WebhookEventTypeSchema,
1879
+ enabled: z.boolean(),
1880
+ createdBy: z.string(),
1881
+ createdAt: z.string(),
1882
+ updatedAt: z.string(),
1883
+ lastTriggeredAt: z.string().nullable(),
1884
+ lastStatus: WebhookDeliveryStatusSchema.nullable()
1885
+ };
1886
+ var WebhookRuleVOSchema = z.discriminatedUnion("actionKind", [
1887
+ z.object({
1888
+ ...webhookRuleVOCommonFields,
1889
+ actionKind: z.literal("webhook"),
1890
+ config: WebhookHttpConfigVOSchema
1891
+ }),
1892
+ z.object({
1893
+ ...webhookRuleVOCommonFields,
1894
+ actionKind: z.literal("notify_agent"),
1895
+ config: WebhookHttpConfigVOSchema
1896
+ }),
1897
+ z.object({
1898
+ ...webhookRuleVOCommonFields,
1899
+ actionKind: z.literal("run_snippet"),
1900
+ config: WebhookSnippetConfigVOSchema
1901
+ })
1902
+ ]);
1903
+ var WebhookDeliveryVOSchema = z.object({
1904
+ id: z.string(),
1905
+ ruleId: z.string(),
1906
+ eventType: WebhookEventTypeSchema,
1907
+ status: WebhookDeliveryStatusSchema,
1908
+ httpStatus: z.number().nullable(),
1909
+ detail: z.string().nullable(),
1910
+ durationMs: z.number().nullable(),
1911
+ createdAt: z.string()
1912
+ });
1913
+ z.object({}).optional().default({});
1914
+ var ListWebhookDeliveriesInputSchema = z.object({
1915
+ ruleId: z.string(),
1916
+ limit: z.coerce.number().int().min(1).max(100).default(20)
1917
+ });
1918
+
1919
+ // ../../packages/busabase-contract/src/domains/webhook/contract.ts
1920
+ var webhookContract = {
1921
+ list: oc.route({
1922
+ method: "GET",
1923
+ path: "/webhooks",
1924
+ tags: ["Webhooks"],
1925
+ summary: "List webhook automation rules",
1926
+ successDescription: "Configured webhook automation rules for this space."
1927
+ }).output(WebhookRuleVOSchema.array()),
1928
+ get: oc.route({
1929
+ method: "GET",
1930
+ path: "/webhooks/{id}",
1931
+ tags: ["Webhooks"],
1932
+ summary: "Get webhook automation rule",
1933
+ successDescription: "A single webhook automation rule."
1934
+ }).input(z.object({ id: z.string() })).output(WebhookRuleVOSchema),
1935
+ create: oc.route({
1936
+ method: "POST",
1937
+ path: "/webhooks",
1938
+ tags: ["Webhooks"],
1939
+ summary: "Create webhook automation rule",
1940
+ successDescription: "Created webhook automation rule. Dispatches on the configured event via an HTTP webhook, an agent notification, or a sandboxed snippet."
1941
+ }).input(WebhookRuleInputSchema).output(WebhookRuleVOSchema),
1942
+ update: oc.route({
1943
+ method: "PUT",
1944
+ path: "/webhooks/{id}",
1945
+ tags: ["Webhooks"],
1946
+ summary: "Update webhook automation rule",
1947
+ successDescription: "Updated webhook automation rule."
1948
+ }).input(WebhookRuleUpdateInputSchema).output(WebhookRuleVOSchema),
1949
+ delete: oc.route({
1950
+ method: "DELETE",
1951
+ path: "/webhooks/{id}",
1952
+ tags: ["Webhooks"],
1953
+ summary: "Delete webhook automation rule",
1954
+ successDescription: "Removed the webhook automation rule."
1955
+ }).input(z.object({ id: z.string() })).output(z.object({ success: z.boolean() })),
1956
+ deliveries: oc.route({
1957
+ method: "GET",
1958
+ path: "/webhooks/{ruleId}/deliveries",
1959
+ tags: ["Webhooks"],
1960
+ summary: "List webhook rule delivery attempts",
1961
+ successDescription: "Recent delivery attempts for a webhook rule, newest first."
1962
+ }).input(ListWebhookDeliveriesInputSchema).output(WebhookDeliveryVOSchema.array()),
1963
+ testFire: oc.route({
1964
+ method: "POST",
1965
+ path: "/webhooks/{id}/test-fire",
1966
+ tags: ["Webhooks"],
1967
+ summary: "Test-fire a webhook automation rule",
1968
+ successDescription: "The delivery record produced by firing this rule right now with a synthetic payload \u2014 runs regardless of the rule's enabled state or its real trigger."
1969
+ }).input(z.object({ id: z.string() })).output(WebhookDeliveryVOSchema)
1970
+ };
1971
+ var activityItemSchema = z.discriminatedUnion("kind", [
1972
+ z.object({
1973
+ kind: z.literal("change_request"),
1974
+ timestamp: z.string(),
1975
+ changeRequest: changeRequestSchema
1976
+ }),
1977
+ z.object({
1978
+ kind: z.literal("operation"),
1979
+ timestamp: z.string(),
1980
+ operationId: z.string(),
1981
+ changeRequest: changeRequestSchema
1982
+ }),
1983
+ z.object({
1984
+ kind: z.literal("record"),
1985
+ timestamp: z.string(),
1986
+ record: recordSchema
1987
+ }),
1988
+ z.object({
1989
+ kind: z.literal("audit"),
1990
+ timestamp: z.string(),
1991
+ auditEvent: auditEventSchema,
1992
+ record: recordSchema.nullable()
1993
+ })
1994
+ ]);
1995
+ var listActivityPagedInputSchema = z.object({
1996
+ limit: z.coerce.number().int().min(1).max(100).optional().default(50),
1997
+ cursor: z.string().optional()
1998
+ }).optional().default({ limit: 50 });
1999
+ var listActivityResponseSchema = z.object({
2000
+ items: z.array(activityItemSchema),
2001
+ nextCursor: z.string().nullable()
2002
+ });
1633
2003
 
1634
2004
  // ../../packages/busabase-contract/src/contract/busabase.ts
1635
2005
  var changeRequestBatchResultSchema = z.object({
@@ -1705,6 +2075,15 @@ var busabaseContractRoutes = {
1705
2075
  successDescription: "Recorded audit event."
1706
2076
  }).input(createAuditEventInputSchema).output(auditEventSchema)
1707
2077
  },
2078
+ activity: {
2079
+ listPaged: oc.route({
2080
+ method: "GET",
2081
+ path: "/activity/paged",
2082
+ tags: ["Activity"],
2083
+ summary: "List the activity feed with keyset pagination",
2084
+ successDescription: "A page of activity items (change requests, operations, records and audit events merged, newest first) plus an opaque nextCursor (null at the end)."
2085
+ }).input(listActivityPagedInputSchema).output(listActivityResponseSchema)
2086
+ },
1708
2087
  comments: {
1709
2088
  list: oc.route({
1710
2089
  method: "GET",
@@ -1743,6 +2122,7 @@ var busabaseContractRoutes = {
1743
2122
  folders: folderContract,
1744
2123
  assets: assetsContract,
1745
2124
  vault: vaultContract,
2125
+ webhooks: webhookContract,
1746
2126
  changeRequests: {
1747
2127
  list: oc.route({
1748
2128
  method: "GET",
@@ -2069,10 +2449,48 @@ var Busabase = class {
2069
2449
  get agentTasks() {
2070
2450
  return this.client.agentTasks;
2071
2451
  }
2452
+ get webhooks() {
2453
+ return this.client.webhooks;
2454
+ }
2072
2455
  /** Full-text search across records, change requests, and Bases. */
2073
2456
  search(input) {
2074
2457
  return this.client.search(input);
2075
2458
  }
2459
+ /**
2460
+ * Supply text for an Asset's Drive Grep Retrieval text slot in one call —
2461
+ * inline for small text, a presigned upload for large text — so callers
2462
+ * never see the underlying three-step flow
2463
+ * (`createTextUploadUrl` → PUT bytes → `putText({ storageKey })`).
2464
+ *
2465
+ * @example
2466
+ * ```ts
2467
+ * await bb.putText(assetId, extractedText); // picks inline vs presigned by size
2468
+ * ```
2469
+ */
2470
+ async putText(assetId, text) {
2471
+ const INLINE_TEXT_MAX_BYTES = 1024 * 1024;
2472
+ const byteLength = typeof Buffer !== "undefined" ? Buffer.byteLength(text, "utf8") : new Blob([text]).size;
2473
+ if (byteLength <= INLINE_TEXT_MAX_BYTES) {
2474
+ return this.client.assets.putText({ assetId, text });
2475
+ }
2476
+ const upload = await this.client.assets.createTextUploadUrl({
2477
+ assetId,
2478
+ sizeBytes: byteLength
2479
+ });
2480
+ const doFetch = this.config.fetch ?? fetch;
2481
+ const response = await doFetch(upload.uploadUrl, {
2482
+ method: "PUT",
2483
+ headers: { "content-type": "text/plain; charset=utf-8" },
2484
+ body: text
2485
+ });
2486
+ if (!response.ok) {
2487
+ const detail = await response.text().catch(() => "");
2488
+ throw new Error(
2489
+ `putText: presigned upload failed (${response.status} ${response.statusText})${detail ? `: ${detail}` : ""}`
2490
+ );
2491
+ }
2492
+ return this.client.assets.putText({ assetId, storageKey: upload.storageKey });
2493
+ }
2076
2494
  /** Service health — reaches the server without requiring auth. */
2077
2495
  health() {
2078
2496
  return this.client.system.health();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "busa-sdk",
3
- "version": "0.9.3",
3
+ "version": "0.9.4",
4
4
  "description": "Typed TypeScript/JavaScript SDK for the Busabase OpenAPI REST API. Talks to a local or remote `busabase server` (or Busabase Cloud). Short-name alias for busabase-sdk.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/busabase/busabase/tree/main/apps/busabase-sdk",