busabase-sdk 0.19.2 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1161,6 +1161,23 @@ const userRefSchema = z.object({
1161
1161
  image: z.string().nullable(),
1162
1162
  role: z.string().nullable().optional()
1163
1163
  });
1164
+ const sourceChannelSchema = z.enum([
1165
+ "web_ui",
1166
+ "browser",
1167
+ "openapi",
1168
+ "sdk",
1169
+ "cli",
1170
+ "mcp",
1171
+ "skill",
1172
+ "webhook",
1173
+ "automation",
1174
+ "import"
1175
+ ]);
1176
+ const sourceAttributionSchema = z.object({
1177
+ displayName: z.string().nullable(),
1178
+ ownerName: z.string().nullable(),
1179
+ channel: sourceChannelSchema.nullable()
1180
+ });
1164
1181
  const commitSchema = z.object({
1165
1182
  id: z.string(),
1166
1183
  baseId: z.string().nullable(),
@@ -1252,6 +1269,7 @@ const changeRequestSchema = z.object({
1252
1269
  status: changeRequestStatusSchema,
1253
1270
  submittedBy: z.string(),
1254
1271
  submittedByUser: userRefSchema.nullable().optional().default(null),
1272
+ sourceAttribution: sourceAttributionSchema.nullable().optional(),
1255
1273
  sourceMeta: z.record(z.string(), z.unknown()),
1256
1274
  reviewPolicySnapshot: z.record(z.string(), z.unknown()),
1257
1275
  mergeSummary: z.record(z.string(), z.unknown()),
@@ -1340,6 +1358,7 @@ const auditEventSchema = z.object({
1340
1358
  action: auditActionSchema,
1341
1359
  actorId: z.string(),
1342
1360
  actor: userRefSchema.nullable().optional().default(null),
1361
+ sourceAttribution: sourceAttributionSchema.nullable().optional(),
1343
1362
  baseId: z.string().nullable(),
1344
1363
  recordId: z.string().nullable(),
1345
1364
  changeRequestId: z.string().nullable(),
@@ -1461,21 +1480,30 @@ const listChangeRequestsPagedInputSchema = z.object({
1461
1480
  /** Opaque base64 cursor (`createdAt|id`) for keyset pagination. */
1462
1481
  cursor: z.string().optional(),
1463
1482
  status: z.array(changeRequestStatusSchema).optional(),
1464
- mine: z.boolean().optional()
1483
+ mine: z.boolean().optional(),
1484
+ affectsNodeId: z.string().min(1).optional()
1465
1485
  }).optional().default({ limit: 50 });
1466
1486
  const listChangeRequestsResponseSchema = z.object({
1467
1487
  changeRequests: z.array(changeRequestSchema),
1468
1488
  nextCursor: z.string().nullable()
1469
1489
  });
1470
- const listChangeRequestsPageInputSchema = z.object({
1490
+ const changeRequestPageInputShape = {
1471
1491
  page: z.coerce.number().int().min(1).optional().default(1),
1472
1492
  pageSize: z.coerce.number().int().min(1).max(100).optional().default(50),
1473
1493
  status: z.array(changeRequestStatusSchema).optional(),
1474
1494
  mine: z.boolean().optional()
1495
+ };
1496
+ const listChangeRequestsPageInputSchema = z.object({
1497
+ ...changeRequestPageInputShape,
1498
+ affectsNodeId: z.string().min(1).optional()
1475
1499
  }).optional().default({
1476
1500
  page: 1,
1477
1501
  pageSize: 50
1478
1502
  });
1503
+ const inboxSnapshotInputSchema = z.object(changeRequestPageInputShape).optional().default({
1504
+ page: 1,
1505
+ pageSize: 50
1506
+ });
1479
1507
  const listChangeRequestsPageResponseSchema = z.object({
1480
1508
  changeRequests: z.array(changeRequestSchema),
1481
1509
  total: z.number().int().nonnegative(),
@@ -3671,6 +3699,104 @@ const listRecordActivityInputSchema = z.object({
3671
3699
  recordId: z.string().min(1),
3672
3700
  limit: z.coerce.number().int().min(1).max(100).optional().default(50)
3673
3701
  });
3702
+ const EMBED_LINK_MAX_MINUTES = 1440;
3703
+ const EmbedNodeTypeSchema = z.enum([
3704
+ "base",
3705
+ "doc",
3706
+ "file",
3707
+ "drive",
3708
+ "skill",
3709
+ "folder",
3710
+ "airapp"
3711
+ ]);
3712
+ const EmbedTargetTypeSchema = z.enum([
3713
+ "node",
3714
+ "change-request",
3715
+ "record-detail"
3716
+ ]);
3717
+ const EmbedFrameModeSchema = z.enum([
3718
+ "anywhere",
3719
+ "origins",
3720
+ "top-level-only"
3721
+ ]);
3722
+ const EmbedAllowedOriginSchema = z.string().trim().min(1).superRefine((value, ctx) => {
3723
+ let url;
3724
+ try {
3725
+ url = new URL(value);
3726
+ } catch {
3727
+ ctx.addIssue({
3728
+ code: "custom",
3729
+ message: "Allowed origins must be valid URLs"
3730
+ });
3731
+ return;
3732
+ }
3733
+ const isLocalHttp = url.protocol === "http:" && (url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]");
3734
+ if (url.protocol !== "https:" && !isLocalHttp) ctx.addIssue({
3735
+ code: "custom",
3736
+ message: "Allowed origins must use HTTPS"
3737
+ });
3738
+ if (url.username || url.password || url.pathname !== "/" || url.search || url.hash || url.hostname.includes("*")) ctx.addIssue({
3739
+ code: "custom",
3740
+ message: "Allowed origins must be exact origins"
3741
+ });
3742
+ }).transform((value) => new URL(value).origin);
3743
+ const EmbedFramePolicyInputSchema = z.discriminatedUnion("mode", [
3744
+ z.object({
3745
+ mode: z.literal("anywhere"),
3746
+ allowedOrigins: z.array(EmbedAllowedOriginSchema).max(0).optional()
3747
+ }),
3748
+ z.object({
3749
+ mode: z.literal("origins"),
3750
+ allowedOrigins: z.array(EmbedAllowedOriginSchema).min(1).max(20)
3751
+ }),
3752
+ z.object({
3753
+ mode: z.literal("top-level-only"),
3754
+ allowedOrigins: z.array(EmbedAllowedOriginSchema).max(0).optional()
3755
+ })
3756
+ ]).transform((policy) => ({
3757
+ mode: policy.mode,
3758
+ allowedOrigins: [...new Set(policy.allowedOrigins ?? [])]
3759
+ }));
3760
+ const EmbedFramePolicyVOSchema = z.object({
3761
+ mode: EmbedFrameModeSchema,
3762
+ allowedOrigins: z.array(z.string().url())
3763
+ }).superRefine((policy, ctx) => {
3764
+ if (!(policy.mode === "origins" ? policy.allowedOrigins.length > 0 : policy.allowedOrigins.length === 0)) ctx.addIssue({
3765
+ code: "custom",
3766
+ message: "Stored frame policy is invalid"
3767
+ });
3768
+ });
3769
+ const CreateEmbedLinkInputSchema = z.object({
3770
+ type: EmbedTargetTypeSchema,
3771
+ typeId: z.string().min(1),
3772
+ expiresInMinutes: z.number().int().min(1).max(EMBED_LINK_MAX_MINUTES).optional().default(15),
3773
+ framePolicy: EmbedFramePolicyInputSchema.optional().default({
3774
+ mode: "anywhere",
3775
+ allowedOrigins: []
3776
+ })
3777
+ });
3778
+ const ListEmbedLinksInputSchema = z.object({
3779
+ type: EmbedTargetTypeSchema.optional(),
3780
+ typeId: z.string().min(1).optional()
3781
+ }).optional().default({});
3782
+ const RevokeEmbedLinkInputSchema = z.object({ id: z.string().min(1) });
3783
+ const EmbedLinkVOSchema = z.object({
3784
+ id: z.string(),
3785
+ type: EmbedTargetTypeSchema,
3786
+ typeId: z.string(),
3787
+ targetName: z.string(),
3788
+ nodeType: EmbedNodeTypeSchema.nullable(),
3789
+ createdAt: z.string().datetime(),
3790
+ expiresAt: z.string().datetime(),
3791
+ revokedAt: z.string().datetime().nullable(),
3792
+ active: z.boolean(),
3793
+ framePolicy: EmbedFramePolicyVOSchema
3794
+ });
3795
+ const CreatedEmbedLinkVOSchema = EmbedLinkVOSchema.extend({
3796
+ url: z.string().url(),
3797
+ iframeUrl: z.string().url()
3798
+ });
3799
+ const RevokeEmbedLinkVOSchema = z.object({ revoked: z.literal(true) });
3674
3800
  //#endregion
3675
3801
  //#region ../../packages/busabase-contract/src/contract/grep-schemas.ts
3676
3802
  /**
@@ -4134,6 +4260,29 @@ const changeRequestBatchFailureSchema = z.object({
4134
4260
  code: z.string().optional(),
4135
4261
  data: z.unknown().optional()
4136
4262
  });
4263
+ const embedLinkErrorResponseSchema = z.object({ error: z.string() });
4264
+ const embedLinkErrors = {
4265
+ BAD_REQUEST: {
4266
+ status: 400,
4267
+ message: "Bad Request",
4268
+ data: embedLinkErrorResponseSchema
4269
+ },
4270
+ UNAUTHORIZED: {
4271
+ status: 401,
4272
+ message: "Unauthorized",
4273
+ data: embedLinkErrorResponseSchema
4274
+ },
4275
+ FORBIDDEN: {
4276
+ status: 403,
4277
+ message: "Forbidden",
4278
+ data: embedLinkErrorResponseSchema
4279
+ },
4280
+ NOT_FOUND: {
4281
+ status: 404,
4282
+ message: "Not Found",
4283
+ data: embedLinkErrorResponseSchema
4284
+ }
4285
+ };
4137
4286
  const changeRequestReviewBatchResultSchema = z.object({ results: z.array(z.discriminatedUnion("ok", [z.object({
4138
4287
  changeRequestId: z.string(),
4139
4288
  ok: z.literal(true),
@@ -4170,6 +4319,29 @@ const busabaseContractRoutes = {
4170
4319
  summary: "Search files, Docs, and Base records with one pattern (unified grep)",
4171
4320
  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
4321
  }).input(UnifiedGrepInputSchema).output(UnifiedGrepResultVOSchema),
4322
+ embedLinks: {
4323
+ create: oc.route({
4324
+ method: "POST",
4325
+ path: "/embed-links",
4326
+ tags: ["Embed Links"],
4327
+ summary: "Create a polymorphic read-only embed link",
4328
+ successDescription: "The capability URL is returned once; only its secret hash is stored."
4329
+ }).errors(embedLinkErrors).input(CreateEmbedLinkInputSchema).output(CreatedEmbedLinkVOSchema),
4330
+ list: oc.route({
4331
+ method: "GET",
4332
+ path: "/embed-links",
4333
+ tags: ["Embed Links"],
4334
+ summary: "List embed links the caller can manage",
4335
+ successDescription: "Embed link metadata without capability secrets."
4336
+ }).errors(embedLinkErrors).input(ListEmbedLinksInputSchema).output(z.array(EmbedLinkVOSchema)),
4337
+ revoke: oc.route({
4338
+ method: "DELETE",
4339
+ path: "/embed-links/{id}",
4340
+ tags: ["Embed Links"],
4341
+ summary: "Revoke an embed link",
4342
+ successDescription: "The capability stops resolving immediately."
4343
+ }).errors(embedLinkErrors).input(RevokeEmbedLinkInputSchema).output(RevokeEmbedLinkVOSchema)
4344
+ },
4173
4345
  nodes: {
4174
4346
  list: oc.route({
4175
4347
  method: "GET",
@@ -4435,16 +4607,16 @@ const busabaseContractRoutes = {
4435
4607
  path: "/change-requests",
4436
4608
  tags: ["Change Requests"],
4437
4609
  summary: "List change requests",
4438
- successDescription: "A page of change requests plus an opaque nextCursor (null at the end). Filter with `status` and/or `mine`."
4610
+ successDescription: "A page of change requests plus an opaque nextCursor (null at the end). Filter with `status`, `mine`, and/or `affectsNodeId`."
4439
4611
  }).input(listChangeRequestsPagedInputSchema).output(listChangeRequestsResponseSchema),
4440
4612
  listPage: oc.route({
4441
4613
  method: "GET",
4442
4614
  path: "/change-requests/page",
4443
4615
  tags: ["Change Requests"],
4444
4616
  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` / `mine` filters as the cursor listing."
4617
+ 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
4618
  }).input(listChangeRequestsPageInputSchema).output(listChangeRequestsPageResponseSchema),
4447
- inboxSnapshot: oc.input(listChangeRequestsPageInputSchema).output(inboxSnapshotResponseSchema),
4619
+ inboxSnapshot: oc.input(inboxSnapshotInputSchema).output(inboxSnapshotResponseSchema),
4448
4620
  counts: oc.route({
4449
4621
  method: "GET",
4450
4622
  path: "/change-requests/counts",
@@ -4495,94 +4667,6 @@ const busabaseContractRoutes = {
4495
4667
  views: viewContract
4496
4668
  };
4497
4669
  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
4670
  //#endregion
4587
4671
  //#region ../../packages/busabase-contract/src/contract/cloud.ts
4588
4672
  /**
@@ -4638,25 +4722,7 @@ const notFoundErrors = { NOT_FOUND: {
4638
4722
  message: "Not Found",
4639
4723
  data: ErrorResponseSchema
4640
4724
  } };
4641
- const embedLinksErrors = {
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;
4725
+ const { embedLinks: _embedLinksAlreadyPublishedAtRoot, vault: _localVault, ...cloudWorkbenchRoutes } = busabaseContractRoutes;
4660
4726
  const cloudExtraRoutes = {
4661
4727
  system: {
4662
4728
  health: oc.route({
@@ -4721,32 +4787,7 @@ const cloudExtraRoutes = {
4721
4787
  ...notFoundErrors
4722
4788
  }).input(z.object({ params: z.object({ id: z.string() }) })).output(AgentTaskDetailSchema)
4723
4789
  },
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
- }
4790
+ embedLinks: busabaseContractRoutes.embedLinks
4750
4791
  };
4751
4792
  const cloudContract = oc.prefix("/api/v1").router({
4752
4793
  ...cloudWorkbenchRoutes,
@@ -4775,6 +4816,7 @@ function resolveConfig(config = {}) {
4775
4816
  webUrl: normalizeBaseUrl(config.webUrl ?? env("BUSABASE_WEB_URL") ?? baseUrl),
4776
4817
  apiKey: config.apiKey ?? env("BUSABASE_API_KEY"),
4777
4818
  spaceId: config.spaceId ?? env("BUSABASE_SPACE_ID"),
4819
+ sourceChannel: config.sourceChannel ?? "sdk",
4778
4820
  headers: config.headers,
4779
4821
  fetch: config.fetch
4780
4822
  };
@@ -4845,6 +4887,7 @@ function createBusabaseClient(config = {}) {
4845
4887
  return {
4846
4888
  ...resolved.apiKey ? { authorization: `Bearer ${resolved.apiKey}` } : {},
4847
4889
  ...resolved.spaceId ? { "x-busabase-space": resolved.spaceId } : {},
4890
+ "x-busabase-channel": resolved.sourceChannel ?? "sdk",
4848
4891
  ...extra
4849
4892
  };
4850
4893
  }
@@ -5031,7 +5074,7 @@ var Busabase = class {
5031
5074
  * This is the *authenticated*, durable link: it never expires, but the reader
5032
5075
  * needs a session unless the node has public sharing enabled. For a no-login
5033
5076
  * link, mint a Cloud embed link instead —
5034
- * `bb.embedLinks.create({ nodeId })` returns `{ url, iframeUrl }`.
5077
+ * `bb.embedLinks.create({ type: "node", typeId: nodeId })` returns `{ url, iframeUrl }`.
5035
5078
  *
5036
5079
  * @example
5037
5080
  * ```ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "busabase-sdk",
3
- "version": "0.19.2",
3
+ "version": "0.20.0",
4
4
  "description": "Typed TypeScript/JavaScript SDK for the Busabase OpenAPI REST API. Talks to a local or remote `busabase server` (or Busabase Cloud).",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/busabase/busabase/tree/main/apps/busabase-sdk",
@@ -63,9 +63,9 @@
63
63
  "tsx": "^4.20.5",
64
64
  "typescript": "^7.0.2",
65
65
  "vitest": "^4.1.11",
66
- "busabase-contract": "0.19.2",
67
- "openlib": "0.1.1",
68
- "open-domains": "0.0.2"
66
+ "busabase-contract": "0.20.0",
67
+ "open-domains": "0.0.2",
68
+ "openlib": "0.1.1"
69
69
  },
70
70
  "engines": {
71
71
  "node": ">=24.18.0"