@coffer-org/sdk 2.1.3 → 2.2.1

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/countries.js CHANGED
@@ -144,7 +144,12 @@ export const COUNTRIES = [
144
144
  { code: 'RW', name: 'Руанда', nameRu: 'Руанда', nameEn: 'Rwanda' },
145
145
  { code: 'KN', name: 'Сент-Кітс і Невіс', nameRu: 'Сент-Китс и Невис', nameEn: 'St. Kitts & Nevis' },
146
146
  { code: 'LC', name: 'Сент-Люсія', nameRu: 'Сент-Люсия', nameEn: 'St. Lucia' },
147
- { code: 'VC', name: 'Сент-Вінсент і Гренадіни', nameRu: 'Сент-Винсент и Гренадины', nameEn: 'St. Vincent & Grenadines' },
147
+ {
148
+ code: 'VC',
149
+ name: 'Сент-Вінсент і Гренадіни',
150
+ nameRu: 'Сент-Винсент и Гренадины',
151
+ nameEn: 'St. Vincent & Grenadines',
152
+ },
148
153
  { code: 'WS', name: 'Самоа', nameRu: 'Самоа', nameEn: 'Samoa' },
149
154
  { code: 'SM', name: 'Сан-Марино', nameRu: 'Сан-Марино', nameEn: 'San Marino' },
150
155
  { code: 'ST', name: 'Сан-Томе і Принсіпі', nameRu: 'Сан-Томе и Принсипи', nameEn: 'São Tomé & Príncipe' },
@@ -152,6 +152,22 @@ export declare function snippet(o: CodeOpts & {
152
152
  key?: undefined;
153
153
  value?: undefined;
154
154
  }): FieldMeta;
155
+ export declare const SOURCE_DEFAULT_MAX_BYTES = 262144;
156
+ export declare function isBinaryText(v: string): boolean;
157
+ export interface SourceOpts extends FieldCoreOpts {
158
+ label?: string;
159
+ }
160
+ export declare function source(o: SourceOpts & {
161
+ key: string;
162
+ }): FieldItem;
163
+ export declare function source(o: SourceOpts & {
164
+ value: unknown;
165
+ key?: undefined;
166
+ }): StaticEl;
167
+ export declare function source(o: SourceOpts & {
168
+ key?: undefined;
169
+ value?: undefined;
170
+ }): FieldMeta;
155
171
  export interface RatingOpts extends FieldCoreOpts {
156
172
  label?: string;
157
173
  }
@@ -242,6 +258,7 @@ export declare const presets: {
242
258
  tags: typeof tags;
243
259
  markdown: typeof markdown;
244
260
  snippet: typeof snippet;
261
+ source: typeof source;
245
262
  rating: typeof rating;
246
263
  duration: typeof duration;
247
264
  reminder: typeof reminder;
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { real, int, text, date, select, string, group, vmsg, jsonRefined, typeErr, optionalize, applyMultiple, wrapKey, normalizeOpts, } from "./fields.js";
2
+ import { real, int, text, date, select, string, group, vmsg, jsonRefined, typeErr, reqTypeErr, optionalize, applyMultiple, wrapKey, normalizeOpts, } from "./fields.js";
3
3
  export function email(raw) {
4
4
  const o = normalizeOpts(raw);
5
5
  const required = o.required ?? false;
@@ -71,11 +71,7 @@ export function internalOauthGrants(o) {
71
71
  label: o.label ?? o.key,
72
72
  multiple: true,
73
73
  view: { kind: 'internalOauthGrants' },
74
- fields: [
75
- string({ key: 'clientName' }),
76
- string({ key: 'createdAt' }),
77
- string({ key: 'lastUsedAt' }),
78
- ],
74
+ fields: [string({ key: 'clientName' }), string({ key: 'createdAt' }), string({ key: 'lastUsedAt' })],
79
75
  });
80
76
  }
81
77
  const SLUG_RE = /^[a-z0-9-]+$/;
@@ -164,24 +160,155 @@ export function link(raw) {
164
160
  const TEL_RE = /^\+?[\d\s()-]{4,}$/;
165
161
  const LINK_RE = /^([a-z][a-z0-9+.-]*:\/\/\S+|[\w-]+(\.[\w-]+)+(:\d+)?(\/\S*)?)$/i;
166
162
  const CSS_COLOR_NAMES = new Set([
167
- 'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure', 'beige', 'bisque', 'black', 'blanchedalmond', 'blue',
168
- 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse', 'chocolate', 'coral', 'cornflowerblue', 'cornsilk',
169
- 'crimson', 'cyan', 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgreen', 'darkgrey', 'darkkhaki',
170
- 'darkmagenta', 'darkolivegreen', 'darkorange', 'darkorchid', 'darkred', 'darksalmon', 'darkseagreen',
171
- 'darkslateblue', 'darkslategray', 'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink', 'deepskyblue',
172
- 'dimgray', 'dimgrey', 'dodgerblue', 'firebrick', 'floralwhite', 'forestgreen', 'fuchsia', 'gainsboro', 'ghostwhite',
173
- 'gold', 'goldenrod', 'gray', 'green', 'greenyellow', 'grey', 'honeydew', 'hotpink', 'indianred', 'indigo', 'ivory',
174
- 'khaki', 'lavender', 'lavenderblush', 'lawngreen', 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan',
175
- 'lightgoldenrodyellow', 'lightgray', 'lightgreen', 'lightgrey', 'lightpink', 'lightsalmon', 'lightseagreen',
176
- 'lightskyblue', 'lightslategray', 'lightslategrey', 'lightsteelblue', 'lightyellow', 'lime', 'limegreen', 'linen',
177
- 'magenta', 'maroon', 'mediumaquamarine', 'mediumblue', 'mediumorchid', 'mediumpurple', 'mediumseagreen',
178
- 'mediumslateblue', 'mediumspringgreen', 'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream',
179
- 'mistyrose', 'moccasin', 'navajowhite', 'navy', 'oldlace', 'olive', 'olivedrab', 'orange', 'orangered', 'orchid',
180
- 'palegoldenrod', 'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip', 'peachpuff', 'peru', 'pink', 'plum',
181
- 'powderblue', 'purple', 'rebeccapurple', 'red', 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown',
182
- 'seagreen', 'seashell', 'sienna', 'silver', 'skyblue', 'slateblue', 'slategray', 'slategrey', 'snow', 'springgreen',
183
- 'steelblue', 'tan', 'teal', 'thistle', 'tomato', 'turquoise', 'violet', 'wheat', 'white', 'whitesmoke', 'yellow',
184
- 'yellowgreen', 'transparent',
163
+ 'aliceblue',
164
+ 'antiquewhite',
165
+ 'aqua',
166
+ 'aquamarine',
167
+ 'azure',
168
+ 'beige',
169
+ 'bisque',
170
+ 'black',
171
+ 'blanchedalmond',
172
+ 'blue',
173
+ 'blueviolet',
174
+ 'brown',
175
+ 'burlywood',
176
+ 'cadetblue',
177
+ 'chartreuse',
178
+ 'chocolate',
179
+ 'coral',
180
+ 'cornflowerblue',
181
+ 'cornsilk',
182
+ 'crimson',
183
+ 'cyan',
184
+ 'darkblue',
185
+ 'darkcyan',
186
+ 'darkgoldenrod',
187
+ 'darkgray',
188
+ 'darkgreen',
189
+ 'darkgrey',
190
+ 'darkkhaki',
191
+ 'darkmagenta',
192
+ 'darkolivegreen',
193
+ 'darkorange',
194
+ 'darkorchid',
195
+ 'darkred',
196
+ 'darksalmon',
197
+ 'darkseagreen',
198
+ 'darkslateblue',
199
+ 'darkslategray',
200
+ 'darkslategrey',
201
+ 'darkturquoise',
202
+ 'darkviolet',
203
+ 'deeppink',
204
+ 'deepskyblue',
205
+ 'dimgray',
206
+ 'dimgrey',
207
+ 'dodgerblue',
208
+ 'firebrick',
209
+ 'floralwhite',
210
+ 'forestgreen',
211
+ 'fuchsia',
212
+ 'gainsboro',
213
+ 'ghostwhite',
214
+ 'gold',
215
+ 'goldenrod',
216
+ 'gray',
217
+ 'green',
218
+ 'greenyellow',
219
+ 'grey',
220
+ 'honeydew',
221
+ 'hotpink',
222
+ 'indianred',
223
+ 'indigo',
224
+ 'ivory',
225
+ 'khaki',
226
+ 'lavender',
227
+ 'lavenderblush',
228
+ 'lawngreen',
229
+ 'lemonchiffon',
230
+ 'lightblue',
231
+ 'lightcoral',
232
+ 'lightcyan',
233
+ 'lightgoldenrodyellow',
234
+ 'lightgray',
235
+ 'lightgreen',
236
+ 'lightgrey',
237
+ 'lightpink',
238
+ 'lightsalmon',
239
+ 'lightseagreen',
240
+ 'lightskyblue',
241
+ 'lightslategray',
242
+ 'lightslategrey',
243
+ 'lightsteelblue',
244
+ 'lightyellow',
245
+ 'lime',
246
+ 'limegreen',
247
+ 'linen',
248
+ 'magenta',
249
+ 'maroon',
250
+ 'mediumaquamarine',
251
+ 'mediumblue',
252
+ 'mediumorchid',
253
+ 'mediumpurple',
254
+ 'mediumseagreen',
255
+ 'mediumslateblue',
256
+ 'mediumspringgreen',
257
+ 'mediumturquoise',
258
+ 'mediumvioletred',
259
+ 'midnightblue',
260
+ 'mintcream',
261
+ 'mistyrose',
262
+ 'moccasin',
263
+ 'navajowhite',
264
+ 'navy',
265
+ 'oldlace',
266
+ 'olive',
267
+ 'olivedrab',
268
+ 'orange',
269
+ 'orangered',
270
+ 'orchid',
271
+ 'palegoldenrod',
272
+ 'palegreen',
273
+ 'paleturquoise',
274
+ 'palevioletred',
275
+ 'papayawhip',
276
+ 'peachpuff',
277
+ 'peru',
278
+ 'pink',
279
+ 'plum',
280
+ 'powderblue',
281
+ 'purple',
282
+ 'rebeccapurple',
283
+ 'red',
284
+ 'rosybrown',
285
+ 'royalblue',
286
+ 'saddlebrown',
287
+ 'salmon',
288
+ 'sandybrown',
289
+ 'seagreen',
290
+ 'seashell',
291
+ 'sienna',
292
+ 'silver',
293
+ 'skyblue',
294
+ 'slateblue',
295
+ 'slategray',
296
+ 'slategrey',
297
+ 'snow',
298
+ 'springgreen',
299
+ 'steelblue',
300
+ 'tan',
301
+ 'teal',
302
+ 'thistle',
303
+ 'tomato',
304
+ 'turquoise',
305
+ 'violet',
306
+ 'wheat',
307
+ 'white',
308
+ 'whitesmoke',
309
+ 'yellow',
310
+ 'yellowgreen',
311
+ 'transparent',
185
312
  ]);
186
313
  export function tag(raw) {
187
314
  const o = normalizeOpts(raw);
@@ -225,6 +352,34 @@ export function snippet(raw) {
225
352
  };
226
353
  return wrapKey(norm, meta);
227
354
  }
355
+ export const SOURCE_DEFAULT_MAX_BYTES = 262_144;
356
+ export function isBinaryText(v) {
357
+ return v.includes('\x00') || v.includes('�');
358
+ }
359
+ export function source(raw) {
360
+ const o = normalizeOpts(raw);
361
+ const required = o.required ?? false;
362
+ const ext = o.ext ?? 'txt';
363
+ const maxBytes = o.maxBytes ?? SOURCE_DEFAULT_MAX_BYTES;
364
+ const s = z.string(reqTypeErr()).superRefine((v, ctx) => {
365
+ if (isBinaryText(v)) {
366
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: vmsg('source_binary') });
367
+ return;
368
+ }
369
+ if (new TextEncoder().encode(v).length > maxBytes)
370
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: vmsg('source_too_large', { maxBytes }) });
371
+ });
372
+ const meta = {
373
+ kind: 'source',
374
+ label: o.label ?? '',
375
+ required,
376
+ prim: 'text',
377
+ column: 'text',
378
+ hints: { ext, maxBytes, noEditControl: true },
379
+ zod: optionalize(s, required),
380
+ };
381
+ return wrapKey(o, meta);
382
+ }
228
383
  export function rating(raw) {
229
384
  const o = normalizeOpts(raw);
230
385
  const required = o.required ?? false;
@@ -328,6 +483,7 @@ export const presets = {
328
483
  tags,
329
484
  markdown,
330
485
  snippet,
486
+ source,
331
487
  rating,
332
488
  duration,
333
489
  reminder,
@@ -13,6 +13,8 @@ export interface Rules {
13
13
  unique?: string[];
14
14
  fixed?: boolean;
15
15
  exts?: string[];
16
+ ext?: string;
17
+ maxBytes?: number;
16
18
  lead?: number;
17
19
  by?: FieldItem;
18
20
  }
@@ -66,6 +68,8 @@ export type NormalizedOpts = {
66
68
  unique?: string[];
67
69
  fixed?: boolean;
68
70
  exts?: string[];
71
+ ext?: string;
72
+ maxBytes?: number;
69
73
  lead?: number;
70
74
  by?: FieldItem;
71
75
  min?: number | string;
@@ -28,6 +28,8 @@ export function normalizeOpts(rawIn) {
28
28
  unique: r.unique,
29
29
  fixed: r.fixed,
30
30
  exts: r.exts,
31
+ ext: r.ext,
32
+ maxBytes: r.maxBytes,
31
33
  lead: r.lead,
32
34
  by: r.by,
33
35
  min: r.min,
package/dist/fields.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- export { vmsg, reqErr, typeErr, reqTypeErr, jsonRefined, optionalize, jsonValue, decodeVmsg, validateField } from './fields/validation.ts';
2
+ export { vmsg, reqErr, typeErr, reqTypeErr, jsonRefined, optionalize, jsonValue, decodeVmsg, validateField, } from './fields/validation.ts';
3
3
  import type { Condition } from './condition.ts';
4
4
  export type { Rules, View, FieldConfig } from './fields/normalize.ts';
5
5
  export { normalizeOpts } from './fields/normalize.ts';
@@ -355,7 +355,7 @@ export declare function triState(o: TriStateOpts & {
355
355
  value?: undefined;
356
356
  }): FieldMeta;
357
357
  export interface SelectOpts extends FieldCoreOpts {
358
- options?: FieldOptions;
358
+ options?: string | (OptionItem | string)[];
359
359
  }
360
360
  export declare function select(o: SelectOpts & {
361
361
  key: string;
package/dist/fields.js CHANGED
@@ -2,7 +2,7 @@ import { z } from 'zod';
2
2
  import { resolveUnits } from "./units.js";
3
3
  import { isCurrencyCode } from "./currencies.js";
4
4
  import { vmsg, reqErr, typeErr, reqTypeErr, jsonRefined, optionalize, jsonValue } from "./fields/validation.js";
5
- export { vmsg, reqErr, typeErr, reqTypeErr, jsonRefined, optionalize, jsonValue, decodeVmsg, validateField } from "./fields/validation.js";
5
+ export { vmsg, reqErr, typeErr, reqTypeErr, jsonRefined, optionalize, jsonValue, decodeVmsg, validateField, } from "./fields/validation.js";
6
6
  export { normalizeOpts } from "./fields/normalize.js";
7
7
  import { normalizeOpts } from "./fields/normalize.js";
8
8
  import { presets } from "./field-presets.js";
@@ -185,7 +185,13 @@ export function applyMultiple(base, multiple) {
185
185
  if (!multiple)
186
186
  return base;
187
187
  const s = multipleZod(base.zod);
188
- return { ...base, column: 'text', hints: { ...base.hints, multiple: true }, json: true, zod: optionalize(s, base.required) };
188
+ return {
189
+ ...base,
190
+ column: 'text',
191
+ hints: { ...base.hints, multiple: true },
192
+ json: true,
193
+ zod: optionalize(s, base.required),
194
+ };
189
195
  }
190
196
  export function string(raw) {
191
197
  const o = normalizeOpts(raw);
@@ -421,11 +427,14 @@ export function triState(raw) {
421
427
  };
422
428
  return wrapKey(o, meta);
423
429
  }
430
+ function toOptionItem(o) {
431
+ return typeof o === 'string' ? { value: o, title: o } : o;
432
+ }
424
433
  export function select(raw) {
425
434
  const o = normalizeOpts(raw);
426
435
  const required = o.required ?? false;
427
436
  const source = typeof o.options === 'string' ? o.options : null;
428
- const inlineOpts = Array.isArray(o.options) ? o.options : [];
437
+ const inlineOpts = Array.isArray(o.options) ? o.options.map(toOptionItem) : [];
429
438
  const s = inlineOpts.length > 0
430
439
  ? z.enum(inlineOpts.map((x) => x.value), { error: () => vmsg('enum') })
431
440
  : z.string(reqErr());
@@ -455,7 +464,10 @@ export function relation(raw) {
455
464
  });
456
465
  }
457
466
  else {
458
- s = z.coerce.number().int().positive({ message: vmsg('int') });
467
+ s = z.coerce
468
+ .number()
469
+ .int()
470
+ .positive({ message: vmsg('int') });
459
471
  }
460
472
  const meta = {
461
473
  kind: 'relation',
@@ -509,9 +521,7 @@ export function check(raw) {
509
521
  const required = o.required ?? false;
510
522
  const multiple = o.multiple ?? false;
511
523
  const slots = o.slots && o.slots.length > 0 ? o.slots : [''];
512
- const contentFields = o.fields?.length
513
- ? o.fields
514
- : [string({ key: 'text', label: 'core.fields.text' })];
524
+ const contentFields = o.fields?.length ? o.fields : [string({ key: 'text', label: 'core.fields.text' })];
515
525
  const contentKeys = new Set();
516
526
  for (const f of contentFields) {
517
527
  if (contentKeys.has(f.key))
@@ -525,7 +535,14 @@ export function check(raw) {
525
535
  const checkFields = slots.map((label, i) => boolean({ key: `check${i}`, label: label || 'core.fields.check' }));
526
536
  if (multiple) {
527
537
  const fields = [...checkFields, ...contentFields];
528
- return group({ key: o.key, label: o.label ?? o.key, multiple: true, required: required, fields, view: { kind: 'checklist' } });
538
+ return group({
539
+ key: o.key,
540
+ label: o.label ?? o.key,
541
+ multiple: true,
542
+ required: required,
543
+ fields,
544
+ view: { kind: 'checklist' },
545
+ });
529
546
  }
530
547
  const shape = {};
531
548
  const columns = {};
package/dist/shelf.d.ts CHANGED
@@ -24,6 +24,7 @@ export interface ShelfDef {
24
24
  icon?: string;
25
25
  claude?: string;
26
26
  standalone?: boolean;
27
+ single?: boolean;
27
28
  views?: ShelfViews;
28
29
  fields: LayoutEl[];
29
30
  }
package/dist/shelf.js CHANGED
@@ -68,7 +68,9 @@ export function defineShelf(m) {
68
68
  const dup = keys.find((k, i) => keys.indexOf(k) !== i);
69
69
  if (dup)
70
70
  throw new Error(`[shelf] ${m.library}/${m.shelf}: duplicate key '${dup}'`);
71
- if (m.standalone !== false && !m.views?.list?.fields?.length)
71
+ if (m.single && !m.claude)
72
+ throw new Error(`[shelf] ${m.library}/${m.shelf}: single shelf requires \`claude\` — the agent cannot find it otherwise`);
73
+ if (m.standalone !== false && !m.single && !m.views?.list?.fields?.length)
72
74
  console.warn(`[shelf] ${m.library}/${m.shelf}: standalone shelf without an explicit views.list`);
73
75
  return m;
74
76
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coffer-org/sdk",
3
- "version": "2.1.3",
3
+ "version": "2.2.1",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=24"