@checkcourt/sdk 0.9.0 → 0.11.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/README.md CHANGED
@@ -193,6 +193,36 @@ ui.form({
193
193
  });
194
194
  ```
195
195
 
196
+ Blocks can carry an `icon` from `UI_ICONS` (text, heading, stat, badge, list items), a `stat`
197
+ can be `size: "lg"`, badges have a soft amber `"warning"` variant, `ui.columns` lays out 2
198
+ to 6 children in equal widths, and `ui.row(children, { justify: "between" })` spreads a row
199
+ across the full width (first child left, last child right). A weather widget:
200
+
201
+ ```ts
202
+ const days = [
203
+ ["Heute", "sun", "24°"],
204
+ ["Do", "cloud-sun", "21°"],
205
+ ["Fr", "cloud-rain", "17°"],
206
+ ["Sa", "cloud-drizzle", "18°"],
207
+ ["So", "sun", "23°"],
208
+ ] as const;
209
+
210
+ ui.doc([
211
+ ui.row(
212
+ [
213
+ ui.stat("Jetzt", "24°", { icon: "sun", size: "lg", hint: "Sonnig" }),
214
+ ui.badge("Regen möglich", { variant: "warning", icon: "droplets" }),
215
+ ],
216
+ { justify: "between" },
217
+ ),
218
+ ui.divider(),
219
+ ui.columns(
220
+ days.map(([day, icon, temp]) => ui.stat(day, temp, { icon })),
221
+ { dividers: true, align: "center" },
222
+ ),
223
+ ]);
224
+ ```
225
+
196
226
  Compare `context.installation_id` and `context.tenant_id` with what you stored from
197
227
  `app.installed` before you act on a request. For the context token alone (for example in
198
228
  the backend of an iframe extension), use `verifyExtensionContext(token, secret)`.
@@ -246,6 +276,31 @@ if (ext.point === "nav.page") {
246
276
  }
247
277
  ```
248
278
 
279
+ #### Permissions for the club's roles
280
+
281
+ A club app can offer its own rights (at most `MAX_APP_PERMISSIONS`, keys matching
282
+ `APP_PERMISSION_KEY_PATTERN`). The club decides in its role editor which roles hold them; only
283
+ administrators hold them from the start. Every extension request carries the viewer's flags
284
+ for all declared keys in `viewer.capabilities.permissions`, and a `nav.page` with `requires`
285
+ is only listed and opened for holders:
286
+
287
+ ```ts
288
+ defineManifest({
289
+ installTargets: ["tenant"],
290
+ permissions: [{ key: "manage_ladder", label: "Rangliste verwalten", description: "Darf Ergebnisse korrigieren" }],
291
+ extensions: [
292
+ { point: "nav.page", kind: "declarative", url: "https://ladder.example.de/ext/admin", label: "Rangliste", icon: "trophy", requires: "manage_ladder" },
293
+ { point: "dashboard.widget", kind: "declarative", url: "https://ladder.example.de/ext/widget" },
294
+ ],
295
+ dataProcessing: { categories: ["Spielergebnisse"], purpose: "Führt die Rangliste", storageLocation: "EU", avvRequired: false },
296
+ });
297
+
298
+ const { context } = ext; // from verifyExtensionRequest, as above
299
+ if (context.viewer.capabilities.permissions?.manage_ladder) {
300
+ // show the edit buttons
301
+ }
302
+ ```
303
+
249
304
  ### OAuth with PKCE (member apps)
250
305
 
251
306
  ```ts
@@ -55,6 +55,14 @@ export interface PointCapabilities {
55
55
  "sidebar.action": Record<string, never>;
56
56
  "nav.page": Record<string, never>;
57
57
  }
58
+ /**
59
+ * Present at every point when the app's manifest declares `permissions`: each declared key with
60
+ * whether the viewer holds it (through a club role; administrators hold all). Absent otherwise.
61
+ * `false` at the kiosk, where nobody is signed in.
62
+ */
63
+ export interface AppPermissionCapabilities {
64
+ permissions?: Record<string, boolean>;
65
+ }
58
66
  export interface PointSubject {
59
67
  "app.settings": {
60
68
  type: "installation";
@@ -98,7 +106,7 @@ interface ContextClaimsOf<P extends ExtensionPoint> {
98
106
  viewer: {
99
107
  /** null on the kiosk; a stable `psn_…` pseudonym unless the installation holds `members:read`. */
100
108
  user_id: string | null;
101
- capabilities: PointCapabilities[P];
109
+ capabilities: PointCapabilities[P] & AppPermissionCapabilities;
102
110
  };
103
111
  iat: number;
104
112
  exp: number;
package/dist/iframe.d.ts CHANGED
@@ -6,7 +6,7 @@ export declare const MAX_TOAST_LENGTH = 200;
6
6
  /** Top-level areas `navigate()` may target; anything else is dropped by CheckCourt. */
7
7
  export declare const NAVIGABLE_SECTIONS: readonly ["dashboard", "booking", "my-bookings", "club", "team", "trainer", "fees", "arbeitsstunden", "settings", "admin"];
8
8
  /** CSS variables CheckCourt sends with every theme message. */
9
- export declare const THEME_TOKEN_NAMES: readonly ["--background", "--foreground", "--card", "--card-foreground", "--muted", "--muted-foreground", "--primary", "--primary-foreground", "--secondary", "--secondary-foreground", "--accent", "--accent-foreground", "--destructive", "--border", "--input", "--ring", "--radius"];
9
+ export declare const THEME_TOKEN_NAMES: readonly ["--background", "--foreground", "--card", "--card-foreground", "--muted", "--muted-foreground", "--primary", "--primary-foreground", "--secondary", "--secondary-foreground", "--accent", "--accent-foreground", "--destructive", "--warning", "--warning-foreground", "--warning-muted", "--border", "--input", "--ring", "--radius"];
10
10
  export type ThemeTokenName = (typeof THEME_TOKEN_NAMES)[number];
11
11
  export type FrameMessage = {
12
12
  type: "checkcourt:resize";
package/dist/iframe.js CHANGED
@@ -31,6 +31,9 @@ export const THEME_TOKEN_NAMES = [
31
31
  "--accent",
32
32
  "--accent-foreground",
33
33
  "--destructive",
34
+ "--warning",
35
+ "--warning-foreground",
36
+ "--warning-muted",
34
37
  "--border",
35
38
  "--input",
36
39
  "--ring",
@@ -86,6 +86,25 @@ export declare const STATIC_ACTION_LABEL_MAX = 24;
86
86
  /** Bounds of an iframe extension's initial `height` in pixels. */
87
87
  export declare const IFRAME_EXTENSION_HEIGHT_MIN = 120;
88
88
  export declare const IFRAME_EXTENSION_HEIGHT_MAX = 2000;
89
+ /** Keys of app permissions: lowercase letters, digits and `_`, starting with a letter, at most 40 characters. */
90
+ export declare const APP_PERMISSION_KEY_PATTERN: RegExp;
91
+ /** Most permissions one manifest may declare. */
92
+ export declare const MAX_APP_PERMISSIONS = 10;
93
+ export declare const APP_PERMISSION_LABEL_MAX = 60;
94
+ export declare const APP_PERMISSION_DESCRIPTION_MAX = 200;
95
+ /**
96
+ * A right the app offers the club's roles, e.g. who may manage its ladder. The club decides in
97
+ * its role editor which roles hold it; only administrators hold it from the start. Viewers' flags
98
+ * arrive as `viewer.capabilities.permissions` in the extension context.
99
+ */
100
+ export interface AppPermission {
101
+ /** Matches `APP_PERMISSION_KEY_PATTERN`, unique within the manifest. */
102
+ key: string;
103
+ /** Shown in the role editor, German, 1 to 60 characters, e.g. "Rangliste verwalten". */
104
+ label: string;
105
+ /** Up to 200 characters. */
106
+ description?: string;
107
+ }
89
108
  /** lucide icon names a static action or `nav.page` may use as `icon`. */
90
109
  export declare const APP_ACTION_ICONS: readonly ["bell", "calendar", "calendar-check", "camera", "chart-column", "circle-help", "clipboard-list", "clock", "cloud-rain", "door-open", "file-text", "flag", "heart-pulse", "info", "key-round", "lightbulb", "link", "list-checks", "lock-open", "map-pin", "megaphone", "message-square", "receipt", "send", "sparkles", "star", "sun", "thermometer", "ticket", "triangle-alert", "trophy", "user-round", "users", "wallet", "wrench"];
91
110
  export type AppActionIcon = (typeof APP_ACTION_ICONS)[number];
@@ -115,6 +134,11 @@ type ExtensionOf<P extends ExtensionPoint> = {
115
134
  /** Navigation entry and page title, 1 to 24 characters (`STATIC_ACTION_LABEL_MAX`). */
116
135
  label: string;
117
136
  icon: AppActionIcon;
137
+ /**
138
+ * Key of one of the manifest's `permissions`: only holders see the entry and may open
139
+ * the page; CheckCourt enforces it for the page and its actions.
140
+ */
141
+ requires?: string;
118
142
  } : P extends "booking.action" ? {
119
143
  label: string;
120
144
  icon?: never;
@@ -247,6 +271,8 @@ export interface Manifest {
247
271
  /** At most 20. */
248
272
  extensions?: readonly ManifestExtension[];
249
273
  settingsSchema?: SettingsSchema;
274
+ /** Rights the app offers the club's roles (at most 10). Club installations only. */
275
+ permissions?: readonly AppPermission[];
250
276
  dataProcessing: DataProcessing;
251
277
  /** Metadata other apps may read (at most 20). Club installations only. */
252
278
  shares?: {
package/dist/manifest.js CHANGED
@@ -41,6 +41,12 @@ export const STATIC_ACTION_LABEL_MAX = 24;
41
41
  /** Bounds of an iframe extension's initial `height` in pixels. */
42
42
  export const IFRAME_EXTENSION_HEIGHT_MIN = 120;
43
43
  export const IFRAME_EXTENSION_HEIGHT_MAX = 2000;
44
+ /** Keys of app permissions: lowercase letters, digits and `_`, starting with a letter, at most 40 characters. */
45
+ export const APP_PERMISSION_KEY_PATTERN = /^[a-z][a-z0-9_]{0,39}$/;
46
+ /** Most permissions one manifest may declare. */
47
+ export const MAX_APP_PERMISSIONS = 10;
48
+ export const APP_PERMISSION_LABEL_MAX = 60;
49
+ export const APP_PERMISSION_DESCRIPTION_MAX = 200;
44
50
  /** lucide icon names a static action or `nav.page` may use as `icon`. */
45
51
  export const APP_ACTION_ICONS = [
46
52
  "bell",
package/dist/ui.d.ts CHANGED
@@ -2,34 +2,55 @@ export declare const UI_VERSION = "v1";
2
2
  export declare const MAX_UI_BLOCKS = 50;
3
3
  /** Top-level blocks sit at depth 1; a container's children one deeper. */
4
4
  export declare const MAX_UI_DEPTH = 3;
5
- export declare const BADGE_VARIANTS: readonly ["default", "secondary", "outline", "destructive"];
5
+ export declare const BADGE_VARIANTS: readonly ["default", "secondary", "outline", "destructive", "warning"];
6
6
  export declare const BUTTON_VARIANTS: readonly ["default", "secondary", "outline", "destructive"];
7
7
  export type BadgeVariant = (typeof BADGE_VARIANTS)[number];
8
8
  export type ButtonVariant = (typeof BUTTON_VARIANTS)[number];
9
+ /** Icons a block may show, by lucide name; CheckCourt draws them in the text color at text size. */
10
+ export declare const UI_ICONS: readonly ["sun", "moon", "cloud", "cloud-sun", "cloud-moon", "cloud-sun-rain", "cloud-rain", "cloud-drizzle", "cloud-lightning", "cloud-snow", "cloud-fog", "snowflake", "wind", "droplet", "droplets", "umbrella", "thermometer", "sunrise", "sunset", "check", "x", "info", "alert-triangle", "triangle-alert", "alert-circle", "circle-alert", "clock", "calendar", "map-pin", "trophy", "users", "user", "lock", "unlock", "lock-open", "lightbulb", "zap", "euro", "star", "heart", "bell", "flag", "activity", "timer", "ticket", "door-open"];
11
+ export type UiIcon = (typeof UI_ICONS)[number];
12
+ /** `lg` shows the value as a large display figure, `md` (default) as a regular stat. */
13
+ export declare const STAT_SIZES: readonly ["md", "lg"];
14
+ export type StatSize = (typeof STAT_SIZES)[number];
15
+ export declare const COLUMNS_ALIGNMENTS: readonly ["start", "center"];
16
+ export type ColumnsAlignment = (typeof COLUMNS_ALIGNMENTS)[number];
17
+ /** `between` spreads a row's children across the full width, first at the left edge, last at the right. */
18
+ export declare const ROW_JUSTIFICATIONS: readonly ["start", "between"];
19
+ export type RowJustify = (typeof ROW_JUSTIFICATIONS)[number];
20
+ /** A `columns` block holds 2 to 6 children. */
21
+ export declare const MIN_COLUMNS = 2;
22
+ export declare const MAX_COLUMNS = 6;
9
23
  export type UiTextBlock = {
10
24
  type: "text";
11
25
  text: string;
12
26
  tone?: "muted";
27
+ icon?: UiIcon;
13
28
  };
14
29
  export type UiHeadingBlock = {
15
30
  type: "heading";
16
31
  text: string;
17
32
  level: 2 | 3;
33
+ icon?: UiIcon;
18
34
  };
35
+ /** With `icon`, the icon sits before the value. */
19
36
  export type UiStatBlock = {
20
37
  type: "stat";
21
38
  label: string;
22
39
  value: string;
23
40
  hint?: string;
41
+ icon?: UiIcon;
42
+ size?: StatSize;
24
43
  };
25
44
  export type UiBadgeBlock = {
26
45
  type: "badge";
27
46
  label: string;
28
47
  variant?: BadgeVariant;
48
+ icon?: UiIcon;
29
49
  };
30
50
  export type UiListItem = {
31
51
  title: string;
32
52
  description?: string;
53
+ icon?: UiIcon;
33
54
  };
34
55
  export type UiListBlock = {
35
56
  type: "list";
@@ -136,8 +157,16 @@ export type UiStackBlock = {
136
157
  export type UiRowBlock = {
137
158
  type: "row";
138
159
  children: UiBlock[];
160
+ justify?: RowJustify;
139
161
  };
140
- export type UiBlock = UiTextBlock | UiHeadingBlock | UiStatBlock | UiBadgeBlock | UiListBlock | UiKeyValueBlock | UiLinkBlock | UiButtonBlock | UiFormBlock | UiDividerBlock | UiStackBlock | UiRowBlock;
162
+ /** 2 to 6 children side by side in equal widths; on narrow cards 4 wrap to 2 per row, 5 and 6 to 3. */
163
+ export type UiColumnsBlock = {
164
+ type: "columns";
165
+ children: UiBlock[];
166
+ dividers?: boolean;
167
+ align?: ColumnsAlignment;
168
+ };
169
+ export type UiBlock = UiTextBlock | UiHeadingBlock | UiStatBlock | UiBadgeBlock | UiListBlock | UiKeyValueBlock | UiLinkBlock | UiButtonBlock | UiFormBlock | UiDividerBlock | UiStackBlock | UiRowBlock | UiColumnsBlock;
141
170
  export type UiToast = {
142
171
  kind: "success" | "error";
143
172
  message: string;
@@ -265,12 +294,23 @@ export declare const ui: {
265
294
  readonly hidden: (options?: UiDocumentOptions) => UiHiddenDocument;
266
295
  readonly text: (text: string, options?: {
267
296
  tone?: "muted";
297
+ icon?: UiIcon;
268
298
  }) => UiTextBlock;
269
- readonly heading: (text: string, level?: 2 | 3) => UiHeadingBlock;
299
+ /** `ui.heading(text, 3)` or `ui.heading(text, { level: 3, icon: "trophy" })`; level defaults to 2. */
300
+ readonly heading: (text: string, levelOrOptions?: 2 | 3 | {
301
+ level?: 2 | 3;
302
+ icon?: UiIcon;
303
+ }) => UiHeadingBlock;
270
304
  readonly stat: (label: string, value: string, options?: {
271
305
  hint?: string;
306
+ icon?: UiIcon;
307
+ size?: StatSize;
272
308
  }) => UiStatBlock;
273
- readonly badge: (label: string, variant?: BadgeVariant) => UiBadgeBlock;
309
+ /** `ui.badge(label, "warning")` or `ui.badge(label, { variant: "warning", icon: "droplets" })`. */
310
+ readonly badge: (label: string, variantOrOptions?: BadgeVariant | {
311
+ variant?: BadgeVariant;
312
+ icon?: UiIcon;
313
+ }) => UiBadgeBlock;
274
314
  readonly list: (items: UiListItem[]) => UiListBlock;
275
315
  /** Pairs keep their order; a plain object is turned into pairs in key order. */
276
316
  readonly keyValue: (pairs: UiKeyValuePair[] | Record<string, string>) => UiKeyValueBlock;
@@ -294,8 +334,15 @@ export declare const ui: {
294
334
  };
295
335
  readonly divider: () => UiDividerBlock;
296
336
  readonly stack: (children: UiBlock[]) => UiStackBlock;
297
- /** Horizontal, wraps on narrow screens. */
298
- readonly row: (children: UiBlock[]) => UiRowBlock;
337
+ /** Horizontal, wraps on narrow screens; `justify: "between"` pushes the last child to the right edge. */
338
+ readonly row: (children: UiBlock[], options?: {
339
+ justify?: RowJustify;
340
+ }) => UiRowBlock;
341
+ /** 2 to 6 equal-width columns, optionally with vertical dividers; throws on any other count. */
342
+ readonly columns: (children: UiBlock[], options?: {
343
+ dividers?: boolean;
344
+ align?: ColumnsAlignment;
345
+ }) => UiColumnsBlock;
299
346
  };
300
347
  /** Toasts for `ui.doc(blocks, { toast })`, at most 200 characters. */
301
348
  export declare const toast: {
package/dist/ui.js CHANGED
@@ -2,8 +2,65 @@ export const UI_VERSION = "v1";
2
2
  export const MAX_UI_BLOCKS = 50;
3
3
  /** Top-level blocks sit at depth 1; a container's children one deeper. */
4
4
  export const MAX_UI_DEPTH = 3;
5
- export const BADGE_VARIANTS = ["default", "secondary", "outline", "destructive"];
5
+ export const BADGE_VARIANTS = ["default", "secondary", "outline", "destructive", "warning"];
6
6
  export const BUTTON_VARIANTS = ["default", "secondary", "outline", "destructive"];
7
+ /** Icons a block may show, by lucide name; CheckCourt draws them in the text color at text size. */
8
+ export const UI_ICONS = [
9
+ "sun",
10
+ "moon",
11
+ "cloud",
12
+ "cloud-sun",
13
+ "cloud-moon",
14
+ "cloud-sun-rain",
15
+ "cloud-rain",
16
+ "cloud-drizzle",
17
+ "cloud-lightning",
18
+ "cloud-snow",
19
+ "cloud-fog",
20
+ "snowflake",
21
+ "wind",
22
+ "droplet",
23
+ "droplets",
24
+ "umbrella",
25
+ "thermometer",
26
+ "sunrise",
27
+ "sunset",
28
+ "check",
29
+ "x",
30
+ "info",
31
+ "alert-triangle",
32
+ "triangle-alert",
33
+ "alert-circle",
34
+ "circle-alert",
35
+ "clock",
36
+ "calendar",
37
+ "map-pin",
38
+ "trophy",
39
+ "users",
40
+ "user",
41
+ "lock",
42
+ "unlock",
43
+ "lock-open",
44
+ "lightbulb",
45
+ "zap",
46
+ "euro",
47
+ "star",
48
+ "heart",
49
+ "bell",
50
+ "flag",
51
+ "activity",
52
+ "timer",
53
+ "ticket",
54
+ "door-open",
55
+ ];
56
+ /** `lg` shows the value as a large display figure, `md` (default) as a regular stat. */
57
+ export const STAT_SIZES = ["md", "lg"];
58
+ export const COLUMNS_ALIGNMENTS = ["start", "center"];
59
+ /** `between` spreads a row's children across the full width, first at the left edge, last at the right. */
60
+ export const ROW_JUSTIFICATIONS = ["start", "between"];
61
+ /** A `columns` block holds 2 to 6 children. */
62
+ export const MIN_COLUMNS = 2;
63
+ export const MAX_COLUMNS = 6;
7
64
  /** CheckCourt caps every render lifetime at this many seconds. */
8
65
  export const UI_CACHE_MAX_AGE_LIMIT = 300;
9
66
  /** Longest badge label of a `court.annotation`. */
@@ -75,6 +132,14 @@ function variantOf(variant, what) {
75
132
  }
76
133
  return variant;
77
134
  }
135
+ function iconOf(icon) {
136
+ if (icon === undefined)
137
+ return undefined;
138
+ if (!UI_ICONS.includes(icon)) {
139
+ throw new TypeError(`Unknown icon ${String(icon)}; use one of UI_ICONS`);
140
+ }
141
+ return icon;
142
+ }
78
143
  function entriesOf(list, what) {
79
144
  if (!Array.isArray(list))
80
145
  throw new TypeError(`${what} must be an array`);
@@ -157,19 +222,31 @@ export const ui = {
157
222
  return compact({ ui: UI_VERSION, hidden: true, toast: options.toast, cache: cacheOf(options.maxAge) });
158
223
  },
159
224
  text(text, options = {}) {
160
- return compact({ type: "text", text, tone: options.tone });
225
+ return compact({ type: "text", text, tone: options.tone, icon: iconOf(options.icon) });
161
226
  },
162
- heading(text, level = 2) {
163
- return { type: "heading", text, level };
227
+ /** `ui.heading(text, 3)` or `ui.heading(text, { level: 3, icon: "trophy" })`; level defaults to 2. */
228
+ heading(text, levelOrOptions = 2) {
229
+ const options = typeof levelOrOptions === "object" ? levelOrOptions : { level: levelOrOptions };
230
+ return compact({ type: "heading", text, level: options.level ?? 2, icon: iconOf(options.icon) });
164
231
  },
165
232
  stat(label, value, options = {}) {
166
- return compact({ type: "stat", label, value, hint: options.hint });
233
+ if (options.size !== undefined && !STAT_SIZES.includes(options.size)) {
234
+ throw new TypeError(`stat size must be one of ${STAT_SIZES.join(", ")}`);
235
+ }
236
+ return compact({ type: "stat", label, value, hint: options.hint, icon: iconOf(options.icon), size: options.size });
167
237
  },
168
- badge(label, variant) {
169
- return compact({ type: "badge", label, variant });
238
+ /** `ui.badge(label, "warning")` or `ui.badge(label, { variant: "warning", icon: "droplets" })`. */
239
+ badge(label, variantOrOptions) {
240
+ const options = typeof variantOrOptions === "object" ? variantOrOptions : { variant: variantOrOptions };
241
+ return compact({
242
+ type: "badge",
243
+ label,
244
+ variant: variantOf(options.variant, "badge variant"),
245
+ icon: iconOf(options.icon),
246
+ });
170
247
  },
171
248
  list(items) {
172
- return { type: "list", items: items.map((item) => compact({ ...item })) };
249
+ return { type: "list", items: items.map((item) => compact({ ...item, icon: iconOf(item.icon) })) };
173
250
  },
174
251
  /** Pairs keep their order; a plain object is turned into pairs in key order. */
175
252
  keyValue(pairs) {
@@ -198,9 +275,22 @@ export const ui = {
198
275
  stack(children) {
199
276
  return { type: "stack", children };
200
277
  },
201
- /** Horizontal, wraps on narrow screens. */
202
- row(children) {
203
- return { type: "row", children };
278
+ /** Horizontal, wraps on narrow screens; `justify: "between"` pushes the last child to the right edge. */
279
+ row(children, options = {}) {
280
+ if (options.justify !== undefined && !ROW_JUSTIFICATIONS.includes(options.justify)) {
281
+ throw new TypeError(`row justify must be one of ${ROW_JUSTIFICATIONS.join(", ")}`);
282
+ }
283
+ return compact({ type: "row", children, justify: options.justify });
284
+ },
285
+ /** 2 to 6 equal-width columns, optionally with vertical dividers; throws on any other count. */
286
+ columns(children, options = {}) {
287
+ if (!Array.isArray(children) || children.length < MIN_COLUMNS || children.length > MAX_COLUMNS) {
288
+ throw new RangeError(`columns takes ${MIN_COLUMNS} to ${MAX_COLUMNS} children`);
289
+ }
290
+ if (options.align !== undefined && !COLUMNS_ALIGNMENTS.includes(options.align)) {
291
+ throw new TypeError(`columns align must be one of ${COLUMNS_ALIGNMENTS.join(", ")}`);
292
+ }
293
+ return compact({ type: "columns", children, dividers: options.dividers, align: options.align });
204
294
  },
205
295
  };
206
296
  /** Toasts for `ui.doc(blocks, { toast })`, at most 200 characters. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@checkcourt/sdk",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "Official TypeScript SDK for the CheckCourt app platform",
5
5
  "private": false,
6
6
  "license": "MIT",