busabase-sdk 0.9.13 → 0.9.15

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 +2210 -73
  2. package/dist/index.js +213 -29
  3. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -44,8 +44,12 @@ var fieldTypeSchema = z.enum([
44
44
  "ai_tags",
45
45
  "code",
46
46
  "json",
47
- "yaml"
47
+ "yaml",
48
+ "formula",
49
+ "lookup",
50
+ "whiteboard"
48
51
  ]);
52
+ var lookupRollupSchema = z.enum(["values", "count", "sum", "average", "min", "max", "concatenate"]).default("values");
49
53
  var fieldOptionsSchema = z.object({
50
54
  ai: z.object({
51
55
  model: z.string().optional(),
@@ -75,7 +79,26 @@ var fieldOptionsSchema = z.object({
75
79
  height: z.number().int().positive().max(1200).optional(),
76
80
  providers: z.array(z.string()).optional()
77
81
  }).optional(),
82
+ // `formula` fields are server-computed (like the other computed types) from
83
+ // `expression` at record write time — see packages/busabase-core's
84
+ // domains/base/formula/ engine. `{slug}` references a sibling field, including
85
+ // another `formula` field (chained formulas) — a dependency graph orders
86
+ // computation and rejects cycles at field create/edit time.
87
+ formula: z.object({
88
+ expression: z.string().min(1)
89
+ }).optional(),
78
90
  inverseFieldId: z.string().optional(),
91
+ // `lookup` fields pull a field's values across a `relation` field on the same
92
+ // Base, optionally rolling them up into one scalar. Unlike every other computed
93
+ // type they are NOT stored on the commit: a lookup's value depends on OTHER
94
+ // records, which can change without this record ever being written, so it is
95
+ // resolved at read time (see busabase-core's domains/base/logic/lookup-values.ts).
96
+ lookup: z.object({
97
+ relationFieldSlug: z.string().min(1).describe("Slug of a `relation` field on THIS Base \u2014 the hop to follow."),
98
+ targetFieldSlug: z.string().min(1).describe("Slug of the field on the related Base whose values are pulled over."),
99
+ rollup: lookupRollupSchema.optional(),
100
+ limit: z.enum(["all", "first"]).optional().describe("`first` looks at only the first linked record; default `all`.")
101
+ }).optional(),
79
102
  multiple: z.boolean().optional(),
80
103
  // Display formatting for `number` columns (Notion-style: one number type,
81
104
  // a format option). `currency` renders via Intl.NumberFormat.
@@ -128,11 +151,11 @@ var createBaseInputSchema = z.object({
128
151
  options: fieldOptionsSchema.optional().default({})
129
152
  })
130
153
  ).default([]),
131
- // Review-first by default: without `autoMerge: true`, this proposes the Base
132
- // as a pending ChangeRequest (status "in_review") instead of creating it
133
- // immediately. Pass `autoMerge: true` only for callers that don't need human
134
- // review (seed/migration scripts, an explicit no-review agent task).
135
- autoMerge: z.boolean().optional().default(false)
154
+ // Permission-aware default: omitted merges immediately if the actor has
155
+ // write access on the parent node, otherwise falls back to a pending
156
+ // ChangeRequest (status "in_review"). Pass explicit `autoMerge: false` to
157
+ // force review even with write access.
158
+ autoMerge: z.boolean().optional()
136
159
  });
137
160
  var createBaseFieldInputSchema = z.object({
138
161
  name: fieldNameSchema,
@@ -354,6 +377,15 @@ var folderNodeType = {
354
377
  operations: []
355
378
  };
356
379
 
380
+ // ../../packages/busabase-contract/src/domains/form/definition.ts
381
+ var formNodeType = {
382
+ type: "form",
383
+ label: "Form",
384
+ icon: "clipboard-list",
385
+ capabilities: { hasDetail: true, creatable: true },
386
+ operations: []
387
+ };
388
+
357
389
  // ../../packages/busabase-contract/src/domains/html/definition.ts
358
390
  var htmlNodeType = {
359
391
  type: "html",
@@ -415,6 +447,7 @@ var BUILTIN_NODE_TYPES = [
415
447
  airappNodeType,
416
448
  fileNodeType,
417
449
  docNodeType,
450
+ formNodeType,
418
451
  whiteboardNodeType,
419
452
  workflowNodeType,
420
453
  htmlNodeType
@@ -476,6 +509,15 @@ var nodePrincipalSchema = z.object({
476
509
  createdAt: z.string(),
477
510
  updatedAt: z.string()
478
511
  });
512
+ var nodeShareSchema = z.object({
513
+ nodeId: z.string(),
514
+ scope: z.enum(["none", "public"]),
515
+ capability: z.enum(["read", "submit"]),
516
+ // Derived from `passwordHash != null` — the hash itself is never serialized.
517
+ hasPassword: z.boolean(),
518
+ expiresAt: z.string().nullable(),
519
+ updatedAt: z.string()
520
+ });
479
521
  var listNodesInputSchema = z.object({
480
522
  parentId: z.string().nullable().optional().describe("Node to start from. Omit or null to start from the space root."),
481
523
  depth: z.coerce.number().int().min(1).max(5).optional().describe(
@@ -762,8 +804,8 @@ var createNodeChangeRequestInputSchema = z.object({
762
804
  'Explanation shown to the human reviewer. Write a conventional-commit style subject \u2014 imperative verb + what + why, e.g. "Reorganize marketing docs under a Campaigns folder".'
763
805
  ),
764
806
  submittedBy: z.string().optional().default("local-producer"),
765
- autoMerge: z.boolean().optional().default(false).describe(
766
- "Whether to approve and merge this structural node change immediately. Defaults to false so node Change Request creation is review-first unless explicitly requested."
807
+ autoMerge: z.boolean().optional().describe(
808
+ "Whether to approve and merge this structural node change immediately. Omitted defaults to merging immediately if the actor has write access on every target node, otherwise falling back to a pending Change Request; pass explicit false to force review even with write access."
767
809
  ),
768
810
  operations: z.array(nodeOperationInputSchema).min(1)
769
811
  });
@@ -936,11 +978,11 @@ var createFileTreeInputSchema = z.object({
936
978
  visibility: z.enum(["private", "workspace", "public"]).optional().default("private"),
937
979
  version: z.string().optional().default("0.1.0"),
938
980
  files: z.array(z.union([assetFileInputSchema, textFileInputSchema])).optional().default([]),
939
- // Review-first by default: without `autoMerge: true`, this proposes the node
940
- // as a pending ChangeRequest (status "in_review") instead of creating it
941
- // immediately. Pass `autoMerge: true` only for callers that don't need human
942
- // review (seed/migration scripts, an explicit no-review agent task).
943
- autoMerge: z.boolean().optional().default(false),
981
+ // Permission-aware default: omitted merges immediately if the actor has
982
+ // write access on the parent node, otherwise falls back to a pending
983
+ // ChangeRequest (status "in_review"). Pass explicit `autoMerge: false` to
984
+ // force review even with write access.
985
+ autoMerge: z.boolean().optional(),
944
986
  // "merge" (default): `files` is layered on top of the config's default seed
945
987
  // files by path — a caller supplying just a couple of extra files (e.g. a
946
988
  // Skill's own reference doc) still gets the default scaffold (SKILL.md,
@@ -1540,12 +1582,14 @@ var createChangeRequestInputSchema = z.object({
1540
1582
  idempotencyKey: z.string().optional().describe(
1541
1583
  "Optional client-supplied key that dedupes retries. Scoped per base + submitter: calling this endpoint again with the SAME idempotencyKey (e.g. after a timeout or a 5xx where you couldn't tell if the first call succeeded) returns the change request created by the first call instead of creating a duplicate. Omit for normal one-shot calls; only set it when you might retry."
1542
1584
  ),
1543
- // Review-first by default: without `autoMerge: true`, this proposes the record
1544
- // as a pending ChangeRequest (status "in_review") instead of creating it
1545
- // immediately. Pass `autoMerge: true` only for callers that don't need human
1546
- // review approves and merges the change request right away, returning the
1547
- // materialized record instead of the pending ChangeRequest.
1548
- autoMerge: z.boolean().optional().default(false)
1585
+ // Permission-aware default: omitted merges immediately if the actor has
1586
+ // write access on the Base's node, otherwise falls back to a pending
1587
+ // ChangeRequest (status "in_review"). Pass explicit `autoMerge: false` to
1588
+ // force review even with write access; `autoMerge: true` approves and
1589
+ // merges right away, returning the materialized record instead of the
1590
+ // pending ChangeRequest (gracefully falls back to a pending CR if the
1591
+ // actor doesn't actually have write access).
1592
+ autoMerge: z.boolean().optional()
1549
1593
  });
1550
1594
  var createBulkChangeRequestInputSchema = z.object({
1551
1595
  records: z.array(z.record(z.string(), z.unknown())).min(1).max(1e3).describe(
@@ -1565,6 +1609,11 @@ var recordFieldFilterInputSchema = z.object({
1565
1609
  valueText: z.string().min(1),
1566
1610
  limit: z.coerce.number().int().min(1).max(100).optional().default(50)
1567
1611
  });
1612
+ var recordFieldGetInputSchema = z.object({
1613
+ baseId: z.string(),
1614
+ fieldSlug: z.string().min(1),
1615
+ valueText: z.string().min(1)
1616
+ });
1568
1617
  var restoreRecordInputSchema = z.object({
1569
1618
  message: z.string().optional(),
1570
1619
  submittedBy: z.string().optional().default("local-editor")
@@ -1784,6 +1833,13 @@ var recordContract = {
1784
1833
  summary: "Filter records by field text",
1785
1834
  successDescription: "Canonical records matching a field text filter."
1786
1835
  }).input(recordFieldFilterInputSchema).output(z.array(recordSchema)),
1836
+ getByField: oc.route({
1837
+ method: "GET",
1838
+ path: "/records/by-field",
1839
+ tags: ["Records"],
1840
+ summary: "Get record by field value",
1841
+ successDescription: "Single canonical record whose field value exactly matches, or null when none does \u2014 a scoped point lookup (e.g. by a unique slug or path field), not a list."
1842
+ }).input(recordFieldGetInputSchema).output(recordSchema.nullable()),
1787
1843
  updateChangeRequest: oc.route({
1788
1844
  method: "PUT",
1789
1845
  path: "/records/{recordId}/change-requests",
@@ -1863,11 +1919,11 @@ var createDocInputSchema = z.object({
1863
1919
  name: z.string().min(1),
1864
1920
  description: z.string().optional().default(""),
1865
1921
  body: z.string().optional().default(""),
1866
- // Review-first by default: without `autoMerge: true`, this proposes the Doc
1867
- // as a pending ChangeRequest (status "in_review") instead of creating it
1868
- // immediately. Pass `autoMerge: true` only for callers that don't need human
1869
- // review (seed/migration scripts, an explicit no-review agent task).
1870
- autoMerge: z.boolean().optional().default(false)
1922
+ // Permission-aware default: omitted merges immediately if the actor has
1923
+ // write access on the parent node, otherwise falls back to a pending
1924
+ // ChangeRequest (status "in_review"). Pass explicit `autoMerge: false` to
1925
+ // force review even with write access.
1926
+ autoMerge: z.boolean().optional()
1871
1927
  });
1872
1928
  var updateDocInputSchema = z.object({
1873
1929
  body: z.string()
@@ -2073,11 +2129,11 @@ var createFileNodeInputSchema = z.object({
2073
2129
  name: z.string().min(1),
2074
2130
  description: z.string().optional().default(""),
2075
2131
  assetId: z.string().min(1),
2076
- // Review-first by default: without `autoMerge: true`, this proposes the File
2077
- // node as a pending ChangeRequest (status "in_review") instead of creating it
2078
- // immediately. Pass `autoMerge: true` only for callers that don't need human
2079
- // review (seed/migration scripts, an explicit no-review agent task).
2080
- autoMerge: z.boolean().optional().default(false)
2132
+ // Permission-aware default: omitted merges immediately if the actor has
2133
+ // write access on the parent node, otherwise falls back to a pending
2134
+ // ChangeRequest (status "in_review"). Pass explicit `autoMerge: false` to
2135
+ // force review even with write access.
2136
+ autoMerge: z.boolean().optional()
2081
2137
  });
2082
2138
  var fileContract = {
2083
2139
  list: oc.route({
@@ -2127,6 +2183,102 @@ var folderContract = {
2127
2183
  successDescription: "Folder node and its direct children."
2128
2184
  }).input(z.object({ nodeId: z.string() })).output(folderSchema)
2129
2185
  };
2186
+ var FormFieldBindingSchema = z.object({
2187
+ inputName: z.string().min(1),
2188
+ fieldSlug: z.string().min(1),
2189
+ required: z.boolean().optional(),
2190
+ label: z.string().optional(),
2191
+ help: z.string().optional()
2192
+ });
2193
+ var FormThemeSchema = z.object({
2194
+ logoUrl: z.string().optional(),
2195
+ coverUrl: z.string().optional(),
2196
+ brandColor: z.string().optional(),
2197
+ hideBranding: z.boolean().optional()
2198
+ });
2199
+ var FormPageSourceSchema = z.object({
2200
+ code: z.string().optional(),
2201
+ theme: FormThemeSchema.optional()
2202
+ });
2203
+ var FormShareSchema = z.object({
2204
+ isPublic: z.boolean().default(false),
2205
+ anonymousSubmit: z.boolean().default(false),
2206
+ submitLimit: z.number().int().positive().optional(),
2207
+ requireCaptcha: z.boolean().optional()
2208
+ });
2209
+ var FormVOSchema = z.object({
2210
+ id: z.string(),
2211
+ nodeId: z.string(),
2212
+ spaceId: z.string(),
2213
+ targetBaseId: z.string(),
2214
+ name: z.string(),
2215
+ description: z.string(),
2216
+ bindings: z.array(FormFieldBindingSchema),
2217
+ page: FormPageSourceSchema,
2218
+ share: FormShareSchema,
2219
+ /** Accepted submissions so far — backs server-side `share.submitLimit`. */
2220
+ submissionCount: z.number().int().nonnegative().default(0),
2221
+ status: z.enum(["active", "archived"]),
2222
+ createdBy: z.string(),
2223
+ createdAt: z.string(),
2224
+ updatedAt: z.string()
2225
+ });
2226
+ var CreateFormInputSchema = z.object({
2227
+ nodeId: z.string().min(1),
2228
+ targetBaseId: z.string().min(1),
2229
+ name: z.string().min(1),
2230
+ description: z.string().optional().default(""),
2231
+ bindings: z.array(FormFieldBindingSchema).optional().default([]),
2232
+ page: FormPageSourceSchema.optional().default({}),
2233
+ share: FormShareSchema.optional().default({ isPublic: false, anonymousSubmit: false })
2234
+ });
2235
+ var UpdateFormInputSchema = z.object({
2236
+ name: z.string().min(1).optional(),
2237
+ description: z.string().optional(),
2238
+ bindings: z.array(FormFieldBindingSchema).optional(),
2239
+ page: FormPageSourceSchema.optional(),
2240
+ share: FormShareSchema.optional()
2241
+ });
2242
+ var SubmitFormInputSchema = z.object({
2243
+ values: z.record(z.string(), z.unknown()),
2244
+ captchaToken: z.string().optional()
2245
+ });
2246
+ var FormSubmitResultSchema = z.object({
2247
+ changeRequestId: z.string(),
2248
+ status: z.literal("pending_review")
2249
+ });
2250
+
2251
+ // ../../packages/busabase-contract/src/domains/form/contract.ts
2252
+ var formContract = {
2253
+ getByNode: oc.route({
2254
+ method: "GET",
2255
+ path: "/forms/{nodeId}",
2256
+ tags: ["Forms"],
2257
+ summary: "Get a form by its node id",
2258
+ successDescription: "The form bound to this node, or 404."
2259
+ }).input(z.object({ nodeId: z.string() })).output(FormVOSchema),
2260
+ create: oc.route({
2261
+ method: "POST",
2262
+ path: "/forms",
2263
+ tags: ["Forms"],
2264
+ summary: "Create a form bound to a Base",
2265
+ successDescription: "The created form."
2266
+ }).input(CreateFormInputSchema).output(FormVOSchema),
2267
+ update: oc.route({
2268
+ method: "PUT",
2269
+ path: "/forms/{nodeId}",
2270
+ tags: ["Forms"],
2271
+ summary: "Update a form's config (owner-managed, not a change request)",
2272
+ successDescription: "The updated form."
2273
+ }).input(UpdateFormInputSchema.extend({ nodeId: z.string() })).output(FormVOSchema),
2274
+ submit: oc.route({
2275
+ method: "POST",
2276
+ path: "/forms/{nodeId}/submit",
2277
+ tags: ["Forms"],
2278
+ summary: "Submit a filled-in form",
2279
+ successDescription: "Creates an approval-first record-create ChangeRequest on the target Base."
2280
+ }).input(SubmitFormInputSchema.extend({ nodeId: z.string() })).output(FormSubmitResultSchema)
2281
+ };
2130
2282
  var InstallPlanNodeTypeSchema = z.enum([
2131
2283
  "folder",
2132
2284
  "doc",
@@ -2824,6 +2976,37 @@ var busabaseContractRoutes = {
2824
2976
  principalId: z.string().min(1)
2825
2977
  })
2826
2978
  ).output(z.object({ removed: z.boolean() }))
2979
+ },
2980
+ share: {
2981
+ get: oc.route({
2982
+ method: "GET",
2983
+ path: "/nodes/{nodeId}/share",
2984
+ tags: ["Nodes", "Sharing"],
2985
+ summary: "Read a node's public link-sharing settings",
2986
+ successDescription: "The node's public-share settings, or null when the node was never shared. The stored password is never returned \u2014 only a `hasPassword` flag."
2987
+ }).input(z.object({ nodeId: z.string() })).output(nodeShareSchema.nullable()),
2988
+ set: oc.route({
2989
+ method: "POST",
2990
+ path: "/nodes/{nodeId}/share",
2991
+ tags: ["Nodes", "Sharing"],
2992
+ summary: "Enable or update a node's public link sharing",
2993
+ successDescription: "Turned public sharing on (or updated its capability/password/expiry) and re-materialized the effective public scope down the subtree. Requires `manage` level on the node."
2994
+ }).input(
2995
+ z.object({
2996
+ nodeId: z.string(),
2997
+ scope: z.enum(["none", "public"]),
2998
+ capability: z.enum(["read", "submit"]).optional(),
2999
+ password: z.string().nullable().optional(),
3000
+ expiresAt: z.string().datetime().nullable().optional()
3001
+ })
3002
+ ).output(nodeShareSchema.nullable()),
3003
+ disable: oc.route({
3004
+ method: "DELETE",
3005
+ path: "/nodes/{nodeId}/share",
3006
+ tags: ["Nodes", "Sharing"],
3007
+ summary: "Revoke a node's public link sharing",
3008
+ successDescription: "Flipped the share scope to none in place (the link is kept so re-enabling produces the same URL). Requires `manage` level on the node."
3009
+ }).input(z.object({ nodeId: z.string() })).output(nodeShareSchema.nullable())
2827
3010
  }
2828
3011
  },
2829
3012
  auditEvents: {
@@ -2888,6 +3071,7 @@ var busabaseContractRoutes = {
2888
3071
  files: fileContract,
2889
3072
  docs: docContract,
2890
3073
  folders: folderContract,
3074
+ forms: formContract,
2891
3075
  assets: assetsContract,
2892
3076
  vault: vaultContract,
2893
3077
  webhooks: webhookContract,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "busabase-sdk",
3
- "version": "0.9.13",
3
+ "version": "0.9.15",
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",
@@ -42,8 +42,8 @@
42
42
  "typescript": "^5.9.3",
43
43
  "vitest": "^2.1.8",
44
44
  "open-domains": "0.0.2",
45
- "openlib": "0.1.1",
46
- "busabase-contract": "0.9.13"
45
+ "busabase-contract": "0.9.15",
46
+ "openlib": "0.1.1"
47
47
  },
48
48
  "engines": {
49
49
  "node": ">=24.18.0"