busabase-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.
- package/dist/index.d.ts +10122 -5137
- package/dist/index.js +433 -15
- package/package.json +4 -4
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,
|
|
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: "
|
|
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: "
|
|
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: `
|
|
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: "
|
|
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": "busabase-sdk",
|
|
3
|
-
"version": "0.9.
|
|
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).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/busabase/busabase/tree/main/apps/busabase-sdk",
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"tsx": "^4.20.5",
|
|
42
42
|
"typescript": "^5.9.3",
|
|
43
43
|
"vitest": "^2.1.8",
|
|
44
|
-
"busabase-contract": "0.9.
|
|
45
|
-
"
|
|
46
|
-
"
|
|
44
|
+
"busabase-contract": "0.9.4",
|
|
45
|
+
"openlib": "0.1.1",
|
|
46
|
+
"open-domains": "0.0.2"
|
|
47
47
|
},
|
|
48
48
|
"engines": {
|
|
49
49
|
"node": ">=24.18.0"
|