busabase-sdk 0.19.2 → 0.21.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/airapp-check.d.ts +117 -0
- package/dist/airapp-check.js +159 -0
- package/dist/airapp-node.d.ts +34 -1
- package/dist/airapp-node.js +22 -1
- package/dist/airapp.d.ts +1 -1
- package/dist/airapp.js +30 -5
- package/dist/{client-kiUJSr_d.d.ts → client-CVz2pqrF.d.ts} +3512 -26
- package/dist/index.d.ts +5 -2769
- package/dist/index.js +284 -164
- package/package.json +8 -4
package/dist/index.js
CHANGED
|
@@ -136,13 +136,15 @@ const AgentSessionVOSchema = z.object({
|
|
|
136
136
|
/** Set when status is "failed"; surfaced verbatim to the user. */
|
|
137
137
|
error: z.string().nullable().default(null)
|
|
138
138
|
});
|
|
139
|
-
/** One connected agent backend in the
|
|
139
|
+
/** One connected agent backend visible in the requested workspace scope. */
|
|
140
140
|
const AgentConnectionVOSchema = z.object({
|
|
141
141
|
slug: z.string(),
|
|
142
142
|
agentName: z.string(),
|
|
143
143
|
transport: AgentTransportSchema,
|
|
144
144
|
sessionCount: z.number().int().nonnegative(),
|
|
145
|
-
latest: AgentSessionVOSchema.nullable()
|
|
145
|
+
latest: AgentSessionVOSchema.nullable(),
|
|
146
|
+
/** Controls owner-only actions such as deleting the saved OAuth grant. */
|
|
147
|
+
ownedByCurrentUser: z.boolean()
|
|
146
148
|
});
|
|
147
149
|
/**
|
|
148
150
|
* One streamed event from a session.
|
|
@@ -178,17 +180,34 @@ const AgentSessionEventVOSchema = z.object({
|
|
|
178
180
|
permissionOptionId: z.string().optional(),
|
|
179
181
|
at: z.string()
|
|
180
182
|
});
|
|
183
|
+
const AgentConnectionScopeSchema = z.enum(["mine", "space"]);
|
|
184
|
+
const ListAgentConnectionsInputSchema = z.object({ scope: AgentConnectionScopeSchema.default("mine") });
|
|
181
185
|
const CreateAgentSessionInputSchema = z.object({
|
|
182
186
|
/** Must name a catalog entry. Deliberately NOT a command line — see below. */
|
|
183
187
|
slug: z.string().min(1) });
|
|
184
188
|
const DisconnectAgentInputSchema = z.object({
|
|
185
189
|
/** The exact connected-agent slug shown by the sessions/catalog surfaces. */
|
|
186
190
|
slug: z.string().min(1) });
|
|
187
|
-
/**
|
|
191
|
+
/**
|
|
192
|
+
* A base64 payload the browser attached.
|
|
193
|
+
*
|
|
194
|
+
* `image`/`audio` map to ACP's `ImageContent`/`AudioContent` verbatim; `file`
|
|
195
|
+
* is everything else (a PDF, a spreadsheet, a Markdown note) and becomes an
|
|
196
|
+
* ACP embedded `resource` block at send time. `data` is base64 for every kind
|
|
197
|
+
* — including textual files — so the browser never has to guess an encoding;
|
|
198
|
+
* whether a file travels to the agent as ACP text or as an ACP blob is decided
|
|
199
|
+
* server-side from the payload itself.
|
|
200
|
+
*/
|
|
188
201
|
const PromptAttachmentInputSchema = z.object({
|
|
189
|
-
kind: z.enum([
|
|
190
|
-
|
|
191
|
-
|
|
202
|
+
kind: z.enum([
|
|
203
|
+
"image",
|
|
204
|
+
"audio",
|
|
205
|
+
"file"
|
|
206
|
+
]),
|
|
207
|
+
data: z.string().min(1).max(2e7),
|
|
208
|
+
mimeType: z.string().min(1),
|
|
209
|
+
/** The original filename, carried for `file` so the agent and the transcript can name it. */
|
|
210
|
+
filename: z.string().max(255).optional()
|
|
192
211
|
});
|
|
193
212
|
const PromptAgentSessionInputSchema = z.object({
|
|
194
213
|
sessionId: z.string().min(1),
|
|
@@ -219,8 +238,8 @@ const agentsContract = {
|
|
|
219
238
|
deletedSessionCount: z.number().int().nonnegative()
|
|
220
239
|
})),
|
|
221
240
|
connections: {
|
|
222
|
-
/** Connected backends
|
|
223
|
-
list: oc.output(AgentConnectionVOSchema.array()) },
|
|
241
|
+
/** Connected backends in the current user's personal or active-space scope. */
|
|
242
|
+
list: oc.input(ListAgentConnectionsInputSchema).output(AgentConnectionVOSchema.array()) },
|
|
224
243
|
sessions: {
|
|
225
244
|
list: oc.output(AgentSessionVOSchema.array()),
|
|
226
245
|
create: oc.input(CreateAgentSessionInputSchema).output(AgentSessionVOSchema),
|
|
@@ -663,7 +682,8 @@ const makeFileTreeNodeType = (config) => ({
|
|
|
663
682
|
icon: config.icon,
|
|
664
683
|
capabilities: {
|
|
665
684
|
hasDetail: true,
|
|
666
|
-
creatable: true
|
|
685
|
+
creatable: true,
|
|
686
|
+
publicAccess: config.publicAccess
|
|
667
687
|
},
|
|
668
688
|
operations: fileTreeOperations(config.type)
|
|
669
689
|
});
|
|
@@ -681,7 +701,8 @@ const airappNodeType = makeFileTreeNodeType({
|
|
|
681
701
|
icon: "app-window",
|
|
682
702
|
routeBase: "airapps",
|
|
683
703
|
tag: "AirApps",
|
|
684
|
-
entryFile: "package.json"
|
|
704
|
+
entryFile: "package.json",
|
|
705
|
+
publicAccess: "no"
|
|
685
706
|
});
|
|
686
707
|
//#endregion
|
|
687
708
|
//#region ../../packages/busabase-contract/src/domains/base/definition.ts
|
|
@@ -692,7 +713,8 @@ const baseNodeType = {
|
|
|
692
713
|
icon: "table",
|
|
693
714
|
capabilities: {
|
|
694
715
|
hasDetail: true,
|
|
695
|
-
creatable: true
|
|
716
|
+
creatable: true,
|
|
717
|
+
publicAccess: "detail"
|
|
696
718
|
},
|
|
697
719
|
operations: [
|
|
698
720
|
{
|
|
@@ -795,7 +817,8 @@ const docNodeType = {
|
|
|
795
817
|
icon: "file-text",
|
|
796
818
|
capabilities: {
|
|
797
819
|
hasDetail: true,
|
|
798
|
-
creatable: true
|
|
820
|
+
creatable: true,
|
|
821
|
+
publicAccess: "detail"
|
|
799
822
|
},
|
|
800
823
|
operations: [{
|
|
801
824
|
kind: "doc_update",
|
|
@@ -812,7 +835,8 @@ const driveNodeType = makeFileTreeNodeType({
|
|
|
812
835
|
icon: "hard-drive",
|
|
813
836
|
routeBase: "drives",
|
|
814
837
|
tag: "Drives",
|
|
815
|
-
entryFile: "README.md"
|
|
838
|
+
entryFile: "README.md",
|
|
839
|
+
publicAccess: "no"
|
|
816
840
|
});
|
|
817
841
|
//#endregion
|
|
818
842
|
//#region ../../packages/busabase-contract/src/domains/file-node/definition.ts
|
|
@@ -824,7 +848,8 @@ const fileNodeType = {
|
|
|
824
848
|
icon: "file",
|
|
825
849
|
capabilities: {
|
|
826
850
|
hasDetail: true,
|
|
827
|
-
creatable: true
|
|
851
|
+
creatable: true,
|
|
852
|
+
publicAccess: "detail"
|
|
828
853
|
},
|
|
829
854
|
operations: []
|
|
830
855
|
};
|
|
@@ -839,7 +864,8 @@ const folderNodeType = {
|
|
|
839
864
|
capabilities: {
|
|
840
865
|
container: true,
|
|
841
866
|
creatable: true,
|
|
842
|
-
hasDetail: true
|
|
867
|
+
hasDetail: true,
|
|
868
|
+
publicAccess: "detail"
|
|
843
869
|
},
|
|
844
870
|
operations: []
|
|
845
871
|
};
|
|
@@ -860,7 +886,8 @@ const formNodeType = {
|
|
|
860
886
|
icon: "form",
|
|
861
887
|
capabilities: {
|
|
862
888
|
hasDetail: true,
|
|
863
|
-
creatable: true
|
|
889
|
+
creatable: true,
|
|
890
|
+
publicAccess: "submit"
|
|
864
891
|
},
|
|
865
892
|
operations: []
|
|
866
893
|
};
|
|
@@ -879,7 +906,8 @@ const htmlNodeType = {
|
|
|
879
906
|
icon: "code-xml",
|
|
880
907
|
capabilities: {
|
|
881
908
|
hasDetail: true,
|
|
882
|
-
creatable: true
|
|
909
|
+
creatable: true,
|
|
910
|
+
publicAccess: "no"
|
|
883
911
|
},
|
|
884
912
|
operations: [{
|
|
885
913
|
kind: "html_document_update",
|
|
@@ -896,7 +924,8 @@ const skillNodeType = makeFileTreeNodeType({
|
|
|
896
924
|
icon: "sparkles",
|
|
897
925
|
routeBase: "skills",
|
|
898
926
|
tag: "Skills",
|
|
899
|
-
entryFile: "SKILL.md"
|
|
927
|
+
entryFile: "SKILL.md",
|
|
928
|
+
publicAccess: "no"
|
|
900
929
|
});
|
|
901
930
|
//#endregion
|
|
902
931
|
//#region ../../packages/busabase-contract/src/domains/whiteboard/definition.ts
|
|
@@ -912,7 +941,8 @@ const whiteboardNodeType = {
|
|
|
912
941
|
icon: "pen-tool",
|
|
913
942
|
capabilities: {
|
|
914
943
|
hasDetail: true,
|
|
915
|
-
creatable: true
|
|
944
|
+
creatable: true,
|
|
945
|
+
publicAccess: "detail"
|
|
916
946
|
},
|
|
917
947
|
operations: [{
|
|
918
948
|
kind: "whiteboard_document_update",
|
|
@@ -935,7 +965,8 @@ const workflowNodeType = {
|
|
|
935
965
|
icon: "workflow",
|
|
936
966
|
capabilities: {
|
|
937
967
|
hasDetail: true,
|
|
938
|
-
creatable: true
|
|
968
|
+
creatable: true,
|
|
969
|
+
publicAccess: "detail"
|
|
939
970
|
},
|
|
940
971
|
operations: [{
|
|
941
972
|
kind: "workflow_document_update",
|
|
@@ -1161,6 +1192,23 @@ const userRefSchema = z.object({
|
|
|
1161
1192
|
image: z.string().nullable(),
|
|
1162
1193
|
role: z.string().nullable().optional()
|
|
1163
1194
|
});
|
|
1195
|
+
const sourceChannelSchema = z.enum([
|
|
1196
|
+
"web_ui",
|
|
1197
|
+
"browser",
|
|
1198
|
+
"openapi",
|
|
1199
|
+
"sdk",
|
|
1200
|
+
"cli",
|
|
1201
|
+
"mcp",
|
|
1202
|
+
"skill",
|
|
1203
|
+
"webhook",
|
|
1204
|
+
"automation",
|
|
1205
|
+
"import"
|
|
1206
|
+
]);
|
|
1207
|
+
const sourceAttributionSchema = z.object({
|
|
1208
|
+
displayName: z.string().nullable(),
|
|
1209
|
+
ownerName: z.string().nullable(),
|
|
1210
|
+
channel: sourceChannelSchema.nullable()
|
|
1211
|
+
});
|
|
1164
1212
|
const commitSchema = z.object({
|
|
1165
1213
|
id: z.string(),
|
|
1166
1214
|
baseId: z.string().nullable(),
|
|
@@ -1252,6 +1300,7 @@ const changeRequestSchema = z.object({
|
|
|
1252
1300
|
status: changeRequestStatusSchema,
|
|
1253
1301
|
submittedBy: z.string(),
|
|
1254
1302
|
submittedByUser: userRefSchema.nullable().optional().default(null),
|
|
1303
|
+
sourceAttribution: sourceAttributionSchema.nullable().optional(),
|
|
1255
1304
|
sourceMeta: z.record(z.string(), z.unknown()),
|
|
1256
1305
|
reviewPolicySnapshot: z.record(z.string(), z.unknown()),
|
|
1257
1306
|
mergeSummary: z.record(z.string(), z.unknown()),
|
|
@@ -1275,11 +1324,18 @@ const agentTaskSchema = z.object({
|
|
|
1275
1324
|
});
|
|
1276
1325
|
const searchResultSchema = z.object({
|
|
1277
1326
|
id: z.string(),
|
|
1327
|
+
/**
|
|
1328
|
+
* `node` covers the CONTENT of a content-bearing node (doc / html /
|
|
1329
|
+
* whiteboard / workflow). Purely additive — callers that do not know it can
|
|
1330
|
+
* ignore the kind, and callers that never asked for it (an explicit
|
|
1331
|
+
* `sources` list without `nodes`) never receive it.
|
|
1332
|
+
*/
|
|
1278
1333
|
kind: z.enum([
|
|
1279
1334
|
"record",
|
|
1280
1335
|
"change_request",
|
|
1281
1336
|
"base",
|
|
1282
|
-
"file"
|
|
1337
|
+
"file",
|
|
1338
|
+
"node"
|
|
1283
1339
|
]),
|
|
1284
1340
|
title: z.string(),
|
|
1285
1341
|
body: z.string(),
|
|
@@ -1292,7 +1348,17 @@ const searchResponseSchema = z.object({
|
|
|
1292
1348
|
limit: z.number(),
|
|
1293
1349
|
offset: z.number(),
|
|
1294
1350
|
hasMore: z.boolean(),
|
|
1295
|
-
results: z.array(searchResultSchema)
|
|
1351
|
+
results: z.array(searchResultSchema),
|
|
1352
|
+
/**
|
|
1353
|
+
* True when at least one in-scope node's content was indexed only up to the
|
|
1354
|
+
* projection cap, so this search could not see all of it.
|
|
1355
|
+
*
|
|
1356
|
+
* Exists so an empty result can be reported honestly: without it, "no
|
|
1357
|
+
* results" is ambiguous between "the workspace does not contain this" and
|
|
1358
|
+
* "we did not look at all of it". Clients should surface it — and point at
|
|
1359
|
+
* `grep`, which has no such cap — rather than implying absence.
|
|
1360
|
+
*/
|
|
1361
|
+
contentTruncated: z.boolean().default(false)
|
|
1296
1362
|
});
|
|
1297
1363
|
const liveEventSchema = z.object({
|
|
1298
1364
|
kind: z.enum([
|
|
@@ -1340,6 +1406,7 @@ const auditEventSchema = z.object({
|
|
|
1340
1406
|
action: auditActionSchema,
|
|
1341
1407
|
actorId: z.string(),
|
|
1342
1408
|
actor: userRefSchema.nullable().optional().default(null),
|
|
1409
|
+
sourceAttribution: sourceAttributionSchema.nullable().optional(),
|
|
1343
1410
|
baseId: z.string().nullable(),
|
|
1344
1411
|
recordId: z.string().nullable(),
|
|
1345
1412
|
changeRequestId: z.string().nullable(),
|
|
@@ -1461,21 +1528,30 @@ const listChangeRequestsPagedInputSchema = z.object({
|
|
|
1461
1528
|
/** Opaque base64 cursor (`createdAt|id`) for keyset pagination. */
|
|
1462
1529
|
cursor: z.string().optional(),
|
|
1463
1530
|
status: z.array(changeRequestStatusSchema).optional(),
|
|
1464
|
-
mine: z.boolean().optional()
|
|
1531
|
+
mine: z.boolean().optional(),
|
|
1532
|
+
affectsNodeId: z.string().min(1).optional()
|
|
1465
1533
|
}).optional().default({ limit: 50 });
|
|
1466
1534
|
const listChangeRequestsResponseSchema = z.object({
|
|
1467
1535
|
changeRequests: z.array(changeRequestSchema),
|
|
1468
1536
|
nextCursor: z.string().nullable()
|
|
1469
1537
|
});
|
|
1470
|
-
const
|
|
1538
|
+
const changeRequestPageInputShape = {
|
|
1471
1539
|
page: z.coerce.number().int().min(1).optional().default(1),
|
|
1472
1540
|
pageSize: z.coerce.number().int().min(1).max(100).optional().default(50),
|
|
1473
1541
|
status: z.array(changeRequestStatusSchema).optional(),
|
|
1474
1542
|
mine: z.boolean().optional()
|
|
1543
|
+
};
|
|
1544
|
+
const listChangeRequestsPageInputSchema = z.object({
|
|
1545
|
+
...changeRequestPageInputShape,
|
|
1546
|
+
affectsNodeId: z.string().min(1).optional()
|
|
1475
1547
|
}).optional().default({
|
|
1476
1548
|
page: 1,
|
|
1477
1549
|
pageSize: 50
|
|
1478
1550
|
});
|
|
1551
|
+
const inboxSnapshotInputSchema = z.object(changeRequestPageInputShape).optional().default({
|
|
1552
|
+
page: 1,
|
|
1553
|
+
pageSize: 50
|
|
1554
|
+
});
|
|
1479
1555
|
const listChangeRequestsPageResponseSchema = z.object({
|
|
1480
1556
|
changeRequests: z.array(changeRequestSchema),
|
|
1481
1557
|
total: z.number().int().nonnegative(),
|
|
@@ -1495,7 +1571,8 @@ const inboxSnapshotResponseSchema = listChangeRequestsPageResponseSchema.extend(
|
|
|
1495
1571
|
const SEARCH_SOURCES = [
|
|
1496
1572
|
"records",
|
|
1497
1573
|
"files",
|
|
1498
|
-
"names"
|
|
1574
|
+
"names",
|
|
1575
|
+
"nodes"
|
|
1499
1576
|
];
|
|
1500
1577
|
const searchInputSchema = z.object({
|
|
1501
1578
|
query: z.string().default(""),
|
|
@@ -2763,6 +2840,19 @@ const ExportAssetTextVOSchema = z.object({
|
|
|
2763
2840
|
textContentHash: z.string().nullable(),
|
|
2764
2841
|
byteCount: z.number().int().nonnegative()
|
|
2765
2842
|
});
|
|
2843
|
+
const ImportBeginInputSchema = z.object({
|
|
2844
|
+
/**
|
|
2845
|
+
* The space id the archive was ORIGINALLY exported from (`manifest.spaceId`
|
|
2846
|
+
* in the `.bbdump`, already integrity-verified before this is called).
|
|
2847
|
+
* `importTableRows`'s "nodes" handling needs this to recognize the
|
|
2848
|
+
* archive's own root-node row deterministically (`rootNodeIdForSpace`) —
|
|
2849
|
+
* scanning each batch's rows for "the one with a null `parentId`" only
|
|
2850
|
+
* works when that row happens to land in the SAME batch as its children,
|
|
2851
|
+
* which cursor pagination (id-ordered, not tree-ordered) does not
|
|
2852
|
+
* guarantee once a space has more nodes than one page. See the matching
|
|
2853
|
+
* comment in `import-logic.ts`.
|
|
2854
|
+
*/
|
|
2855
|
+
sourceSpaceId: z.string() });
|
|
2766
2856
|
const ImportBeginVOSchema = z.object({ sessionId: z.string() });
|
|
2767
2857
|
/**
|
|
2768
2858
|
* `docBodies`, `attachmentBlobs` and `assetTextBlobs` are pseudo-tables: doc
|
|
@@ -2826,7 +2916,7 @@ const dumpContract = {
|
|
|
2826
2916
|
tags: ["Dump"],
|
|
2827
2917
|
summary: "Begin a full-fidelity import session",
|
|
2828
2918
|
successDescription: "Created an import session for the current space. Refused unless the space's node tree is empty (full-fidelity import preserves original ids and cannot merge into existing data)."
|
|
2829
|
-
}).output(ImportBeginVOSchema),
|
|
2919
|
+
}).input(ImportBeginInputSchema).output(ImportBeginVOSchema),
|
|
2830
2920
|
importTables: oc.route({
|
|
2831
2921
|
method: "POST",
|
|
2832
2922
|
path: "/dump/import/tables",
|
|
@@ -3671,6 +3761,104 @@ const listRecordActivityInputSchema = z.object({
|
|
|
3671
3761
|
recordId: z.string().min(1),
|
|
3672
3762
|
limit: z.coerce.number().int().min(1).max(100).optional().default(50)
|
|
3673
3763
|
});
|
|
3764
|
+
const EMBED_LINK_MAX_MINUTES = 1440;
|
|
3765
|
+
const EmbedNodeTypeSchema = z.enum([
|
|
3766
|
+
"base",
|
|
3767
|
+
"doc",
|
|
3768
|
+
"file",
|
|
3769
|
+
"drive",
|
|
3770
|
+
"skill",
|
|
3771
|
+
"folder",
|
|
3772
|
+
"airapp"
|
|
3773
|
+
]);
|
|
3774
|
+
const EmbedTargetTypeSchema = z.enum([
|
|
3775
|
+
"node",
|
|
3776
|
+
"change-request",
|
|
3777
|
+
"record-detail"
|
|
3778
|
+
]);
|
|
3779
|
+
const EmbedFrameModeSchema = z.enum([
|
|
3780
|
+
"anywhere",
|
|
3781
|
+
"origins",
|
|
3782
|
+
"top-level-only"
|
|
3783
|
+
]);
|
|
3784
|
+
const EmbedAllowedOriginSchema = z.string().trim().min(1).superRefine((value, ctx) => {
|
|
3785
|
+
let url;
|
|
3786
|
+
try {
|
|
3787
|
+
url = new URL(value);
|
|
3788
|
+
} catch {
|
|
3789
|
+
ctx.addIssue({
|
|
3790
|
+
code: "custom",
|
|
3791
|
+
message: "Allowed origins must be valid URLs"
|
|
3792
|
+
});
|
|
3793
|
+
return;
|
|
3794
|
+
}
|
|
3795
|
+
const isLocalHttp = url.protocol === "http:" && (url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]");
|
|
3796
|
+
if (url.protocol !== "https:" && !isLocalHttp) ctx.addIssue({
|
|
3797
|
+
code: "custom",
|
|
3798
|
+
message: "Allowed origins must use HTTPS"
|
|
3799
|
+
});
|
|
3800
|
+
if (url.username || url.password || url.pathname !== "/" || url.search || url.hash || url.hostname.includes("*")) ctx.addIssue({
|
|
3801
|
+
code: "custom",
|
|
3802
|
+
message: "Allowed origins must be exact origins"
|
|
3803
|
+
});
|
|
3804
|
+
}).transform((value) => new URL(value).origin);
|
|
3805
|
+
const EmbedFramePolicyInputSchema = z.discriminatedUnion("mode", [
|
|
3806
|
+
z.object({
|
|
3807
|
+
mode: z.literal("anywhere"),
|
|
3808
|
+
allowedOrigins: z.array(EmbedAllowedOriginSchema).max(0).optional()
|
|
3809
|
+
}),
|
|
3810
|
+
z.object({
|
|
3811
|
+
mode: z.literal("origins"),
|
|
3812
|
+
allowedOrigins: z.array(EmbedAllowedOriginSchema).min(1).max(20)
|
|
3813
|
+
}),
|
|
3814
|
+
z.object({
|
|
3815
|
+
mode: z.literal("top-level-only"),
|
|
3816
|
+
allowedOrigins: z.array(EmbedAllowedOriginSchema).max(0).optional()
|
|
3817
|
+
})
|
|
3818
|
+
]).transform((policy) => ({
|
|
3819
|
+
mode: policy.mode,
|
|
3820
|
+
allowedOrigins: [...new Set(policy.allowedOrigins ?? [])]
|
|
3821
|
+
}));
|
|
3822
|
+
const EmbedFramePolicyVOSchema = z.object({
|
|
3823
|
+
mode: EmbedFrameModeSchema,
|
|
3824
|
+
allowedOrigins: z.array(z.string().url())
|
|
3825
|
+
}).superRefine((policy, ctx) => {
|
|
3826
|
+
if (!(policy.mode === "origins" ? policy.allowedOrigins.length > 0 : policy.allowedOrigins.length === 0)) ctx.addIssue({
|
|
3827
|
+
code: "custom",
|
|
3828
|
+
message: "Stored frame policy is invalid"
|
|
3829
|
+
});
|
|
3830
|
+
});
|
|
3831
|
+
const CreateEmbedLinkInputSchema = z.object({
|
|
3832
|
+
type: EmbedTargetTypeSchema,
|
|
3833
|
+
typeId: z.string().min(1),
|
|
3834
|
+
expiresInMinutes: z.number().int().min(1).max(EMBED_LINK_MAX_MINUTES).optional().default(15),
|
|
3835
|
+
framePolicy: EmbedFramePolicyInputSchema.optional().default({
|
|
3836
|
+
mode: "anywhere",
|
|
3837
|
+
allowedOrigins: []
|
|
3838
|
+
})
|
|
3839
|
+
});
|
|
3840
|
+
const ListEmbedLinksInputSchema = z.object({
|
|
3841
|
+
type: EmbedTargetTypeSchema.optional(),
|
|
3842
|
+
typeId: z.string().min(1).optional()
|
|
3843
|
+
}).optional().default({});
|
|
3844
|
+
const RevokeEmbedLinkInputSchema = z.object({ id: z.string().min(1) });
|
|
3845
|
+
const EmbedLinkVOSchema = z.object({
|
|
3846
|
+
id: z.string(),
|
|
3847
|
+
type: EmbedTargetTypeSchema,
|
|
3848
|
+
typeId: z.string(),
|
|
3849
|
+
targetName: z.string(),
|
|
3850
|
+
nodeType: EmbedNodeTypeSchema.nullable(),
|
|
3851
|
+
createdAt: z.string().datetime(),
|
|
3852
|
+
expiresAt: z.string().datetime(),
|
|
3853
|
+
revokedAt: z.string().datetime().nullable(),
|
|
3854
|
+
active: z.boolean(),
|
|
3855
|
+
framePolicy: EmbedFramePolicyVOSchema
|
|
3856
|
+
});
|
|
3857
|
+
const CreatedEmbedLinkVOSchema = EmbedLinkVOSchema.extend({
|
|
3858
|
+
url: z.string().url(),
|
|
3859
|
+
iframeUrl: z.string().url()
|
|
3860
|
+
});
|
|
3861
|
+
const RevokeEmbedLinkVOSchema = z.object({ revoked: z.literal(true) });
|
|
3674
3862
|
//#endregion
|
|
3675
3863
|
//#region ../../packages/busabase-contract/src/contract/grep-schemas.ts
|
|
3676
3864
|
/**
|
|
@@ -4107,6 +4295,14 @@ const NodeDetailVOSchema = z.discriminatedUnion("type", [
|
|
|
4107
4295
|
* hint. An ambiguous slug with no `type` is refused rather than silently
|
|
4108
4296
|
* resolved to whichever row sorts first.
|
|
4109
4297
|
*/
|
|
4298
|
+
/**
|
|
4299
|
+
* `nodes.ancestors` output — the node's ancestor ids, ROOT-FIRST, excluding
|
|
4300
|
+
* the node itself. Ids only, deliberately: the sidebar already has (or can
|
|
4301
|
+
* lazily fetch) each ancestor's own row, and it only needs to know WHICH
|
|
4302
|
+
* folders to expand. Returning full nodes here would duplicate `nodes.list`
|
|
4303
|
+
* and make a cheap navigational lookup expensive.
|
|
4304
|
+
*/
|
|
4305
|
+
const nodeAncestorsVOSchema = z.object({ ancestorIds: z.array(z.string()) });
|
|
4110
4306
|
const getNodeInputSchema = z.object({
|
|
4111
4307
|
nodeId: z.string().describe("Node id, or a slug that is unique within its type."),
|
|
4112
4308
|
type: z.enum(NODE_TYPES).optional().describe("Optional disambiguation hint, only needed when `nodeId` is a slug that exists under more than one node type.")
|
|
@@ -4134,6 +4330,29 @@ const changeRequestBatchFailureSchema = z.object({
|
|
|
4134
4330
|
code: z.string().optional(),
|
|
4135
4331
|
data: z.unknown().optional()
|
|
4136
4332
|
});
|
|
4333
|
+
const embedLinkErrorResponseSchema = z.object({ error: z.string() });
|
|
4334
|
+
const embedLinkErrors = {
|
|
4335
|
+
BAD_REQUEST: {
|
|
4336
|
+
status: 400,
|
|
4337
|
+
message: "Bad Request",
|
|
4338
|
+
data: embedLinkErrorResponseSchema
|
|
4339
|
+
},
|
|
4340
|
+
UNAUTHORIZED: {
|
|
4341
|
+
status: 401,
|
|
4342
|
+
message: "Unauthorized",
|
|
4343
|
+
data: embedLinkErrorResponseSchema
|
|
4344
|
+
},
|
|
4345
|
+
FORBIDDEN: {
|
|
4346
|
+
status: 403,
|
|
4347
|
+
message: "Forbidden",
|
|
4348
|
+
data: embedLinkErrorResponseSchema
|
|
4349
|
+
},
|
|
4350
|
+
NOT_FOUND: {
|
|
4351
|
+
status: 404,
|
|
4352
|
+
message: "Not Found",
|
|
4353
|
+
data: embedLinkErrorResponseSchema
|
|
4354
|
+
}
|
|
4355
|
+
};
|
|
4137
4356
|
const changeRequestReviewBatchResultSchema = z.object({ results: z.array(z.discriminatedUnion("ok", [z.object({
|
|
4138
4357
|
changeRequestId: z.string(),
|
|
4139
4358
|
ok: z.literal(true),
|
|
@@ -4170,6 +4389,29 @@ const busabaseContractRoutes = {
|
|
|
4170
4389
|
summary: "Search files, Docs, and Base records with one pattern (unified grep)",
|
|
4171
4390
|
successDescription: "Streaming regex/literal matches across every in-scope source — Drive/Skill files, Doc bodies, and Base records (canonical headCommit.payload, never the truncated search projection) — with one shared pattern, one shared maxMatches/deadline budget (files scanned first, then docs, then whatever budget remains goes to records), and a per-source honest coverage report (files keeps its existing missing/stale/unsearchable/errored/notReached; docs and records report scanned/errored/notReached). truncated is set when any source truncated or has notReached > 0."
|
|
4172
4391
|
}).input(UnifiedGrepInputSchema).output(UnifiedGrepResultVOSchema),
|
|
4392
|
+
embedLinks: {
|
|
4393
|
+
create: oc.route({
|
|
4394
|
+
method: "POST",
|
|
4395
|
+
path: "/embed-links",
|
|
4396
|
+
tags: ["Embed Links"],
|
|
4397
|
+
summary: "Create a polymorphic read-only embed link",
|
|
4398
|
+
successDescription: "The capability URL is returned once; only its secret hash is stored."
|
|
4399
|
+
}).errors(embedLinkErrors).input(CreateEmbedLinkInputSchema).output(CreatedEmbedLinkVOSchema),
|
|
4400
|
+
list: oc.route({
|
|
4401
|
+
method: "GET",
|
|
4402
|
+
path: "/embed-links",
|
|
4403
|
+
tags: ["Embed Links"],
|
|
4404
|
+
summary: "List embed links the caller can manage",
|
|
4405
|
+
successDescription: "Embed link metadata without capability secrets."
|
|
4406
|
+
}).errors(embedLinkErrors).input(ListEmbedLinksInputSchema).output(z.array(EmbedLinkVOSchema)),
|
|
4407
|
+
revoke: oc.route({
|
|
4408
|
+
method: "DELETE",
|
|
4409
|
+
path: "/embed-links/{id}",
|
|
4410
|
+
tags: ["Embed Links"],
|
|
4411
|
+
summary: "Revoke an embed link",
|
|
4412
|
+
successDescription: "The capability stops resolving immediately."
|
|
4413
|
+
}).errors(embedLinkErrors).input(RevokeEmbedLinkInputSchema).output(RevokeEmbedLinkVOSchema)
|
|
4414
|
+
},
|
|
4173
4415
|
nodes: {
|
|
4174
4416
|
list: oc.route({
|
|
4175
4417
|
method: "GET",
|
|
@@ -4183,7 +4425,7 @@ const busabaseContractRoutes = {
|
|
|
4183
4425
|
path: "/nodes/search",
|
|
4184
4426
|
tags: ["Nodes", "Search"],
|
|
4185
4427
|
summary: "Search nodes by name/slug (cheap, name-only quick-jump)",
|
|
4186
|
-
successDescription: "Plain ilike match on name/slug across every registered node type, scoped by the same node-visibility ACL as `nodes.list`. No content scan and no full-text ranking — ordered exact-slug-match first, then by name. Backs the dashboard search dialog's 'Recent' tab cache-miss path
|
|
4428
|
+
successDescription: "Plain ilike match on name/slug across every registered node type, scoped by the same node-visibility ACL as `nodes.list`. No content scan and no full-text ranking — ordered exact-slug-match first, then by name. Backs the dashboard search dialog's 'Recent' tab cache-miss path. To search what is written INSIDE nodes, use `search` with the `nodes` source (indexed, paginated) or `grep` (exhaustive, no index)."
|
|
4187
4429
|
}).input(searchNodesByNameInputSchema).output(z.array(nodeSearchResultSchema)),
|
|
4188
4430
|
isDescendant: oc.route({
|
|
4189
4431
|
method: "GET",
|
|
@@ -4192,6 +4434,13 @@ const busabaseContractRoutes = {
|
|
|
4192
4434
|
summary: "Check whether a node is a descendant of another",
|
|
4193
4435
|
successDescription: "Server-authoritative parentId-chain walk from nodeId up to potentialAncestorId. Used to gate cross-branch drag-and-drop drops in the sidebar, since the full tree is no longer guaranteed to be loaded client-side (depth-bounded lazy load) — a purely local walk could wrongly allow dropping a folder into its own unloaded descendant."
|
|
4194
4436
|
}).input(isDescendantInputSchema).output(isDescendantOutputSchema),
|
|
4437
|
+
ancestors: oc.route({
|
|
4438
|
+
method: "GET",
|
|
4439
|
+
path: "/nodes/{nodeId}/ancestors",
|
|
4440
|
+
tags: ["Nodes"],
|
|
4441
|
+
summary: "List a node's ancestor ids",
|
|
4442
|
+
successDescription: "The node's ancestor ids, root-first, excluding the node itself (`[]` directly under the workspace root). `nodeId` accepts an id or a slug, same as `nodes.get`; pass `type` when a slug exists under more than one type. Lets a depth-bounded, lazily-expanded tree open straight to a deep node on a cold load (a refresh, a bookmark, a shared link) without one round trip per level."
|
|
4443
|
+
}).input(getNodeInputSchema).output(nodeAncestorsVOSchema),
|
|
4195
4444
|
createChangeRequest: oc.route({
|
|
4196
4445
|
method: "POST",
|
|
4197
4446
|
path: "/nodes/change-requests",
|
|
@@ -4435,16 +4684,16 @@ const busabaseContractRoutes = {
|
|
|
4435
4684
|
path: "/change-requests",
|
|
4436
4685
|
tags: ["Change Requests"],
|
|
4437
4686
|
summary: "List change requests",
|
|
4438
|
-
successDescription: "A page of change requests plus an opaque nextCursor (null at the end). Filter with `status` and/or `
|
|
4687
|
+
successDescription: "A page of change requests plus an opaque nextCursor (null at the end). Filter with `status`, `mine`, and/or `affectsNodeId`."
|
|
4439
4688
|
}).input(listChangeRequestsPagedInputSchema).output(listChangeRequestsResponseSchema),
|
|
4440
4689
|
listPage: oc.route({
|
|
4441
4690
|
method: "GET",
|
|
4442
4691
|
path: "/change-requests/page",
|
|
4443
4692
|
tags: ["Change Requests"],
|
|
4444
4693
|
summary: "List a numbered change request page",
|
|
4445
|
-
successDescription: "A random-access page of change requests plus the total across the whole filter. Same `status`
|
|
4694
|
+
successDescription: "A random-access page of change requests plus the total across the whole filter. Same `status`, `mine`, and `affectsNodeId` filters as the cursor listing."
|
|
4446
4695
|
}).input(listChangeRequestsPageInputSchema).output(listChangeRequestsPageResponseSchema),
|
|
4447
|
-
inboxSnapshot: oc.input(
|
|
4696
|
+
inboxSnapshot: oc.input(inboxSnapshotInputSchema).output(inboxSnapshotResponseSchema),
|
|
4448
4697
|
counts: oc.route({
|
|
4449
4698
|
method: "GET",
|
|
4450
4699
|
path: "/change-requests/counts",
|
|
@@ -4495,94 +4744,6 @@ const busabaseContractRoutes = {
|
|
|
4495
4744
|
views: viewContract
|
|
4496
4745
|
};
|
|
4497
4746
|
oc.prefix("/api/v1").router(busabaseContractRoutes);
|
|
4498
|
-
const EMBED_LINK_MAX_MINUTES = 1440;
|
|
4499
|
-
const EmbedNodeTypeSchema = z.enum([
|
|
4500
|
-
"base",
|
|
4501
|
-
"doc",
|
|
4502
|
-
"file",
|
|
4503
|
-
"drive",
|
|
4504
|
-
"skill",
|
|
4505
|
-
"folder",
|
|
4506
|
-
"airapp"
|
|
4507
|
-
]);
|
|
4508
|
-
const EmbedFrameModeSchema = z.enum([
|
|
4509
|
-
"anywhere",
|
|
4510
|
-
"origins",
|
|
4511
|
-
"top-level-only"
|
|
4512
|
-
]);
|
|
4513
|
-
const EmbedAllowedOriginSchema = z.string().trim().min(1).superRefine((value, ctx) => {
|
|
4514
|
-
let url;
|
|
4515
|
-
try {
|
|
4516
|
-
url = new URL(value);
|
|
4517
|
-
} catch {
|
|
4518
|
-
ctx.addIssue({
|
|
4519
|
-
code: "custom",
|
|
4520
|
-
message: "Allowed origins must be valid URLs"
|
|
4521
|
-
});
|
|
4522
|
-
return;
|
|
4523
|
-
}
|
|
4524
|
-
const isLocalHttp = url.protocol === "http:" && (url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]");
|
|
4525
|
-
if (url.protocol !== "https:" && !isLocalHttp) ctx.addIssue({
|
|
4526
|
-
code: "custom",
|
|
4527
|
-
message: "Allowed origins must use HTTPS"
|
|
4528
|
-
});
|
|
4529
|
-
if (url.username || url.password || url.pathname !== "/" || url.search || url.hash || url.hostname.includes("*")) ctx.addIssue({
|
|
4530
|
-
code: "custom",
|
|
4531
|
-
message: "Allowed origins must be exact origins"
|
|
4532
|
-
});
|
|
4533
|
-
}).transform((value) => new URL(value).origin);
|
|
4534
|
-
const EmbedFramePolicyInputSchema = z.discriminatedUnion("mode", [
|
|
4535
|
-
z.object({
|
|
4536
|
-
mode: z.literal("anywhere"),
|
|
4537
|
-
allowedOrigins: z.array(EmbedAllowedOriginSchema).max(0).optional()
|
|
4538
|
-
}),
|
|
4539
|
-
z.object({
|
|
4540
|
-
mode: z.literal("origins"),
|
|
4541
|
-
allowedOrigins: z.array(EmbedAllowedOriginSchema).min(1).max(20)
|
|
4542
|
-
}),
|
|
4543
|
-
z.object({
|
|
4544
|
-
mode: z.literal("top-level-only"),
|
|
4545
|
-
allowedOrigins: z.array(EmbedAllowedOriginSchema).max(0).optional()
|
|
4546
|
-
})
|
|
4547
|
-
]).transform((policy) => ({
|
|
4548
|
-
mode: policy.mode,
|
|
4549
|
-
allowedOrigins: [...new Set(policy.allowedOrigins ?? [])]
|
|
4550
|
-
}));
|
|
4551
|
-
const EmbedFramePolicyVOSchema = z.object({
|
|
4552
|
-
mode: EmbedFrameModeSchema,
|
|
4553
|
-
allowedOrigins: z.array(z.string().url())
|
|
4554
|
-
}).superRefine((policy, ctx) => {
|
|
4555
|
-
if (!(policy.mode === "origins" ? policy.allowedOrigins.length > 0 : policy.allowedOrigins.length === 0)) ctx.addIssue({
|
|
4556
|
-
code: "custom",
|
|
4557
|
-
message: "Stored frame policy is invalid"
|
|
4558
|
-
});
|
|
4559
|
-
});
|
|
4560
|
-
const CreateEmbedLinkInputSchema = z.object({
|
|
4561
|
-
nodeId: z.string().min(1),
|
|
4562
|
-
expiresInMinutes: z.number().int().min(1).max(EMBED_LINK_MAX_MINUTES).optional().default(15),
|
|
4563
|
-
framePolicy: EmbedFramePolicyInputSchema.optional().default({
|
|
4564
|
-
mode: "anywhere",
|
|
4565
|
-
allowedOrigins: []
|
|
4566
|
-
})
|
|
4567
|
-
});
|
|
4568
|
-
const ListEmbedLinksInputSchema = z.object({ nodeId: z.string().min(1).optional() }).optional().default({});
|
|
4569
|
-
const RevokeEmbedLinkInputSchema = z.object({ id: z.string().min(1) });
|
|
4570
|
-
const EmbedLinkVOSchema = z.object({
|
|
4571
|
-
id: z.string(),
|
|
4572
|
-
nodeId: z.string(),
|
|
4573
|
-
nodeName: z.string(),
|
|
4574
|
-
nodeType: EmbedNodeTypeSchema,
|
|
4575
|
-
createdAt: z.string().datetime(),
|
|
4576
|
-
expiresAt: z.string().datetime(),
|
|
4577
|
-
revokedAt: z.string().datetime().nullable(),
|
|
4578
|
-
active: z.boolean(),
|
|
4579
|
-
framePolicy: EmbedFramePolicyVOSchema
|
|
4580
|
-
});
|
|
4581
|
-
const CreatedEmbedLinkVOSchema = EmbedLinkVOSchema.extend({
|
|
4582
|
-
url: z.string().url(),
|
|
4583
|
-
iframeUrl: z.string().url()
|
|
4584
|
-
});
|
|
4585
|
-
const RevokeEmbedLinkVOSchema = z.object({ revoked: z.literal(true) });
|
|
4586
4747
|
//#endregion
|
|
4587
4748
|
//#region ../../packages/busabase-contract/src/contract/cloud.ts
|
|
4588
4749
|
/**
|
|
@@ -4638,25 +4799,7 @@ const notFoundErrors = { NOT_FOUND: {
|
|
|
4638
4799
|
message: "Not Found",
|
|
4639
4800
|
data: ErrorResponseSchema
|
|
4640
4801
|
} };
|
|
4641
|
-
const
|
|
4642
|
-
BAD_REQUEST: {
|
|
4643
|
-
status: 400,
|
|
4644
|
-
message: "Bad Request",
|
|
4645
|
-
data: ErrorResponseSchema
|
|
4646
|
-
},
|
|
4647
|
-
...authenticatedErrors,
|
|
4648
|
-
FORBIDDEN: {
|
|
4649
|
-
status: 403,
|
|
4650
|
-
message: "Forbidden",
|
|
4651
|
-
data: ErrorResponseSchema
|
|
4652
|
-
},
|
|
4653
|
-
...notFoundErrors
|
|
4654
|
-
};
|
|
4655
|
-
const securedRoute = (operation) => ({
|
|
4656
|
-
...operation,
|
|
4657
|
-
security: [{ bearerAuth: [] }]
|
|
4658
|
-
});
|
|
4659
|
-
const { vault: _localVault, ...cloudWorkbenchRoutes } = busabaseContractRoutes;
|
|
4802
|
+
const { embedLinks: _embedLinksAlreadyPublishedAtRoot, vault: _localVault, ...cloudWorkbenchRoutes } = busabaseContractRoutes;
|
|
4660
4803
|
const cloudExtraRoutes = {
|
|
4661
4804
|
system: {
|
|
4662
4805
|
health: oc.route({
|
|
@@ -4721,32 +4864,7 @@ const cloudExtraRoutes = {
|
|
|
4721
4864
|
...notFoundErrors
|
|
4722
4865
|
}).input(z.object({ params: z.object({ id: z.string() }) })).output(AgentTaskDetailSchema)
|
|
4723
4866
|
},
|
|
4724
|
-
embedLinks:
|
|
4725
|
-
create: oc.route({
|
|
4726
|
-
method: "POST",
|
|
4727
|
-
path: "/embed-links",
|
|
4728
|
-
tags: ["Embed Links"],
|
|
4729
|
-
summary: "Create a short-lived read-only embed link for one node",
|
|
4730
|
-
successDescription: "The capability URL is returned once; only its secret hash is stored.",
|
|
4731
|
-
spec: securedRoute
|
|
4732
|
-
}).errors(embedLinksErrors).input(CreateEmbedLinkInputSchema).output(CreatedEmbedLinkVOSchema),
|
|
4733
|
-
list: oc.route({
|
|
4734
|
-
method: "GET",
|
|
4735
|
-
path: "/embed-links",
|
|
4736
|
-
tags: ["Embed Links"],
|
|
4737
|
-
summary: "List embed links the caller can manage",
|
|
4738
|
-
successDescription: "Embed link metadata without capability secrets.",
|
|
4739
|
-
spec: securedRoute
|
|
4740
|
-
}).errors(embedLinksErrors).input(ListEmbedLinksInputSchema).output(z.array(EmbedLinkVOSchema)),
|
|
4741
|
-
revoke: oc.route({
|
|
4742
|
-
method: "DELETE",
|
|
4743
|
-
path: "/embed-links/{id}",
|
|
4744
|
-
tags: ["Embed Links"],
|
|
4745
|
-
summary: "Revoke an embed link",
|
|
4746
|
-
successDescription: "The capability stops resolving immediately.",
|
|
4747
|
-
spec: securedRoute
|
|
4748
|
-
}).errors(embedLinksErrors).input(RevokeEmbedLinkInputSchema).output(RevokeEmbedLinkVOSchema)
|
|
4749
|
-
}
|
|
4867
|
+
embedLinks: busabaseContractRoutes.embedLinks
|
|
4750
4868
|
};
|
|
4751
4869
|
const cloudContract = oc.prefix("/api/v1").router({
|
|
4752
4870
|
...cloudWorkbenchRoutes,
|
|
@@ -4775,6 +4893,7 @@ function resolveConfig(config = {}) {
|
|
|
4775
4893
|
webUrl: normalizeBaseUrl(config.webUrl ?? env("BUSABASE_WEB_URL") ?? baseUrl),
|
|
4776
4894
|
apiKey: config.apiKey ?? env("BUSABASE_API_KEY"),
|
|
4777
4895
|
spaceId: config.spaceId ?? env("BUSABASE_SPACE_ID"),
|
|
4896
|
+
sourceChannel: config.sourceChannel ?? "sdk",
|
|
4778
4897
|
headers: config.headers,
|
|
4779
4898
|
fetch: config.fetch
|
|
4780
4899
|
};
|
|
@@ -4845,6 +4964,7 @@ function createBusabaseClient(config = {}) {
|
|
|
4845
4964
|
return {
|
|
4846
4965
|
...resolved.apiKey ? { authorization: `Bearer ${resolved.apiKey}` } : {},
|
|
4847
4966
|
...resolved.spaceId ? { "x-busabase-space": resolved.spaceId } : {},
|
|
4967
|
+
"x-busabase-channel": resolved.sourceChannel ?? "sdk",
|
|
4848
4968
|
...extra
|
|
4849
4969
|
};
|
|
4850
4970
|
}
|
|
@@ -5031,7 +5151,7 @@ var Busabase = class {
|
|
|
5031
5151
|
* This is the *authenticated*, durable link: it never expires, but the reader
|
|
5032
5152
|
* needs a session unless the node has public sharing enabled. For a no-login
|
|
5033
5153
|
* link, mint a Cloud embed link instead —
|
|
5034
|
-
* `bb.embedLinks.create({ nodeId })` returns `{ url, iframeUrl }`.
|
|
5154
|
+
* `bb.embedLinks.create({ type: "node", typeId: nodeId })` returns `{ url, iframeUrl }`.
|
|
5035
5155
|
*
|
|
5036
5156
|
* @example
|
|
5037
5157
|
* ```ts
|