busabase-sdk 0.41.0 → 0.50.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.d.ts +1 -1
- package/dist/airapp.js +1 -134
- package/dist/{client-vnydDLvt.d.ts → client-EYjDfri3.d.ts} +118 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +223 -107
- package/dist/template-C5oO6Au_.js +147 -0
- package/package.json +4 -4
package/dist/airapp.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as BusabaseClient } from "./client-
|
|
1
|
+
import { t as BusabaseClient } from "./client-EYjDfri3.js";
|
|
2
2
|
//#region src/airapp.d.ts
|
|
3
3
|
type NodeChangeRequestInput = Parameters<BusabaseClient["nodes"]["createChangeRequest"]>[0];
|
|
4
4
|
type NodeOperationInput = NodeChangeRequestInput["operations"][number];
|
package/dist/airapp.js
CHANGED
|
@@ -1,137 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
//#region ../../packages/busabase-contract/src/domains/skill/frontmatter.ts
|
|
3
|
-
/**
|
|
4
|
-
* `SKILL.md` frontmatter — the generic shape, independent of Busabase.
|
|
5
|
-
*
|
|
6
|
-
* This used to live inside `domains/package/template.ts`, which encoded an
|
|
7
|
-
* assumption that no longer holds: that a Skill is a *part of* a template. Most
|
|
8
|
-
* Skills are not. A Skill is a directory with a `SKILL.md` an agent reads; it
|
|
9
|
-
* needs no `busabase.json`, ships no `content/`, and never installs into a
|
|
10
|
-
* workspace. Busabase's own `busabase-app-creator` is one.
|
|
11
|
-
*
|
|
12
|
-
* Modelling it only as a template component meant there was nowhere to hang
|
|
13
|
-
* checks for a plain Skill, so there were none. Hence its own file, in the
|
|
14
|
-
* domain it belongs to.
|
|
15
|
-
*
|
|
16
|
-
* `metadata` is deliberately open: a Skill carries whatever its ecosystem
|
|
17
|
-
* defines (categories, tags, risk labels, per-agent hints). The Busabase-specific
|
|
18
|
-
* block that decides template-ness is layered on in `domains/package/template.ts`
|
|
19
|
-
* — the template format knows about Skills, not the other way round.
|
|
20
|
-
*/
|
|
21
|
-
const SkillFrontmatterSchema$1 = z.object({
|
|
22
|
-
/** Identity. For a Skill inside a package this must equal the package name. */
|
|
23
|
-
name: z.string().min(1),
|
|
24
|
-
/**
|
|
25
|
-
* How an agent decides whether to reach for this Skill at all — so an empty one
|
|
26
|
-
* is not a cosmetic omission, it is a Skill that never gets picked.
|
|
27
|
-
*/
|
|
28
|
-
description: z.string().default(""),
|
|
29
|
-
metadata: z.object({}).passthrough().optional()
|
|
30
|
-
});
|
|
31
|
-
const TemplateAirAppRefSchema = z.object({
|
|
32
|
-
/** Slug of the `content/<dir>` holding the AirApp. */
|
|
33
|
-
slug: z.string().min(1),
|
|
34
|
-
role: z.enum([
|
|
35
|
-
"primary",
|
|
36
|
-
"admin",
|
|
37
|
-
"public",
|
|
38
|
-
"tool"
|
|
39
|
-
]),
|
|
40
|
-
label: z.string().optional()
|
|
41
|
-
});
|
|
42
|
-
/**
|
|
43
|
-
* Secrets the app expects to find in the Vault.
|
|
44
|
-
*
|
|
45
|
-
* DECLARED, never created: the package format has no slot for secret values and
|
|
46
|
-
* must not grow one (the same "you cannot leak what the format cannot express"
|
|
47
|
-
* rule the whole format is built on). Install surfaces these as a post-install
|
|
48
|
-
* prompt; the user fills them in the Vault themselves.
|
|
49
|
-
*/
|
|
50
|
-
const TemplateSecretSchema = z.object({
|
|
51
|
-
key: z.string().min(1),
|
|
52
|
-
description: z.string().default(""),
|
|
53
|
-
required: z.boolean().default(true)
|
|
54
|
-
});
|
|
55
|
-
z.object({
|
|
56
|
-
/** Template Center category, e.g. `"crm"`, `"email"`, `"content"`. */
|
|
57
|
-
category: z.string().min(1),
|
|
58
|
-
tags: z.array(z.string()).default([]),
|
|
59
|
-
/** Card/detail screenshots, package-relative (`assets/screenshots/overview.webp`). */
|
|
60
|
-
screenshots: z.array(z.string()).default([]),
|
|
61
|
-
/**
|
|
62
|
-
* Ready-made prompts shown after install ("Ask agent" prefills the first).
|
|
63
|
-
*
|
|
64
|
-
* They are the difference between a folder of tables and something a user can
|
|
65
|
-
* *use*: the point of a template is that the agent already knows the job, and
|
|
66
|
-
* these are how that is made visible rather than left for the user to guess.
|
|
67
|
-
*/
|
|
68
|
-
agentPrompts: z.array(z.string()).default([]),
|
|
69
|
-
/** Single-AirApp shorthand. Mutually exclusive with `airapps`. */
|
|
70
|
-
airapp: z.string().optional(),
|
|
71
|
-
/** Multi-AirApp form. Exactly one entry must have `role: "primary"`. */
|
|
72
|
-
airapps: z.array(TemplateAirAppRefSchema).optional(),
|
|
73
|
-
/**
|
|
74
|
-
* Bumped by the author when the declared resource shape changes.
|
|
75
|
-
*
|
|
76
|
-
* Part of the ownership stamp, so BOTH doors must agree on it: the installer
|
|
77
|
-
* writes it, and a skill's own `setup.mjs` compares against it to decide
|
|
78
|
-
* whether a node it finds is its own current shape or an older one to repair.
|
|
79
|
-
* Defaulted rather than required so an author who never versions their app
|
|
80
|
-
* still gets a stamp both sides recognise.
|
|
81
|
-
*/
|
|
82
|
-
schemaVersion: z.number().int().nonnegative().default(1),
|
|
83
|
-
vaultNamespace: z.string().optional(),
|
|
84
|
-
secrets: z.array(TemplateSecretSchema).default([]),
|
|
85
|
-
requires: z.object({ airapp: z.boolean().optional() }).default({})
|
|
86
|
-
});
|
|
87
|
-
/**
|
|
88
|
-
* `metadata.busabase` inside the root `SKILL.md`'s YAML frontmatter.
|
|
89
|
-
*
|
|
90
|
-
* `template: true` is an EXPLICIT opt-in, not an inference from "this skill
|
|
91
|
-
* happens to contain a package". Publishing a template means accepting that
|
|
92
|
-
* installers will run its AirApp code and feed its SKILL.md to their agent; that
|
|
93
|
-
* deserves a deliberate flag rather than a side effect of directory shape.
|
|
94
|
-
*/
|
|
95
|
-
const SkillBusabaseMetadataSchema = z.object({
|
|
96
|
-
template: z.boolean().default(false),
|
|
97
|
-
folderSlug: z.string().optional(),
|
|
98
|
-
/** Resource keys the manual talks about; each must exist under `content/`. */
|
|
99
|
-
resources: z.array(z.string()).default([]),
|
|
100
|
-
risk: z.string().optional()
|
|
101
|
-
});
|
|
102
|
-
SkillFrontmatterSchema$1.extend({ metadata: z.object({ busabase: SkillBusabaseMetadataSchema.optional() }).passthrough().optional() });
|
|
103
|
-
/** Stamp on every resource node (Base, Drive, AirApp, …) an app owns. */
|
|
104
|
-
const AppResourceOwnershipSchema = z.object({
|
|
105
|
-
appId: z.string().min(1),
|
|
106
|
-
/** Stable internal handle (`"contacts"`), NOT the installed slug. */
|
|
107
|
-
resourceKey: z.string().min(1),
|
|
108
|
-
schemaVersion: z.number().int().nonnegative()
|
|
109
|
-
});
|
|
110
|
-
/**
|
|
111
|
-
* The `resourceKey` reserved for an app's root Folder.
|
|
112
|
-
*
|
|
113
|
-
* `busabase-sdk` recognises an app's own Folder by looking for exactly this
|
|
114
|
-
* value (`ownsAppRoot`), so the installer must write it too — a Folder stamped
|
|
115
|
-
* with anything else reads as a stranger's, and the skill's own `setup.mjs`
|
|
116
|
-
* then refuses to touch its own workspace with `SETUP_CONFLICT`. Exported so
|
|
117
|
-
* neither side carries the string literal privately.
|
|
118
|
-
*/
|
|
119
|
-
const APP_ROOT_RESOURCE_KEY = "app-root";
|
|
120
|
-
AppResourceOwnershipSchema.extend({
|
|
121
|
-
resourceKey: z.literal(APP_ROOT_RESOURCE_KEY),
|
|
122
|
-
version: z.string().optional(),
|
|
123
|
-
source: z.object({
|
|
124
|
-
repo: z.string().optional(),
|
|
125
|
-
ref: z.string().optional(),
|
|
126
|
-
subdir: z.string().optional()
|
|
127
|
-
}).optional(),
|
|
128
|
-
installedAt: z.string().optional()
|
|
129
|
-
});
|
|
130
|
-
z.object({
|
|
131
|
-
appId: z.string().min(1),
|
|
132
|
-
["isTemplateSkill"]: z.literal(true)
|
|
133
|
-
});
|
|
134
|
-
//#endregion
|
|
1
|
+
import { t as APP_ROOT_RESOURCE_KEY } from "./template-C5oO6Au_.js";
|
|
135
2
|
//#region src/airapp.ts
|
|
136
3
|
/**
|
|
137
4
|
* AirApp resource provisioning — how an app claims (or creates) the Folder and
|
|
@@ -14926,6 +14926,7 @@ declare const cloudContract: {
|
|
|
14926
14926
|
"asset.uploaded": "asset.uploaded";
|
|
14927
14927
|
changes_requested: "changes_requested";
|
|
14928
14928
|
"record.created": "record.created";
|
|
14929
|
+
"record.updated": "record.updated";
|
|
14929
14930
|
}>;
|
|
14930
14931
|
enabled: z.ZodBoolean;
|
|
14931
14932
|
createdBy: z.ZodString;
|
|
@@ -14953,6 +14954,7 @@ declare const cloudContract: {
|
|
|
14953
14954
|
"asset.uploaded": "asset.uploaded";
|
|
14954
14955
|
changes_requested: "changes_requested";
|
|
14955
14956
|
"record.created": "record.created";
|
|
14957
|
+
"record.updated": "record.updated";
|
|
14956
14958
|
}>;
|
|
14957
14959
|
enabled: z.ZodBoolean;
|
|
14958
14960
|
createdBy: z.ZodString;
|
|
@@ -14980,6 +14982,7 @@ declare const cloudContract: {
|
|
|
14980
14982
|
"asset.uploaded": "asset.uploaded";
|
|
14981
14983
|
changes_requested: "changes_requested";
|
|
14982
14984
|
"record.created": "record.created";
|
|
14985
|
+
"record.updated": "record.updated";
|
|
14983
14986
|
}>;
|
|
14984
14987
|
enabled: z.ZodBoolean;
|
|
14985
14988
|
createdBy: z.ZodString;
|
|
@@ -15009,6 +15012,7 @@ declare const cloudContract: {
|
|
|
15009
15012
|
"asset.uploaded": "asset.uploaded";
|
|
15010
15013
|
changes_requested: "changes_requested";
|
|
15011
15014
|
"record.created": "record.created";
|
|
15015
|
+
"record.updated": "record.updated";
|
|
15012
15016
|
}>;
|
|
15013
15017
|
enabled: z.ZodBoolean;
|
|
15014
15018
|
createdBy: z.ZodString;
|
|
@@ -15036,6 +15040,7 @@ declare const cloudContract: {
|
|
|
15036
15040
|
"asset.uploaded": "asset.uploaded";
|
|
15037
15041
|
changes_requested: "changes_requested";
|
|
15038
15042
|
"record.created": "record.created";
|
|
15043
|
+
"record.updated": "record.updated";
|
|
15039
15044
|
}>;
|
|
15040
15045
|
enabled: z.ZodBoolean;
|
|
15041
15046
|
createdBy: z.ZodString;
|
|
@@ -15063,6 +15068,7 @@ declare const cloudContract: {
|
|
|
15063
15068
|
"asset.uploaded": "asset.uploaded";
|
|
15064
15069
|
changes_requested: "changes_requested";
|
|
15065
15070
|
"record.created": "record.created";
|
|
15071
|
+
"record.updated": "record.updated";
|
|
15066
15072
|
}>;
|
|
15067
15073
|
enabled: z.ZodBoolean;
|
|
15068
15074
|
createdBy: z.ZodString;
|
|
@@ -15087,6 +15093,7 @@ declare const cloudContract: {
|
|
|
15087
15093
|
"asset.uploaded": "asset.uploaded";
|
|
15088
15094
|
changes_requested: "changes_requested";
|
|
15089
15095
|
"record.created": "record.created";
|
|
15096
|
+
"record.updated": "record.updated";
|
|
15090
15097
|
}>;
|
|
15091
15098
|
baseId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
15092
15099
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -15103,6 +15110,7 @@ declare const cloudContract: {
|
|
|
15103
15110
|
"asset.uploaded": "asset.uploaded";
|
|
15104
15111
|
changes_requested: "changes_requested";
|
|
15105
15112
|
"record.created": "record.created";
|
|
15113
|
+
"record.updated": "record.updated";
|
|
15106
15114
|
}>;
|
|
15107
15115
|
baseId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
15108
15116
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -15119,6 +15127,7 @@ declare const cloudContract: {
|
|
|
15119
15127
|
"asset.uploaded": "asset.uploaded";
|
|
15120
15128
|
changes_requested: "changes_requested";
|
|
15121
15129
|
"record.created": "record.created";
|
|
15130
|
+
"record.updated": "record.updated";
|
|
15122
15131
|
}>;
|
|
15123
15132
|
baseId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
15124
15133
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -15137,6 +15146,7 @@ declare const cloudContract: {
|
|
|
15137
15146
|
"asset.uploaded": "asset.uploaded";
|
|
15138
15147
|
changes_requested: "changes_requested";
|
|
15139
15148
|
"record.created": "record.created";
|
|
15149
|
+
"record.updated": "record.updated";
|
|
15140
15150
|
}>;
|
|
15141
15151
|
enabled: z.ZodBoolean;
|
|
15142
15152
|
createdBy: z.ZodString;
|
|
@@ -15164,6 +15174,7 @@ declare const cloudContract: {
|
|
|
15164
15174
|
"asset.uploaded": "asset.uploaded";
|
|
15165
15175
|
changes_requested: "changes_requested";
|
|
15166
15176
|
"record.created": "record.created";
|
|
15177
|
+
"record.updated": "record.updated";
|
|
15167
15178
|
}>;
|
|
15168
15179
|
enabled: z.ZodBoolean;
|
|
15169
15180
|
createdBy: z.ZodString;
|
|
@@ -15191,6 +15202,7 @@ declare const cloudContract: {
|
|
|
15191
15202
|
"asset.uploaded": "asset.uploaded";
|
|
15192
15203
|
changes_requested: "changes_requested";
|
|
15193
15204
|
"record.created": "record.created";
|
|
15205
|
+
"record.updated": "record.updated";
|
|
15194
15206
|
}>;
|
|
15195
15207
|
enabled: z.ZodBoolean;
|
|
15196
15208
|
createdBy: z.ZodString;
|
|
@@ -15215,6 +15227,7 @@ declare const cloudContract: {
|
|
|
15215
15227
|
"asset.uploaded": "asset.uploaded";
|
|
15216
15228
|
changes_requested: "changes_requested";
|
|
15217
15229
|
"record.created": "record.created";
|
|
15230
|
+
"record.updated": "record.updated";
|
|
15218
15231
|
}>;
|
|
15219
15232
|
baseId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
15220
15233
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -15232,6 +15245,7 @@ declare const cloudContract: {
|
|
|
15232
15245
|
"asset.uploaded": "asset.uploaded";
|
|
15233
15246
|
changes_requested: "changes_requested";
|
|
15234
15247
|
"record.created": "record.created";
|
|
15248
|
+
"record.updated": "record.updated";
|
|
15235
15249
|
}>;
|
|
15236
15250
|
baseId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
15237
15251
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -15249,6 +15263,7 @@ declare const cloudContract: {
|
|
|
15249
15263
|
"asset.uploaded": "asset.uploaded";
|
|
15250
15264
|
changes_requested: "changes_requested";
|
|
15251
15265
|
"record.created": "record.created";
|
|
15266
|
+
"record.updated": "record.updated";
|
|
15252
15267
|
}>;
|
|
15253
15268
|
baseId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
15254
15269
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -15268,6 +15283,7 @@ declare const cloudContract: {
|
|
|
15268
15283
|
"asset.uploaded": "asset.uploaded";
|
|
15269
15284
|
changes_requested: "changes_requested";
|
|
15270
15285
|
"record.created": "record.created";
|
|
15286
|
+
"record.updated": "record.updated";
|
|
15271
15287
|
}>;
|
|
15272
15288
|
enabled: z.ZodBoolean;
|
|
15273
15289
|
createdBy: z.ZodString;
|
|
@@ -15295,6 +15311,7 @@ declare const cloudContract: {
|
|
|
15295
15311
|
"asset.uploaded": "asset.uploaded";
|
|
15296
15312
|
changes_requested: "changes_requested";
|
|
15297
15313
|
"record.created": "record.created";
|
|
15314
|
+
"record.updated": "record.updated";
|
|
15298
15315
|
}>;
|
|
15299
15316
|
enabled: z.ZodBoolean;
|
|
15300
15317
|
createdBy: z.ZodString;
|
|
@@ -15322,6 +15339,7 @@ declare const cloudContract: {
|
|
|
15322
15339
|
"asset.uploaded": "asset.uploaded";
|
|
15323
15340
|
changes_requested: "changes_requested";
|
|
15324
15341
|
"record.created": "record.created";
|
|
15342
|
+
"record.updated": "record.updated";
|
|
15325
15343
|
}>;
|
|
15326
15344
|
enabled: z.ZodBoolean;
|
|
15327
15345
|
createdBy: z.ZodString;
|
|
@@ -15355,6 +15373,7 @@ declare const cloudContract: {
|
|
|
15355
15373
|
"asset.uploaded": "asset.uploaded";
|
|
15356
15374
|
changes_requested: "changes_requested";
|
|
15357
15375
|
"record.created": "record.created";
|
|
15376
|
+
"record.updated": "record.updated";
|
|
15358
15377
|
}>;
|
|
15359
15378
|
status: z.ZodEnum<{
|
|
15360
15379
|
failed: "failed";
|
|
@@ -15376,6 +15395,7 @@ declare const cloudContract: {
|
|
|
15376
15395
|
"asset.uploaded": "asset.uploaded";
|
|
15377
15396
|
changes_requested: "changes_requested";
|
|
15378
15397
|
"record.created": "record.created";
|
|
15398
|
+
"record.updated": "record.updated";
|
|
15379
15399
|
}>;
|
|
15380
15400
|
status: z.ZodEnum<{
|
|
15381
15401
|
failed: "failed";
|
|
@@ -15571,6 +15591,12 @@ declare const cloudContract: {
|
|
|
15571
15591
|
name: z.ZodString;
|
|
15572
15592
|
description: z.ZodString;
|
|
15573
15593
|
category: z.ZodString;
|
|
15594
|
+
risk: z.ZodOptional<z.ZodEnum<{
|
|
15595
|
+
"gated-write": "gated-write";
|
|
15596
|
+
"local-write": "local-write";
|
|
15597
|
+
"read-only": "read-only";
|
|
15598
|
+
sandbox: "sandbox";
|
|
15599
|
+
}>>;
|
|
15574
15600
|
tags: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
15575
15601
|
screenshots: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
15576
15602
|
agentPrompts: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
@@ -19476,6 +19502,31 @@ declare const cloudContract: {
|
|
|
19476
19502
|
}>;
|
|
19477
19503
|
value: z.ZodOptional<z.ZodUnknown>;
|
|
19478
19504
|
}, z.core.$strip>>>;
|
|
19505
|
+
valueFilters: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
19506
|
+
fieldSlug: z.ZodString;
|
|
19507
|
+
operator: z.ZodEnum<{
|
|
19508
|
+
eq: "eq";
|
|
19509
|
+
gt: "gt";
|
|
19510
|
+
gte: "gte";
|
|
19511
|
+
lt: "lt";
|
|
19512
|
+
lte: "lte";
|
|
19513
|
+
ne: "ne";
|
|
19514
|
+
}>;
|
|
19515
|
+
value: z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodBoolean]>;
|
|
19516
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
19517
|
+
any: z.ZodArray<z.ZodObject<{
|
|
19518
|
+
fieldSlug: z.ZodString;
|
|
19519
|
+
operator: z.ZodEnum<{
|
|
19520
|
+
eq: "eq";
|
|
19521
|
+
gt: "gt";
|
|
19522
|
+
gte: "gte";
|
|
19523
|
+
lt: "lt";
|
|
19524
|
+
lte: "lte";
|
|
19525
|
+
ne: "ne";
|
|
19526
|
+
}>;
|
|
19527
|
+
value: z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodBoolean]>;
|
|
19528
|
+
}, z.core.$strip>>;
|
|
19529
|
+
}, z.core.$strip>]>>>;
|
|
19479
19530
|
sort: z.ZodOptional<z.ZodObject<{
|
|
19480
19531
|
fieldSlug: z.ZodString;
|
|
19481
19532
|
fieldType: z.ZodOptional<z.ZodString>;
|
|
@@ -19930,12 +19981,51 @@ declare const cloudContract: {
|
|
|
19930
19981
|
}>;
|
|
19931
19982
|
value: z.ZodOptional<z.ZodUnknown>;
|
|
19932
19983
|
}, z.core.$strip>>>;
|
|
19984
|
+
valueFilters: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
19985
|
+
fieldSlug: z.ZodString;
|
|
19986
|
+
operator: z.ZodEnum<{
|
|
19987
|
+
eq: "eq";
|
|
19988
|
+
gt: "gt";
|
|
19989
|
+
gte: "gte";
|
|
19990
|
+
lt: "lt";
|
|
19991
|
+
lte: "lte";
|
|
19992
|
+
ne: "ne";
|
|
19993
|
+
}>;
|
|
19994
|
+
value: z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodBoolean]>;
|
|
19995
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
19996
|
+
any: z.ZodArray<z.ZodObject<{
|
|
19997
|
+
fieldSlug: z.ZodString;
|
|
19998
|
+
operator: z.ZodEnum<{
|
|
19999
|
+
eq: "eq";
|
|
20000
|
+
gt: "gt";
|
|
20001
|
+
gte: "gte";
|
|
20002
|
+
lt: "lt";
|
|
20003
|
+
lte: "lte";
|
|
20004
|
+
ne: "ne";
|
|
20005
|
+
}>;
|
|
20006
|
+
value: z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodBoolean]>;
|
|
20007
|
+
}, z.core.$strip>>;
|
|
20008
|
+
}, z.core.$strip>]>>>;
|
|
19933
20009
|
}, z.core.$strip>>>, z.ZodObject<{
|
|
19934
20010
|
total: z.ZodNumber;
|
|
19935
20011
|
}, z.core.$strip>, import("@orpc/contract").MergedErrorMap<Record<never, never>, Record<never, never>>, Record<never, never>>;
|
|
19936
20012
|
groupBy: import("@orpc/contract").ContractProcedure<z.ZodObject<{
|
|
19937
20013
|
baseId: z.ZodString;
|
|
19938
|
-
fieldSlug: z.ZodString
|
|
20014
|
+
fieldSlug: z.ZodOptional<z.ZodString>;
|
|
20015
|
+
bucketing: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
|
|
20016
|
+
grid: "grid";
|
|
20017
|
+
sql: "sql";
|
|
20018
|
+
}>>>;
|
|
20019
|
+
aggregates: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
20020
|
+
fn: z.ZodEnum<{
|
|
20021
|
+
avg: "avg";
|
|
20022
|
+
count: "count";
|
|
20023
|
+
max: "max";
|
|
20024
|
+
min: "min";
|
|
20025
|
+
sum: "sum";
|
|
20026
|
+
}>;
|
|
20027
|
+
fieldSlug: z.ZodString;
|
|
20028
|
+
}, z.core.$strip>>>;
|
|
19939
20029
|
viewId: z.ZodOptional<z.ZodString>;
|
|
19940
20030
|
filters: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
19941
20031
|
fieldSlug: z.ZodString;
|
|
@@ -19950,10 +20040,36 @@ declare const cloudContract: {
|
|
|
19950
20040
|
}>;
|
|
19951
20041
|
value: z.ZodOptional<z.ZodUnknown>;
|
|
19952
20042
|
}, z.core.$strip>>>;
|
|
20043
|
+
valueFilters: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
20044
|
+
fieldSlug: z.ZodString;
|
|
20045
|
+
operator: z.ZodEnum<{
|
|
20046
|
+
eq: "eq";
|
|
20047
|
+
gt: "gt";
|
|
20048
|
+
gte: "gte";
|
|
20049
|
+
lt: "lt";
|
|
20050
|
+
lte: "lte";
|
|
20051
|
+
ne: "ne";
|
|
20052
|
+
}>;
|
|
20053
|
+
value: z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodBoolean]>;
|
|
20054
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
20055
|
+
any: z.ZodArray<z.ZodObject<{
|
|
20056
|
+
fieldSlug: z.ZodString;
|
|
20057
|
+
operator: z.ZodEnum<{
|
|
20058
|
+
eq: "eq";
|
|
20059
|
+
gt: "gt";
|
|
20060
|
+
gte: "gte";
|
|
20061
|
+
lt: "lt";
|
|
20062
|
+
lte: "lte";
|
|
20063
|
+
ne: "ne";
|
|
20064
|
+
}>;
|
|
20065
|
+
value: z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodBoolean]>;
|
|
20066
|
+
}, z.core.$strip>>;
|
|
20067
|
+
}, z.core.$strip>]>>>;
|
|
19953
20068
|
}, z.core.$strip>, z.ZodObject<{
|
|
19954
20069
|
groups: z.ZodArray<z.ZodObject<{
|
|
19955
|
-
value: z.ZodNullable<z.ZodString
|
|
20070
|
+
value: z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
19956
20071
|
count: z.ZodNumber;
|
|
20072
|
+
aggregates: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNullable<z.ZodNumber>>>;
|
|
19957
20073
|
}, z.core.$strip>>;
|
|
19958
20074
|
total: z.ZodNumber;
|
|
19959
20075
|
}, z.core.$strip>, import("@orpc/contract").MergedErrorMap<Record<never, never>, import("@orpc/contract").MergedErrorMap<Record<never, never>, {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as AssetUsageVO, A as NodeVO, At as ViewConfigVO, B as UpdateVaultSettingsDTO, Bt as NodeIconSchema, C as CommentVO, Ct as GalleryCardSize, D as MentionInboxItemVO, Dt as RecordVO, E as LookupRollup, Et as RecordLinkVO, F as SearchResponseVO, Ft as ViewVO, G as VaultItemVO, H as VaultEnvironment, Ht as CreatableNodeType, I as SearchResultKind, It as AttachmentRef, J as VaultSettingsVO, K as VaultRuntimeEnv, L as SearchResultVO, Lt as CloudContract, M as OperationVO, Mt as ViewFilterVO, N as ReviewVO, Nt as ViewSortVO, O as MentionInboxPageVO, Ot as VIEW_FIELD_MAX_WIDTH, P as ReviewVerdict, Pt as ViewType, Q as AssetTextStatus, R as SourceAttributionVO, Rt as cloudContract, S as CommentSubjectType, St as BaseVO, T as FieldType, Tt as GanttScale, U as VaultItemInput, Ut as NodeType, V as VaultAccessPolicy, Vt as CREATABLE_NODE_TYPES, W as VaultItemKind, Wt as OperationKind, X as FileNodeVO, Y as FileNodeMetadata, Z as AssetDetailVO, _ as ChangeRequestVO, _t as ListFormsVO, a as createBusabaseClient, at as FileTreeReadFileVO, b as CommentMentionTargetType, bt as AssetAttachmentRef, c as AuditAction, ct as CreateFormDTO, d as ChangeRequestBatchFailureVO, dt as FormPageSourceVO, et as AssetVO, f as ChangeRequestCountsVO, ft as FormShareVO, g as ChangeRequestTargetType, gt as ListFormsDTO, h as ChangeRequestStatus, ht as FormVO, i as ResolvedConfig, it as FileTreeNodeVO, j as OperationStatus, jt as ViewFilterOperator, k as NodeSearchResultVO, kt as VIEW_FIELD_MIN_WIDTH, l as AuditEventVO, lt as FormBoundFieldVO, m as ChangeRequestReviewBatchResultVO, mt as FormThemeVO, n as BusabaseConfig, nt as GrepResultVO, o as resolveConfig, ot as NodeDetailVO, p as ChangeRequestMergeBatchResultVO, pt as FormSubmitResultVO, q as VaultScopeType, r as DEFAULT_BASE_URL, rt as FileTreeFileVO, s as AgentTaskVO, st as ActivityItemVO, t as BusabaseClient, tt as GrepInputDTO, u as BusabaseSourceChannel, ut as FormFieldBindingVO, v as CommentMentionDispatchStatus, vt as SubmitFormDTO, w as CommitVO, wt as GalleryCoverFit, x as CommentMentionVO, xt as BaseFieldVO, y as CommentMentionInputDTO, yt as UpdateFormDTO, z as UserRefVO, zt as NodeIcon } from "./client-
|
|
1
|
+
import { $ as AssetUsageVO, A as NodeVO, At as ViewConfigVO, B as UpdateVaultSettingsDTO, Bt as NodeIconSchema, C as CommentVO, Ct as GalleryCardSize, D as MentionInboxItemVO, Dt as RecordVO, E as LookupRollup, Et as RecordLinkVO, F as SearchResponseVO, Ft as ViewVO, G as VaultItemVO, H as VaultEnvironment, Ht as CreatableNodeType, I as SearchResultKind, It as AttachmentRef, J as VaultSettingsVO, K as VaultRuntimeEnv, L as SearchResultVO, Lt as CloudContract, M as OperationVO, Mt as ViewFilterVO, N as ReviewVO, Nt as ViewSortVO, O as MentionInboxPageVO, Ot as VIEW_FIELD_MAX_WIDTH, P as ReviewVerdict, Pt as ViewType, Q as AssetTextStatus, R as SourceAttributionVO, Rt as cloudContract, S as CommentSubjectType, St as BaseVO, T as FieldType, Tt as GanttScale, U as VaultItemInput, Ut as NodeType, V as VaultAccessPolicy, Vt as CREATABLE_NODE_TYPES, W as VaultItemKind, Wt as OperationKind, X as FileNodeVO, Y as FileNodeMetadata, Z as AssetDetailVO, _ as ChangeRequestVO, _t as ListFormsVO, a as createBusabaseClient, at as FileTreeReadFileVO, b as CommentMentionTargetType, bt as AssetAttachmentRef, c as AuditAction, ct as CreateFormDTO, d as ChangeRequestBatchFailureVO, dt as FormPageSourceVO, et as AssetVO, f as ChangeRequestCountsVO, ft as FormShareVO, g as ChangeRequestTargetType, gt as ListFormsDTO, h as ChangeRequestStatus, ht as FormVO, i as ResolvedConfig, it as FileTreeNodeVO, j as OperationStatus, jt as ViewFilterOperator, k as NodeSearchResultVO, kt as VIEW_FIELD_MIN_WIDTH, l as AuditEventVO, lt as FormBoundFieldVO, m as ChangeRequestReviewBatchResultVO, mt as FormThemeVO, n as BusabaseConfig, nt as GrepResultVO, o as resolveConfig, ot as NodeDetailVO, p as ChangeRequestMergeBatchResultVO, pt as FormSubmitResultVO, q as VaultScopeType, r as DEFAULT_BASE_URL, rt as FileTreeFileVO, s as AgentTaskVO, st as ActivityItemVO, t as BusabaseClient, tt as GrepInputDTO, u as BusabaseSourceChannel, ut as FormFieldBindingVO, v as CommentMentionDispatchStatus, vt as SubmitFormDTO, w as CommitVO, wt as GalleryCoverFit, x as CommentMentionVO, xt as BaseFieldVO, y as CommentMentionInputDTO, yt as UpdateFormDTO, z as UserRefVO, zt as NodeIcon } from "./client-EYjDfri3.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
//#region src/url.d.ts
|
|
4
4
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { n as TemplateRiskLevelSchema } from "./template-C5oO6Au_.js";
|
|
1
2
|
import { t as normalizeBaseUrl } from "./url-B8GMXalA.js";
|
|
2
3
|
import { ORPCError, createORPCClient } from "@orpc/client";
|
|
3
4
|
import { OpenAPILink } from "@orpc/openapi-client/fetch";
|
|
@@ -1222,12 +1223,7 @@ const nodeShareSchema = z.object({
|
|
|
1222
1223
|
const listNodesInputSchema = z.object({
|
|
1223
1224
|
parentId: z.string().nullable().optional().describe("Node to start from. Omit or null to start from the space root."),
|
|
1224
1225
|
depth: z.coerce.number().int().min(1).max(5).optional().describe("How many levels beneath the start point to eagerly include (default 2 once either field is set). Capped at 5."),
|
|
1225
|
-
|
|
1226
|
-
* `active` (default) walks the live tree. `archived` returns the flat set of
|
|
1227
|
-
* soft-archived nodes for the Trash view — no `parentId`/`depth` walk, since
|
|
1228
|
-
* archived nodes are shown as a list, not a tree.
|
|
1229
|
-
*/
|
|
1230
|
-
status: z.enum(["active", "archived"]).optional().default("active"),
|
|
1226
|
+
status: z.enum(["active", "archived"]).optional().default("active").describe("`active` walks the live TREE. `archived` returns a FLAT list of soft-archived nodes (the Trash view) with no parent/depth walk — so the response shape you can rely on differs between the two, not just the rows."),
|
|
1231
1227
|
/**
|
|
1232
1228
|
* Narrow to specific node types and return a FLAT list of lightweight node
|
|
1233
1229
|
* summaries (`children: []`) instead of walking the tree. This is what
|
|
@@ -1254,8 +1250,8 @@ const listNodesInputSchema = z.object({
|
|
|
1254
1250
|
types: z.union([z.array(z.enum(NODE_TYPES)), z.enum(NODE_TYPES)]).transform((value) => Array.isArray(value) ? value : [value]).optional().describe("Return a flat list of lightweight summaries for these node types instead of the tree. Read one node's full detail with GET /nodes/{nodeId}.")
|
|
1255
1251
|
}).optional();
|
|
1256
1252
|
const isDescendantInputSchema = z.object({
|
|
1257
|
-
nodeId: z.string(),
|
|
1258
|
-
potentialAncestorId: z.string()
|
|
1253
|
+
nodeId: z.string().describe("The node walked UPWARDS from — the possible descendant."),
|
|
1254
|
+
potentialAncestorId: z.string().describe("The node looked for on the way up. Answers \"is `nodeId` inside this one?\", not the reverse — swapping the two silently returns the wrong answer rather than an error.")
|
|
1259
1255
|
});
|
|
1260
1256
|
const isDescendantOutputSchema = z.object({ isDescendant: z.boolean() });
|
|
1261
1257
|
const updateNodeMetadataInputSchema = z.object({
|
|
@@ -1322,8 +1318,8 @@ const updateNodeAgentPromptsInputSchema = z.object({
|
|
|
1322
1318
|
agentPrompts: customAgentPromptsSchema.nullable()
|
|
1323
1319
|
});
|
|
1324
1320
|
const searchNodesByNameInputSchema = z.object({
|
|
1325
|
-
query: z.string().min(1),
|
|
1326
|
-
limit: z.coerce.number().int().min(1).max(50).optional().default(20)
|
|
1321
|
+
query: z.string().min(1).describe("Matched against node NAMES only. Use `/api/v1/search` to search content."),
|
|
1322
|
+
limit: z.coerce.number().int().min(1).max(50).optional().default(20).describe("Results to return. Capped at 50 here, unlike most listings' 100.")
|
|
1327
1323
|
});
|
|
1328
1324
|
const nodeSearchResultSchema = z.object({
|
|
1329
1325
|
id: z.string(),
|
|
@@ -1514,8 +1510,8 @@ const mentionInboxPageSchema = z.object({
|
|
|
1514
1510
|
unreadCount: z.number().int()
|
|
1515
1511
|
});
|
|
1516
1512
|
const listMentionInboxInputSchema = z.object({
|
|
1517
|
-
page: z.number().int().min(1).optional().default(1),
|
|
1518
|
-
pageSize: z.number().int().min(1).max(100).optional().default(50)
|
|
1513
|
+
page: z.number().int().min(1).optional().default(1).describe("1-indexed, not 0-indexed."),
|
|
1514
|
+
pageSize: z.number().int().min(1).max(100).optional().default(50).describe("Mentions per page. Capped at 100.")
|
|
1519
1515
|
});
|
|
1520
1516
|
const markMentionsReadInputSchema = z.object({
|
|
1521
1517
|
/** Stamps every unread mention row this caller has on that comment. */
|
|
@@ -1753,8 +1749,8 @@ const reviewChangeRequestInputSchema = z.object({
|
|
|
1753
1749
|
reason: z.string().optional()
|
|
1754
1750
|
});
|
|
1755
1751
|
const commentSubjectInputSchema = z.object({
|
|
1756
|
-
subjectType: commentSubjectTypeSchema,
|
|
1757
|
-
subjectId: z.string().min(1)
|
|
1752
|
+
subjectType: commentSubjectTypeSchema.describe("What the comment thread hangs off, which decides how `subjectId` is interpreted."),
|
|
1753
|
+
subjectId: z.string().min(1).describe("The subject's id, interpreted according to `subjectType`.")
|
|
1758
1754
|
});
|
|
1759
1755
|
const createCommentInputSchema = commentSubjectInputSchema.extend({
|
|
1760
1756
|
authorId: z.string().optional().default("local-admin"),
|
|
@@ -1766,34 +1762,33 @@ const createCommentInputSchema = commentSubjectInputSchema.extend({
|
|
|
1766
1762
|
*/
|
|
1767
1763
|
mentions: z.array(commentMentionInputSchema).optional().default([])
|
|
1768
1764
|
});
|
|
1769
|
-
const listInputSchema = z.object({ limit: z.coerce.number().int().min(1).max(100).optional().default(50) }).optional().default({ limit: 50 });
|
|
1765
|
+
const listInputSchema = z.object({ limit: z.coerce.number().int().min(1).max(100).optional().default(50).describe("Rows to return, most recent first. Capped at 100; this listing has no cursor.") }).optional().default({ limit: 50 });
|
|
1770
1766
|
/**
|
|
1771
1767
|
* Active-or-archived selector for listings whose archived twin was folded in.
|
|
1772
1768
|
* Archived rows are the same shape as live ones — the only thing that ever
|
|
1773
1769
|
* differed between `/x` and `/x/archived` was this predicate.
|
|
1774
1770
|
*/
|
|
1775
|
-
const listByStatusInputSchema = z.object({ status: z.enum(["active", "archived"]).optional().default("active") });
|
|
1771
|
+
const listByStatusInputSchema = z.object({ status: z.enum(["active", "archived"]).optional().default("active").describe("`active` (default) or the soft-archived set. Archived rows have the SAME shape as live ones — this is a predicate, not a different resource.") });
|
|
1776
1772
|
const listChangeRequestsPagedInputSchema = z.object({
|
|
1777
|
-
limit: z.coerce.number().int().min(1).max(100).optional().default(50),
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
affectsNodeId: z.string().min(1).optional()
|
|
1773
|
+
limit: z.coerce.number().int().min(1).max(100).optional().default(50).describe("Change requests per page. Capped at 100; ask for the next page with `cursor`."),
|
|
1774
|
+
cursor: z.string().optional().describe("Opaque page cursor: pass back the `nextCursor` from the previous response. Do not construct or parse it."),
|
|
1775
|
+
status: z.array(changeRequestStatusSchema).optional().describe("Keep only these statuses. Omitting it returns every status, not just open ones."),
|
|
1776
|
+
mine: z.boolean().optional().describe("Only change requests CREATED by the acting user — not ones awaiting their review."),
|
|
1777
|
+
affectsNodeId: z.string().min(1).optional().describe("Only change requests whose target, or any of their operations, touches this node — including Base-backed nodes. To ask whether a resource already has an unfinished change request, pass this with `limit: 1` rather than paging the space: an empty result is conclusive.")
|
|
1783
1778
|
}).optional().default({ limit: 50 });
|
|
1784
1779
|
const listChangeRequestsResponseSchema = z.object({
|
|
1785
1780
|
changeRequests: z.array(changeRequestSchema),
|
|
1786
1781
|
nextCursor: z.string().nullable()
|
|
1787
1782
|
});
|
|
1788
1783
|
const changeRequestPageInputShape = {
|
|
1789
|
-
page: z.coerce.number().int().min(1).optional().default(1),
|
|
1790
|
-
pageSize: z.coerce.number().int().min(1).max(100).optional().default(50),
|
|
1791
|
-
status: z.array(changeRequestStatusSchema).optional(),
|
|
1792
|
-
mine: z.boolean().optional()
|
|
1784
|
+
page: z.coerce.number().int().min(1).optional().default(1).describe("1-indexed, not 0-indexed."),
|
|
1785
|
+
pageSize: z.coerce.number().int().min(1).max(100).optional().default(50).describe("Change requests per page. Capped at 100."),
|
|
1786
|
+
status: z.array(changeRequestStatusSchema).optional().describe("Keep only these statuses. Omitting it returns every status, not just open ones."),
|
|
1787
|
+
mine: z.boolean().optional().describe("Only change requests CREATED by the acting user — not ones awaiting their review.")
|
|
1793
1788
|
};
|
|
1794
1789
|
const listChangeRequestsPageInputSchema = z.object({
|
|
1795
1790
|
...changeRequestPageInputShape,
|
|
1796
|
-
affectsNodeId: z.string().min(1).optional()
|
|
1791
|
+
affectsNodeId: z.string().min(1).optional().describe("Only change requests whose target, or any of their operations, touches this node — including Base-backed nodes.")
|
|
1797
1792
|
}).optional().default({
|
|
1798
1793
|
page: 1,
|
|
1799
1794
|
pageSize: 50
|
|
@@ -1825,9 +1820,9 @@ const SEARCH_SOURCES = [
|
|
|
1825
1820
|
"nodes"
|
|
1826
1821
|
];
|
|
1827
1822
|
const searchInputSchema = z.object({
|
|
1828
|
-
query: z.string().default(""),
|
|
1829
|
-
limit: z.coerce.number().int().min(1).max(100).optional().default(20),
|
|
1830
|
-
offset: z.coerce.number().int().min(0).optional().default(0),
|
|
1823
|
+
query: z.string().default("").describe("Full-text query. An empty string matches nothing."),
|
|
1824
|
+
limit: z.coerce.number().int().min(1).max(100).optional().default(20).describe("Results per page. Capped at 100; note the default is 20, not 50."),
|
|
1825
|
+
offset: z.coerce.number().int().min(0).optional().default(0).describe("0-indexed skip count. This endpoint pages by offset, not by cursor."),
|
|
1831
1826
|
/**
|
|
1832
1827
|
* Restrict which content this call searches. Omitted means all three
|
|
1833
1828
|
* (unchanged behavior for every caller before this parameter existed).
|
|
@@ -1837,7 +1832,7 @@ const searchInputSchema = z.object({
|
|
|
1837
1832
|
* (`?sources=records&sources=files`) becomes an array. Accept both shapes
|
|
1838
1833
|
* and normalize to an array.
|
|
1839
1834
|
*/
|
|
1840
|
-
sources: z.union([z.array(z.enum(SEARCH_SOURCES)), z.enum(SEARCH_SOURCES)]).transform((value) => Array.isArray(value) ? value : [value]).optional()
|
|
1835
|
+
sources: z.union([z.array(z.enum(SEARCH_SOURCES)), z.enum(SEARCH_SOURCES)]).transform((value) => Array.isArray(value) ? value : [value]).optional().describe("Restrict which content is searched. Omitting it searches ALL sources. Repeat the parameter to pass several (`?sources=records&sources=files`); a single occurrence is accepted as a bare value.")
|
|
1841
1836
|
});
|
|
1842
1837
|
const authSpaceSchema = z.object({
|
|
1843
1838
|
id: z.string(),
|
|
@@ -2003,11 +1998,9 @@ const fileTreeNodeTypeSchema = z.enum([
|
|
|
2003
1998
|
"drive",
|
|
2004
1999
|
"airapp"
|
|
2005
2000
|
]);
|
|
2006
|
-
/** `nodeId` accepts a node id or a slug. A slug is only unique *within* a type,
|
|
2007
|
-
* so pass `type` alongside it to disambiguate; a node id needs no hint. */
|
|
2008
2001
|
const fileTreeRefSchema = z.object({
|
|
2009
|
-
nodeId: z.string(),
|
|
2010
|
-
type: fileTreeNodeTypeSchema.optional()
|
|
2002
|
+
nodeId: z.string().describe("A node id OR a slug. A slug is only unique WITHIN a type, so pass `type` alongside one; a node id needs no hint."),
|
|
2003
|
+
type: fileTreeNodeTypeSchema.optional().describe("Disambiguates a slug. Unnecessary — and ignored — when `nodeId` is an id.")
|
|
2011
2004
|
});
|
|
2012
2005
|
const fileTreeContract = {
|
|
2013
2006
|
create: oc.route({
|
|
@@ -2351,8 +2344,8 @@ z.object({
|
|
|
2351
2344
|
/** `GET /assets/{assetId}/text/lines?startLine&endLine` — range capped at 2000 lines. */
|
|
2352
2345
|
const ReadTextLinesInputSchema = z.object({
|
|
2353
2346
|
assetId: z.string(),
|
|
2354
|
-
startLine: z.coerce.number().int().min(1),
|
|
2355
|
-
endLine: z.coerce.number().int().min(1)
|
|
2347
|
+
startLine: z.coerce.number().int().min(1).describe("First line to read. 1-indexed, and INCLUSIVE."),
|
|
2348
|
+
endLine: z.coerce.number().int().min(1).describe("Last line to read, INCLUSIVE. A range wider than 2000 lines is silently narrowed to the first 2000 rather than rejected — the response reports `lineCountCapped` when that happened, so check it before concluding the file ends there.")
|
|
2356
2349
|
});
|
|
2357
2350
|
const ReadLinesVOSchema = z.object({
|
|
2358
2351
|
lines: z.array(z.string()),
|
|
@@ -2639,21 +2632,68 @@ const listRecordsSortSchema = z.object({
|
|
|
2639
2632
|
fieldType: z.string().optional(),
|
|
2640
2633
|
direction: z.enum(["asc", "desc"]).optional().default("asc")
|
|
2641
2634
|
});
|
|
2635
|
+
const listRecordsValueFilterSchema = z.object({
|
|
2636
|
+
fieldSlug: z.string(),
|
|
2637
|
+
operator: z.enum([
|
|
2638
|
+
"eq",
|
|
2639
|
+
"ne",
|
|
2640
|
+
"gt",
|
|
2641
|
+
"gte",
|
|
2642
|
+
"lt",
|
|
2643
|
+
"lte"
|
|
2644
|
+
]),
|
|
2645
|
+
/**
|
|
2646
|
+
* A number for number fields, an ISO 8601 string for date fields, a boolean
|
|
2647
|
+
* for checkbox, and a string for the text-like families (where only `eq`/`ne`
|
|
2648
|
+
* are exact — see `buildExactValueFilter`).
|
|
2649
|
+
*/
|
|
2650
|
+
value: z.union([
|
|
2651
|
+
z.number(),
|
|
2652
|
+
z.string(),
|
|
2653
|
+
z.boolean()
|
|
2654
|
+
])
|
|
2655
|
+
});
|
|
2656
|
+
/**
|
|
2657
|
+
* One conjunct of `valueFilters`: either a single comparison, or a disjunction
|
|
2658
|
+
* of them.
|
|
2659
|
+
*
|
|
2660
|
+
* `valueFilters` is an AND of these, so an entry carrying `any` makes the whole
|
|
2661
|
+
* list a CNF (an AND of ORs) — which is enough to express ANY boolean
|
|
2662
|
+
* combination of comparisons, since every formula has a CNF. That is why this
|
|
2663
|
+
* is one flat level rather than an arbitrarily nested tree: a recursive schema
|
|
2664
|
+
* would buy no expressive power, and would cost a `z.lazy` that OpenAPI
|
|
2665
|
+
* generation and generated clients both handle worse than a plain union.
|
|
2666
|
+
*
|
|
2667
|
+
* NOT is deliberately absent, and is not a gap: every operator here has an
|
|
2668
|
+
* exact negation (`eq`↔`ne`, `gt`↔`lte`, `gte`↔`lt`), so a caller pushes
|
|
2669
|
+
* negation down to the leaves with De Morgan before sending. Keeping NOT out of
|
|
2670
|
+
* the wire format keeps the server's evaluation MONOTONE, which is what makes
|
|
2671
|
+
* the missing-value semantics below sound.
|
|
2672
|
+
*
|
|
2673
|
+
* Missing values: a comparison against a field the record has no row for is
|
|
2674
|
+
* false, never true — the `EXISTS` in `buildExactValueFilter` sees no row. That
|
|
2675
|
+
* collapses SQL's UNKNOWN to false at each leaf, which is safe here precisely
|
|
2676
|
+
* because the formula is monotone: for an AND/OR tree with no NOT, "Kleene
|
|
2677
|
+
* three-valued result is TRUE" and "result with UNKNOWN replaced by FALSE is
|
|
2678
|
+
* TRUE" agree (OR is `some operand true` and AND is `all operands true` under
|
|
2679
|
+
* both readings). A NOT anywhere in the tree would break that equivalence,
|
|
2680
|
+
* which is the other reason it is not on the wire.
|
|
2681
|
+
*/
|
|
2682
|
+
const listRecordsValueFilterNodeSchema = z.union([listRecordsValueFilterSchema, z.object({ any: z.array(listRecordsValueFilterSchema).min(1) })]);
|
|
2642
2683
|
const listRecordsInputSchema = z.object({
|
|
2643
|
-
limit: z.coerce.number().int().min(1).max(100).optional().default(50),
|
|
2644
|
-
baseId: z.string().optional(),
|
|
2645
|
-
|
|
2646
|
-
|
|
2684
|
+
limit: z.coerce.number().int().min(1).max(100).optional().default(50).describe("Records per page. Capped at 100; ask for the next page with `cursor`."),
|
|
2685
|
+
baseId: z.string().optional().describe("Restrict to one Base. OMITTING it lists records across the WHOLE SPACE, which is rarely what a caller means and is easy to miss — every other parameter still applies, so an unscoped query looks like it worked."),
|
|
2686
|
+
cursor: z.string().optional().describe("Opaque page cursor: pass back the `nextCursor` from the previous response. Do not construct or parse it — it is keyed on `createdAt`, or on the sort field when `sort` is given, and that is an implementation detail."),
|
|
2687
|
+
status: z.enum(["active", "archived"]).optional().default("active").describe("`active` is the live table; `archived` is the Base's trash."),
|
|
2688
|
+
filters: z.array(listRecordsFilterSchema).optional().describe("View filters — a best-effort SUPERSET, not an exact answer. They mean what the grid means (a currency number reads as \"$1,234.00\", a select as its choice label), and the server may return records that do not match, so the caller must narrow them again and must NOT trust `limit` alongside them. Use `valueFilters` when you need an exact row set."),
|
|
2647
2689
|
/**
|
|
2648
|
-
*
|
|
2649
|
-
*
|
|
2650
|
-
*
|
|
2690
|
+
* Exact value comparisons. Unlike `filters` these are authoritative — the
|
|
2691
|
+
* returned rows are exactly those that match, so a caller can page and
|
|
2692
|
+
* limit against them. ANDed together (and with `filters` when both are
|
|
2693
|
+
* given); an entry may be a disjunction, making the list a CNF.
|
|
2651
2694
|
*/
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
filters: z.array(listRecordsFilterSchema).optional(),
|
|
2655
|
-
/** View sort for server-side push-down (number/date fields only). */
|
|
2656
|
-
sort: listRecordsSortSchema.optional()
|
|
2695
|
+
valueFilters: z.array(listRecordsValueFilterNodeSchema).optional().describe("EXACT value comparisons, unlike `filters` which are a best-effort superset. The returned rows are exactly those that match, so `limit` can be trusted alongside them. Entries are ANDed; an entry may instead be `{ any: [...] }` to OR its comparisons, which makes the list a CNF and can express any boolean combination. Requires `baseId`. Compares number, date, checkbox and text-like fields (text and select support eq/ne only); anything else is a 400 rather than a silently dropped condition."),
|
|
2696
|
+
sort: listRecordsSortSchema.optional().describe("Sort by one field. Only number and date fields sort authoritatively (their typed value column matches a client's own ordering); any other field type is returned in the default order and left for the caller to sort.")
|
|
2657
2697
|
}).optional().default({
|
|
2658
2698
|
limit: 50,
|
|
2659
2699
|
status: "active"
|
|
@@ -2663,8 +2703,8 @@ const listRecordsResponseSchema = z.object({
|
|
|
2663
2703
|
nextCursor: z.string().nullable()
|
|
2664
2704
|
});
|
|
2665
2705
|
const listRecordsPageInputSchema = z.object({
|
|
2666
|
-
baseId: z.string().min(1),
|
|
2667
|
-
viewId: z.string().min(1).optional(),
|
|
2706
|
+
baseId: z.string().min(1).describe("Required here, unlike `records.list` where omitting it spans the whole space."),
|
|
2707
|
+
viewId: z.string().min(1).optional().describe("Show only what this saved View would: its filters and its sort."),
|
|
2668
2708
|
/**
|
|
2669
2709
|
* Extra conditions ANDed with the View's own filters — "this View, further
|
|
2670
2710
|
* narrowed". The motivating case is one board column: the saved View's
|
|
@@ -2677,7 +2717,7 @@ const listRecordsPageInputSchema = z.object({
|
|
|
2677
2717
|
* That distinction is the whole point — a *superset* page can be missing
|
|
2678
2718
|
* records, and a board column that silently drops cards reads as data loss.
|
|
2679
2719
|
*/
|
|
2680
|
-
filters: z.array(listRecordsFilterSchema).optional(),
|
|
2720
|
+
filters: z.array(listRecordsFilterSchema).optional().describe("Extra conditions ANDed with the View's own — \"this View, further narrowed\". Unlike `records.list`'s `filters`, these are EXACT: every page is precisely what the client's own matcher would keep, so a page is never missing records it should hold."),
|
|
2681
2721
|
/**
|
|
2682
2722
|
* Scope the page to records whose `date`/`created_time`/`updated_time` field
|
|
2683
2723
|
* falls in `[gte, lt)` — an absolute UTC instant range, not a `filters`
|
|
@@ -2695,13 +2735,11 @@ const listRecordsPageInputSchema = z.object({
|
|
|
2695
2735
|
*/
|
|
2696
2736
|
dateRange: z.object({
|
|
2697
2737
|
fieldSlug: z.string().min(1),
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
page: z.coerce.number().int().min(1).optional().default(1),
|
|
2704
|
-
pageSize: z.coerce.number().int().min(1).max(100).optional().default(50)
|
|
2738
|
+
gte: z.string().describe("Inclusive lower bound, ISO 8601 UTC instant."),
|
|
2739
|
+
lt: z.string().describe("EXCLUSIVE upper bound, ISO 8601 UTC instant.")
|
|
2740
|
+
}).optional().describe("Scope the page to a `date`/`created_time`/`updated_time` field falling in `[gte, lt)` — a half-open range of absolute UTC instants, not a `filters` condition. Resolve the bounds yourself: a day or a month only means something in a timezone, and the server does not know the viewer's."),
|
|
2741
|
+
page: z.coerce.number().int().min(1).optional().default(1).describe("1-indexed, not 0-indexed."),
|
|
2742
|
+
pageSize: z.coerce.number().int().min(1).max(100).optional().default(50).describe("Records per page. Capped at 100.")
|
|
2705
2743
|
});
|
|
2706
2744
|
const listRecordsPageResponseSchema = z.object({
|
|
2707
2745
|
records: z.array(recordSchema),
|
|
@@ -2711,13 +2749,8 @@ const listRecordsPageResponseSchema = z.object({
|
|
|
2711
2749
|
pageSize: z.number().int().min(1).max(100)
|
|
2712
2750
|
});
|
|
2713
2751
|
const countRecordsInputSchema = z.object({
|
|
2714
|
-
baseId: z.string().optional(),
|
|
2715
|
-
|
|
2716
|
-
* Count only the rows a saved View would display (the View's filters
|
|
2717
|
-
* applied; its sort is ignored — a count doesn't need an order). A View
|
|
2718
|
-
* belongs to exactly one Base, so this requires `baseId`.
|
|
2719
|
-
*/
|
|
2720
|
-
viewId: z.string().optional(),
|
|
2752
|
+
baseId: z.string().optional().describe("Restrict to one Base. Omitting it counts every record in the space. Required as soon as `viewId`, `filters` or `valueFilters` is given — a field slug only means something within one Base."),
|
|
2753
|
+
viewId: z.string().optional().describe("Count only what this saved View would display. Its filters apply; its sort is ignored, since a count has no order. Requires `baseId`."),
|
|
2721
2754
|
/**
|
|
2722
2755
|
* Ad-hoc filter conditions — same shape `records.list`'s `filters` uses —
|
|
2723
2756
|
* for composing a condition set without a saved View (e.g. an AirApp
|
|
@@ -2728,8 +2761,23 @@ const countRecordsInputSchema = z.object({
|
|
|
2728
2761
|
* never the caller-supplied `fieldType` hint, which elsewhere is only a
|
|
2729
2762
|
* pushdown hint and isn't trustworthy enough for an exact count.
|
|
2730
2763
|
*/
|
|
2731
|
-
filters: z.array(listRecordsFilterSchema).optional()
|
|
2764
|
+
filters: z.array(listRecordsFilterSchema).optional().describe("Ad-hoc conditions, ANDed with the View's own when `viewId` is also given. Unlike `records.list`'s superset `filters`, the COUNT is exact either way — but a condition whose exactness cannot be proven makes the server read every candidate row instead of running one aggregate, so prefer `valueFilters` where it fits. Requires `baseId`."),
|
|
2765
|
+
/**
|
|
2766
|
+
* Exact value comparisons, same shape and meaning as `records.list`'s.
|
|
2767
|
+
*
|
|
2768
|
+
* Worth having here specifically because they are ALWAYS exact: a count
|
|
2769
|
+
* scoped only by these stays a single SQL `count(*)`, where an ad-hoc view
|
|
2770
|
+
* `filters` set that cannot be proven exact falls back to reading every
|
|
2771
|
+
* candidate row and counting the survivors. Requires `baseId` for the same
|
|
2772
|
+
* reason `filters` does — a field slug is only unambiguous within one Base.
|
|
2773
|
+
*/
|
|
2774
|
+
valueFilters: z.array(listRecordsValueFilterNodeSchema).optional().describe("EXACT value comparisons, same shape as `records.list`'s. Always exact, so a count scoped only by these stays a single SQL count instead of reading every candidate row. Requires `baseId`.")
|
|
2732
2775
|
}).superRefine((value, ctx) => {
|
|
2776
|
+
if (value.valueFilters?.length && !value.baseId) ctx.addIssue({
|
|
2777
|
+
code: "custom",
|
|
2778
|
+
path: ["baseId"],
|
|
2779
|
+
message: "baseId is required when valueFilters is given"
|
|
2780
|
+
});
|
|
2733
2781
|
if (value.viewId && !value.baseId) ctx.addIssue({
|
|
2734
2782
|
code: "custom",
|
|
2735
2783
|
path: ["baseId"],
|
|
@@ -2744,9 +2792,30 @@ const countRecordsInputSchema = z.object({
|
|
|
2744
2792
|
const countRecordsResponseSchema = z.object({
|
|
2745
2793
|
/** Total active records in the space (optionally scoped to a base). */
|
|
2746
2794
|
total: z.number().int().nonnegative() });
|
|
2795
|
+
/**
|
|
2796
|
+
* A numeric aggregate over the records in a group.
|
|
2797
|
+
*
|
|
2798
|
+
* Exact for the same reason `valueFilters` are: `value_number` holds the value
|
|
2799
|
+
* itself, so `sum`/`avg`/`min`/`max` are ordinary SQL over a real column with
|
|
2800
|
+
* no formatting layer to diverge from. Restricted to number-shaped fields for
|
|
2801
|
+
* exactly that reason — there is no column to add up on the others.
|
|
2802
|
+
*
|
|
2803
|
+
* `count` here counts rows whose value is PRESENT, which is not the same as the
|
|
2804
|
+
* group's `count` (that one counts records, present value or not). Both are
|
|
2805
|
+
* useful and SQL distinguishes them, so both are available.
|
|
2806
|
+
*/
|
|
2807
|
+
const recordAggregateSchema = z.object({
|
|
2808
|
+
fn: z.enum([
|
|
2809
|
+
"sum",
|
|
2810
|
+
"avg",
|
|
2811
|
+
"min",
|
|
2812
|
+
"max",
|
|
2813
|
+
"count"
|
|
2814
|
+
]),
|
|
2815
|
+
fieldSlug: z.string().min(1)
|
|
2816
|
+
});
|
|
2747
2817
|
const groupRecordsInputSchema = z.object({
|
|
2748
|
-
|
|
2749
|
-
baseId: z.string().min(1),
|
|
2818
|
+
baseId: z.string().min(1).describe("Required: a field slug is only unambiguous within one Base."),
|
|
2750
2819
|
/**
|
|
2751
2820
|
* The field to group by. Restricted to `select` and `checkbox`: their stored
|
|
2752
2821
|
* value IS the grouping key (a choice id / a boolean), so a SQL GROUP BY
|
|
@@ -2754,28 +2823,74 @@ const groupRecordsInputSchema = z.object({
|
|
|
2754
2823
|
* be truncated at the projection limit, and date keys would bucket by the
|
|
2755
2824
|
* server's timezone rather than the viewer's — both would report a
|
|
2756
2825
|
* confidently wrong split, so they're rejected instead of approximated.
|
|
2826
|
+
*
|
|
2827
|
+
* OMIT it to aggregate the whole filtered set as a single bucket. That is the
|
|
2828
|
+
* shape a summary tile wants ("total pipeline value"), and it costs one query
|
|
2829
|
+
* instead of reading every record to add them up client-side.
|
|
2757
2830
|
*/
|
|
2758
|
-
fieldSlug: z.string().min(1),
|
|
2759
|
-
/**
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2831
|
+
fieldSlug: z.string().min(1).optional().describe("The field to group by. OMIT it to aggregate the whole filtered set as a single bucket, which is what a summary tile wants. Under the default `grid` bucketing only `select` and `checkbox` can be grouped; `sql` bucketing also allows number and date fields."),
|
|
2832
|
+
/**
|
|
2833
|
+
* Which bucketing rules to use, and they genuinely differ.
|
|
2834
|
+
*
|
|
2835
|
+
* `grid` (the default, and what this endpoint has always done) buckets the
|
|
2836
|
+
* way the GRID renders: an unset checkbox folds in with `false`, and an empty
|
|
2837
|
+
* string folds into the null bucket. That is right for a Kanban column header
|
|
2838
|
+
* — a card with no value belongs under "false", not in a fourth column.
|
|
2839
|
+
*
|
|
2840
|
+
* `sql` buckets the way `GROUP BY` does: a missing value gets its OWN bucket
|
|
2841
|
+
* and nothing is folded. That is right for a caller reproducing SQL — an ORM
|
|
2842
|
+
* driver, or anything comparing this against a database — and it is what lets
|
|
2843
|
+
* such a caller trust the server's answer instead of re-grouping locally.
|
|
2844
|
+
*
|
|
2845
|
+
* The two disagree on real data, which is why this is a choice rather than a
|
|
2846
|
+
* fix: neither is a better version of the other.
|
|
2847
|
+
*/
|
|
2848
|
+
bucketing: z.enum(["grid", "sql"]).optional().default("grid").describe("How records are bucketed, and the two modes disagree on real data. `grid` (default) buckets the way the grid renders: an unset checkbox counts as `false` and an empty string falls in the null bucket — right for a Kanban column header. `sql` buckets the way GROUP BY does: a missing value gets its OWN bucket and nothing is folded — right for anything reproducing SQL. `sql` also returns keys in their own type (a number for a number field) rather than as strings."),
|
|
2849
|
+
/**
|
|
2850
|
+
* Numeric aggregates evaluated per group, keyed in the response as
|
|
2851
|
+
* `"<fn>:<fieldSlug>"`. Without this the response is counts only, exactly as
|
|
2852
|
+
* before.
|
|
2853
|
+
*/
|
|
2854
|
+
aggregates: z.array(recordAggregateSchema).optional().describe("Numeric aggregates evaluated per group, keyed in the response as `\"<fn>:<fieldSlug>\"`. Only number-shaped fields can be aggregated; anything else is a 400. `sum`/`avg`/`min`/`max` of a group holding no values are NULL rather than 0, and `count` over a FIELD counts present values — which is not the same as the group's own `count`, which counts records."),
|
|
2855
|
+
viewId: z.string().min(1).optional().describe("Group only what this saved View would display. Its filters apply; its sort is ignored."),
|
|
2856
|
+
filters: z.array(listRecordsFilterSchema).optional().describe("Ad-hoc conditions, ANDed with the View's own when both are given. The grouping is exact either way, but a condition whose exactness cannot be proven makes the server read every candidate row instead of running one GROUP BY."),
|
|
2857
|
+
/**
|
|
2858
|
+
* Exact value comparisons, ANDed with everything above. Always exact, so a
|
|
2859
|
+
* grouping scoped only by these stays a single SQL GROUP BY.
|
|
2860
|
+
*/
|
|
2861
|
+
valueFilters: z.array(listRecordsValueFilterNodeSchema).optional().describe("EXACT value comparisons, same shape as `records.list`'s. Always exact, so a grouping scoped only by these stays a single SQL GROUP BY.")
|
|
2763
2862
|
});
|
|
2764
2863
|
const groupRecordsResponseSchema = z.object({
|
|
2765
2864
|
groups: z.array(z.object({
|
|
2766
2865
|
/**
|
|
2767
|
-
* The raw stored key
|
|
2768
|
-
*
|
|
2769
|
-
* (
|
|
2770
|
-
*
|
|
2771
|
-
*
|
|
2866
|
+
* The raw stored key.
|
|
2867
|
+
*
|
|
2868
|
+
* Under `grid` bucketing (the default) this is always a string or null: a
|
|
2869
|
+
* `select` choice id, or `"true"`/`"false"` for a checkbox, where `null`
|
|
2870
|
+
* is the bucket of records with no value (a Kanban board's
|
|
2871
|
+
* "Uncategorized" column) and an unset checkbox counts as `"false"`.
|
|
2872
|
+
*
|
|
2873
|
+
* Under `sql` bucketing it is the STORED value in its own type — a number
|
|
2874
|
+
* for a number field, a boolean for a checkbox, an ISO string for a date
|
|
2875
|
+
* — and `null` means the record has no value for that field, which under
|
|
2876
|
+
* these rules is a bucket of its own rather than folded into another.
|
|
2772
2877
|
*
|
|
2773
2878
|
* Choice LABELS are deliberately not resolved here — the client already
|
|
2774
2879
|
* holds the Base's field definitions and renders labels itself, and
|
|
2775
2880
|
* returning ids keeps this response stable across a choice rename.
|
|
2776
2881
|
*/
|
|
2777
|
-
value: z.
|
|
2778
|
-
|
|
2882
|
+
value: z.union([
|
|
2883
|
+
z.string(),
|
|
2884
|
+
z.number(),
|
|
2885
|
+
z.boolean()
|
|
2886
|
+
]).nullable().describe("The bucket key. Under `grid` bucketing always a string or null (a select's choice, or `\"true\"`/`\"false\"` for a checkbox, with null meaning \"no value\"). Under `sql` bucketing it is the stored value in its own type, and null is the bucket of records that have no value for the field."),
|
|
2887
|
+
count: z.number().int().nonnegative().describe("Records in this bucket."),
|
|
2888
|
+
/**
|
|
2889
|
+
* Present only when `aggregates` was requested. Keyed `"<fn>:<fieldSlug>"`.
|
|
2890
|
+
* A value of `null` means the group held no rows with that field set —
|
|
2891
|
+
* which is NOT the same as `0`, and a dashboard renders them differently.
|
|
2892
|
+
*/
|
|
2893
|
+
aggregates: z.record(z.string(), z.number().nullable()).optional().describe("Present only when `aggregates` was requested, keyed `\"<fn>:<fieldSlug>\"`. A null value means the bucket held no records with that field set — not zero.")
|
|
2779
2894
|
})),
|
|
2780
2895
|
/** Sum of every group's count — the same number `records.count` would return. */
|
|
2781
2896
|
total: z.number().int().nonnegative()
|
|
@@ -2822,10 +2937,10 @@ const createBulkUpdateChangeRequestInputSchema = z.object({
|
|
|
2822
2937
|
}
|
|
2823
2938
|
});
|
|
2824
2939
|
const recordFieldFilterInputSchema = z.object({
|
|
2825
|
-
baseId: z.string().optional(),
|
|
2826
|
-
fieldSlug: z.string().min(1),
|
|
2827
|
-
valueText: z.string().min(1),
|
|
2828
|
-
limit: z.coerce.number().int().min(1).max(100).optional().default(50)
|
|
2940
|
+
baseId: z.string().optional().describe("Restrict to one Base. Omitting it searches the whole space."),
|
|
2941
|
+
fieldSlug: z.string().min(1).describe("The field's SLUG, not its display name — visible in the Base's field settings."),
|
|
2942
|
+
valueText: z.string().min(1).describe("Matched by EXACT equality, not substring or fuzzy — this is the de-dup-by-key lookup. Use `/api/v1/search` for full-text."),
|
|
2943
|
+
limit: z.coerce.number().int().min(1).max(100).optional().default(50).describe("Maximum matches to return. Capped at 100.")
|
|
2829
2944
|
});
|
|
2830
2945
|
const recordFieldGetInputSchema = z.object({
|
|
2831
2946
|
baseId: z.string().describe("Field selector: Base id. Requires fieldSlug and valueText."),
|
|
@@ -3099,8 +3214,8 @@ const docContract = { create: oc.route({
|
|
|
3099
3214
|
*/
|
|
3100
3215
|
const ReadNodeLinesInputSchema = z.object({
|
|
3101
3216
|
nodeId: z.string(),
|
|
3102
|
-
startLine: z.coerce.number().int().min(1),
|
|
3103
|
-
endLine: z.coerce.number().int().min(1)
|
|
3217
|
+
startLine: z.coerce.number().int().min(1).describe("First line to read. 1-indexed, and INCLUSIVE."),
|
|
3218
|
+
endLine: z.coerce.number().int().min(1).describe("Last line to read, INCLUSIVE. A range wider than 2000 lines is silently narrowed to the first 2000 rather than rejected — the response reports `lineCountCapped` when that happened, so check it before concluding the file ends there.")
|
|
3104
3219
|
});
|
|
3105
3220
|
//#endregion
|
|
3106
3221
|
//#region ../../packages/busabase-contract/src/domains/dump/types.ts
|
|
@@ -3418,10 +3533,9 @@ const FormVOSchema = z.object({
|
|
|
3418
3533
|
updatedAt: z.string()
|
|
3419
3534
|
});
|
|
3420
3535
|
const ListFormsInputSchema = z.object({
|
|
3421
|
-
targetBaseId: z.string().min(1),
|
|
3422
|
-
limit: z.coerce.number().int().min(1).max(100).optional().default(50),
|
|
3423
|
-
|
|
3424
|
-
cursor: z.string().optional()
|
|
3536
|
+
targetBaseId: z.string().min(1).describe("The Base the forms WRITE INTO — required; this is not a space-wide listing."),
|
|
3537
|
+
limit: z.coerce.number().int().min(1).max(100).optional().default(50).describe("Forms per page. Capped at 100; ask for the next page with `cursor`."),
|
|
3538
|
+
cursor: z.string().optional().describe("Opaque page cursor: pass back the `nextCursor` from the previous response. Do not construct or parse it.")
|
|
3425
3539
|
});
|
|
3426
3540
|
const ListFormsVOSchema = z.object({
|
|
3427
3541
|
forms: z.array(FormVOSchema),
|
|
@@ -3754,9 +3868,11 @@ const installContract = {
|
|
|
3754
3868
|
* Template Center catalog types (pure zod, client-safe).
|
|
3755
3869
|
*
|
|
3756
3870
|
* The catalog is the file `busabase-cli index` builds from a skills repository
|
|
3757
|
-
* — see `busabase-package/index-build`.
|
|
3758
|
-
* imported because that module is Node-only (it reads packages)
|
|
3759
|
-
*
|
|
3871
|
+
* — see `busabase-package/index-build`. Most shapes are re-declared here rather
|
|
3872
|
+
* than imported because that module is Node-only (it reads packages) and these
|
|
3873
|
+
* are rendered in a browser; `TemplateRiskLevelSchema` is the one exception,
|
|
3874
|
+
* imported from the package domain because it is already pure zod and a third
|
|
3875
|
+
* copy of the same enum is a worse outcome than the cross-domain import.
|
|
3760
3876
|
*
|
|
3761
3877
|
* Spec: `apps/busabase/content/spec/template-center.md` §6.4.
|
|
3762
3878
|
*/
|
|
@@ -3775,6 +3891,8 @@ const TemplateCardVOSchema = z.object({
|
|
|
3775
3891
|
name: z.string(),
|
|
3776
3892
|
description: z.string(),
|
|
3777
3893
|
category: z.string(),
|
|
3894
|
+
/** Absent when undeclared or unrecognized — the card shows "undeclared", never a guess. */
|
|
3895
|
+
risk: TemplateRiskLevelSchema.optional(),
|
|
3778
3896
|
tags: z.array(z.string()).default([]),
|
|
3779
3897
|
/**
|
|
3780
3898
|
* Absolute URLs, resolved server-side.
|
|
@@ -3812,9 +3930,7 @@ const TemplateCatalogVOSchema = z.object({
|
|
|
3812
3930
|
*/
|
|
3813
3931
|
error: z.string().optional()
|
|
3814
3932
|
});
|
|
3815
|
-
const ListTemplatesDTOSchema = z.object({
|
|
3816
|
-
/** Bypass the cache — the refresh button. */
|
|
3817
|
-
refresh: z.boolean().optional() }).optional().default({});
|
|
3933
|
+
const ListTemplatesDTOSchema = z.object({ refresh: z.boolean().optional().describe("Bypass the cache and re-fetch the catalogue — what the refresh button does. Slower; leave it off for ordinary reads.") }).optional().default({});
|
|
3818
3934
|
//#endregion
|
|
3819
3935
|
//#region ../../packages/busabase-contract/src/domains/templates/contract.ts
|
|
3820
3936
|
/**
|
|
@@ -3919,6 +4035,7 @@ const vaultContract = {
|
|
|
3919
4035
|
//#region ../../packages/busabase-contract/src/domains/webhook/types.ts
|
|
3920
4036
|
const WebhookEventTypeSchema = z.enum([
|
|
3921
4037
|
"record.created",
|
|
4038
|
+
"record.updated",
|
|
3922
4039
|
"ai_mention",
|
|
3923
4040
|
"changes_requested",
|
|
3924
4041
|
"asset.uploaded"
|
|
@@ -4034,7 +4151,7 @@ const WebhookDeliveryVOSchema = z.object({
|
|
|
4034
4151
|
z.object({}).optional().default({});
|
|
4035
4152
|
const ListWebhookDeliveriesInputSchema = z.object({
|
|
4036
4153
|
ruleId: z.string(),
|
|
4037
|
-
limit: z.coerce.number().int().min(1).max(100).default(20)
|
|
4154
|
+
limit: z.coerce.number().int().min(1).max(100).default(20).describe("Delivery attempts to return, newest first.")
|
|
4038
4155
|
});
|
|
4039
4156
|
//#endregion
|
|
4040
4157
|
//#region ../../packages/busabase-contract/src/domains/webhook/contract.ts
|
|
@@ -4124,10 +4241,9 @@ const activityItemSchema = z.discriminatedUnion("kind", [
|
|
|
4124
4241
|
record: recordSchema.nullable()
|
|
4125
4242
|
})
|
|
4126
4243
|
]);
|
|
4127
|
-
/** Keyset page request: opaque base64 cursor (`ts|kind|id`) + page size. */
|
|
4128
4244
|
const listActivityPagedInputSchema = z.object({
|
|
4129
|
-
limit: z.coerce.number().int().min(1).max(100).optional().default(50),
|
|
4130
|
-
cursor: z.string().optional()
|
|
4245
|
+
limit: z.coerce.number().int().min(1).max(100).optional().default(50).describe("Items per page. Capped at 100; ask for the next page with `cursor`."),
|
|
4246
|
+
cursor: z.string().optional().describe("Opaque page cursor: pass back the `nextCursor` from the previous response. Do not construct or parse it.")
|
|
4131
4247
|
}).optional().default({ limit: 50 });
|
|
4132
4248
|
const listActivityResponseSchema = z.object({
|
|
4133
4249
|
items: z.array(activityItemSchema),
|
|
@@ -4135,13 +4251,13 @@ const listActivityResponseSchema = z.object({
|
|
|
4135
4251
|
});
|
|
4136
4252
|
/** Node-scoped raw activity stream request — offset/limit only, no cursor. */
|
|
4137
4253
|
const listNodeActivityInputSchema = z.object({
|
|
4138
|
-
nodeId: z.string().min(1),
|
|
4139
|
-
limit: z.coerce.number().int().min(1).max(100).optional().default(50)
|
|
4254
|
+
nodeId: z.string().min(1).describe("Activity is scoped to this node alone, not its subtree."),
|
|
4255
|
+
limit: z.coerce.number().int().min(1).max(100).optional().default(50).describe("Most recent events to return, capped at 100. This stream has NO cursor — it is a recent window, not a pageable history; use `/api/v1/activity/paged` to walk further back.")
|
|
4140
4256
|
});
|
|
4141
4257
|
/** Record-scoped raw activity stream request — same shape as node, keyed on recordId. */
|
|
4142
4258
|
const listRecordActivityInputSchema = z.object({
|
|
4143
|
-
recordId: z.string().min(1),
|
|
4144
|
-
limit: z.coerce.number().int().min(1).max(100).optional().default(50)
|
|
4259
|
+
recordId: z.string().min(1).describe("Activity for this record's own history."),
|
|
4260
|
+
limit: z.coerce.number().int().min(1).max(100).optional().default(50).describe("Most recent events to return, capped at 100. This stream has NO cursor — it is a recent window, not a pageable history; use `/api/v1/activity/paged` to walk further back.")
|
|
4145
4261
|
});
|
|
4146
4262
|
const EMBED_LINK_MAX_MINUTES = 1440;
|
|
4147
4263
|
const EmbedNodeTypeSchema = z.enum([
|
|
@@ -4220,8 +4336,8 @@ const CreateEmbedLinkInputSchema = z.object({
|
|
|
4220
4336
|
})
|
|
4221
4337
|
});
|
|
4222
4338
|
const ListEmbedLinksInputSchema = z.object({
|
|
4223
|
-
type: EmbedTargetTypeSchema.optional(),
|
|
4224
|
-
typeId: z.string().min(1).optional()
|
|
4339
|
+
type: EmbedTargetTypeSchema.optional().describe("Which kind of target the links point at. Omitting it returns links of every kind."),
|
|
4340
|
+
typeId: z.string().min(1).optional().describe("The target's id, interpreted according to `type`.")
|
|
4225
4341
|
}).optional().default({});
|
|
4226
4342
|
const RevokeEmbedLinkInputSchema = z.object({ id: z.string().min(1) });
|
|
4227
4343
|
const EmbedLinkVOSchema = z.object({
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region ../../packages/busabase-contract/src/domains/skill/frontmatter.ts
|
|
3
|
+
/**
|
|
4
|
+
* `SKILL.md` frontmatter — the generic shape, independent of Busabase.
|
|
5
|
+
*
|
|
6
|
+
* This used to live inside `domains/package/template.ts`, which encoded an
|
|
7
|
+
* assumption that no longer holds: that a Skill is a *part of* a template. Most
|
|
8
|
+
* Skills are not. A Skill is a directory with a `SKILL.md` an agent reads; it
|
|
9
|
+
* needs no `busabase.json`, ships no `content/`, and never installs into a
|
|
10
|
+
* workspace. Busabase's own `busabase-app-creator` is one.
|
|
11
|
+
*
|
|
12
|
+
* Modelling it only as a template component meant there was nowhere to hang
|
|
13
|
+
* checks for a plain Skill, so there were none. Hence its own file, in the
|
|
14
|
+
* domain it belongs to.
|
|
15
|
+
*
|
|
16
|
+
* `metadata` is deliberately open: a Skill carries whatever its ecosystem
|
|
17
|
+
* defines (categories, tags, risk labels, per-agent hints). The Busabase-specific
|
|
18
|
+
* block that decides template-ness is layered on in `domains/package/template.ts`
|
|
19
|
+
* — the template format knows about Skills, not the other way round.
|
|
20
|
+
*/
|
|
21
|
+
const SkillFrontmatterSchema$1 = z.object({
|
|
22
|
+
/** Identity. For a Skill inside a package this must equal the package name. */
|
|
23
|
+
name: z.string().min(1),
|
|
24
|
+
/**
|
|
25
|
+
* How an agent decides whether to reach for this Skill at all — so an empty one
|
|
26
|
+
* is not a cosmetic omission, it is a Skill that never gets picked.
|
|
27
|
+
*/
|
|
28
|
+
description: z.string().default(""),
|
|
29
|
+
metadata: z.object({}).passthrough().optional()
|
|
30
|
+
});
|
|
31
|
+
const TemplateAirAppRefSchema = z.object({
|
|
32
|
+
/** Slug of the `content/<dir>` holding the AirApp. */
|
|
33
|
+
slug: z.string().min(1),
|
|
34
|
+
role: z.enum([
|
|
35
|
+
"primary",
|
|
36
|
+
"admin",
|
|
37
|
+
"public",
|
|
38
|
+
"tool"
|
|
39
|
+
]),
|
|
40
|
+
label: z.string().optional()
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* Secrets the app expects to find in the Vault.
|
|
44
|
+
*
|
|
45
|
+
* DECLARED, never created: the package format has no slot for secret values and
|
|
46
|
+
* must not grow one (the same "you cannot leak what the format cannot express"
|
|
47
|
+
* rule the whole format is built on). Install surfaces these as a post-install
|
|
48
|
+
* prompt; the user fills them in the Vault themselves.
|
|
49
|
+
*/
|
|
50
|
+
const TemplateSecretSchema = z.object({
|
|
51
|
+
key: z.string().min(1),
|
|
52
|
+
description: z.string().default(""),
|
|
53
|
+
required: z.boolean().default(true)
|
|
54
|
+
});
|
|
55
|
+
z.object({
|
|
56
|
+
/** Template Center category, e.g. `"crm"`, `"email"`, `"content"`. */
|
|
57
|
+
category: z.string().min(1),
|
|
58
|
+
tags: z.array(z.string()).default([]),
|
|
59
|
+
/** Card/detail screenshots, package-relative (`assets/screenshots/overview.webp`). */
|
|
60
|
+
screenshots: z.array(z.string()).default([]),
|
|
61
|
+
/**
|
|
62
|
+
* Ready-made prompts shown after install ("Ask agent" prefills the first).
|
|
63
|
+
*
|
|
64
|
+
* They are the difference between a folder of tables and something a user can
|
|
65
|
+
* *use*: the point of a template is that the agent already knows the job, and
|
|
66
|
+
* these are how that is made visible rather than left for the user to guess.
|
|
67
|
+
*/
|
|
68
|
+
agentPrompts: z.array(z.string()).default([]),
|
|
69
|
+
/** Single-AirApp shorthand. Mutually exclusive with `airapps`. */
|
|
70
|
+
airapp: z.string().optional(),
|
|
71
|
+
/** Multi-AirApp form. Exactly one entry must have `role: "primary"`. */
|
|
72
|
+
airapps: z.array(TemplateAirAppRefSchema).optional(),
|
|
73
|
+
/**
|
|
74
|
+
* Bumped by the author when the declared resource shape changes.
|
|
75
|
+
*
|
|
76
|
+
* Part of the ownership stamp, so BOTH doors must agree on it: the installer
|
|
77
|
+
* writes it, and a skill's own `setup.mjs` compares against it to decide
|
|
78
|
+
* whether a node it finds is its own current shape or an older one to repair.
|
|
79
|
+
* Defaulted rather than required so an author who never versions their app
|
|
80
|
+
* still gets a stamp both sides recognise.
|
|
81
|
+
*/
|
|
82
|
+
schemaVersion: z.number().int().nonnegative().default(1),
|
|
83
|
+
vaultNamespace: z.string().optional(),
|
|
84
|
+
secrets: z.array(TemplateSecretSchema).default([]),
|
|
85
|
+
requires: z.object({ airapp: z.boolean().optional() }).default({})
|
|
86
|
+
});
|
|
87
|
+
const TemplateRiskLevelSchema = z.enum([
|
|
88
|
+
"gated-write",
|
|
89
|
+
"local-write",
|
|
90
|
+
"read-only",
|
|
91
|
+
"sandbox"
|
|
92
|
+
]);
|
|
93
|
+
/**
|
|
94
|
+
* `metadata.busabase` inside the root `SKILL.md`'s YAML frontmatter.
|
|
95
|
+
*
|
|
96
|
+
* `template: true` is an EXPLICIT opt-in, not an inference from "this skill
|
|
97
|
+
* happens to contain a package". Publishing a template means accepting that
|
|
98
|
+
* installers will run its AirApp code and feed its SKILL.md to their agent; that
|
|
99
|
+
* deserves a deliberate flag rather than a side effect of directory shape.
|
|
100
|
+
*/
|
|
101
|
+
const SkillBusabaseMetadataSchema = z.object({
|
|
102
|
+
template: z.boolean().default(false),
|
|
103
|
+
folderSlug: z.string().optional(),
|
|
104
|
+
/** Resource keys the manual talks about; each must exist under `content/`. */
|
|
105
|
+
resources: z.array(z.string()).default([]),
|
|
106
|
+
/**
|
|
107
|
+
* Free-form on purpose — see `parseTemplateRisk`. Validating this to the enum
|
|
108
|
+
* here would turn a stranger's typo or a retired term into a hard parse
|
|
109
|
+
* failure for the whole frontmatter, which is a worse outcome than a card
|
|
110
|
+
* that cannot show a risk badge.
|
|
111
|
+
*/
|
|
112
|
+
risk: z.string().optional()
|
|
113
|
+
});
|
|
114
|
+
SkillFrontmatterSchema$1.extend({ metadata: z.object({ busabase: SkillBusabaseMetadataSchema.optional() }).passthrough().optional() });
|
|
115
|
+
/** Stamp on every resource node (Base, Drive, AirApp, …) an app owns. */
|
|
116
|
+
const AppResourceOwnershipSchema = z.object({
|
|
117
|
+
appId: z.string().min(1),
|
|
118
|
+
/** Stable internal handle (`"contacts"`), NOT the installed slug. */
|
|
119
|
+
resourceKey: z.string().min(1),
|
|
120
|
+
schemaVersion: z.number().int().nonnegative()
|
|
121
|
+
});
|
|
122
|
+
/**
|
|
123
|
+
* The `resourceKey` reserved for an app's root Folder.
|
|
124
|
+
*
|
|
125
|
+
* `busabase-sdk` recognises an app's own Folder by looking for exactly this
|
|
126
|
+
* value (`ownsAppRoot`), so the installer must write it too — a Folder stamped
|
|
127
|
+
* with anything else reads as a stranger's, and the skill's own `setup.mjs`
|
|
128
|
+
* then refuses to touch its own workspace with `SETUP_CONFLICT`. Exported so
|
|
129
|
+
* neither side carries the string literal privately.
|
|
130
|
+
*/
|
|
131
|
+
const APP_ROOT_RESOURCE_KEY = "app-root";
|
|
132
|
+
AppResourceOwnershipSchema.extend({
|
|
133
|
+
resourceKey: z.literal(APP_ROOT_RESOURCE_KEY),
|
|
134
|
+
version: z.string().optional(),
|
|
135
|
+
source: z.object({
|
|
136
|
+
repo: z.string().optional(),
|
|
137
|
+
ref: z.string().optional(),
|
|
138
|
+
subdir: z.string().optional()
|
|
139
|
+
}).optional(),
|
|
140
|
+
installedAt: z.string().optional()
|
|
141
|
+
});
|
|
142
|
+
z.object({
|
|
143
|
+
appId: z.string().min(1),
|
|
144
|
+
["isTemplateSkill"]: z.literal(true)
|
|
145
|
+
});
|
|
146
|
+
//#endregion
|
|
147
|
+
export { TemplateRiskLevelSchema as n, APP_ROOT_RESOURCE_KEY as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "busabase-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.50.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",
|
|
@@ -67,9 +67,9 @@
|
|
|
67
67
|
"tsx": "^4.20.5",
|
|
68
68
|
"typescript": "^7.0.2",
|
|
69
69
|
"vitest": "^4.1.11",
|
|
70
|
-
"busabase-contract": "0.
|
|
71
|
-
"
|
|
72
|
-
"
|
|
70
|
+
"busabase-contract": "0.50.0",
|
|
71
|
+
"open-domains": "0.0.2",
|
|
72
|
+
"openlib": "0.1.1"
|
|
73
73
|
},
|
|
74
74
|
"engines": {
|
|
75
75
|
"node": ">=24.18.0"
|