@coffer-org/sdk 1.6.0 → 1.8.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.
@@ -0,0 +1,14 @@
1
+ import type { ColumnType } from '../fields.ts';
2
+ export interface ColumnConversion {
3
+ from: string[];
4
+ to: {
5
+ name: string;
6
+ type: ColumnType;
7
+ }[];
8
+ map(src: Record<string, unknown>): Record<string, unknown>;
9
+ }
10
+ export declare const URL_PARTS: readonly ["scheme", "username", "password", "host", "port", "path", "query", "hash"];
11
+ export declare function urlToLink(key: string): ColumnConversion;
12
+ export declare function linkToUrl(key: string): ColumnConversion;
13
+ export declare function scalarToArray(key: string): ColumnConversion;
14
+ export declare function arrayToScalar(key: string): ColumnConversion;
@@ -0,0 +1,79 @@
1
+ import { parseUrl, buildUrl } from "./url.js";
2
+ export const URL_PARTS = ['scheme', 'username', 'password', 'host', 'port', 'path', 'query', 'hash'];
3
+ const urlColumns = (key) => URL_PARTS.map((p) => ({ name: `${key}__${p}`, type: p === 'port' ? 'integer' : 'text' }));
4
+ function partsToValue(key, src) {
5
+ const v = {};
6
+ for (const p of URL_PARTS) {
7
+ const raw = src[`${key}__${p}`];
8
+ if (raw == null || raw === '')
9
+ continue;
10
+ if (p === 'port') {
11
+ const n = Number(raw);
12
+ if (Number.isFinite(n))
13
+ v.port = n;
14
+ }
15
+ else {
16
+ v[p] = String(raw);
17
+ }
18
+ }
19
+ return v;
20
+ }
21
+ export function urlToLink(key) {
22
+ return {
23
+ from: URL_PARTS.map((p) => `${key}__${p}`),
24
+ to: [{ name: key, type: 'text' }],
25
+ map: (src) => ({ [key]: buildUrl(partsToValue(key, src)) || null }),
26
+ };
27
+ }
28
+ export function linkToUrl(key) {
29
+ return {
30
+ from: [key],
31
+ to: urlColumns(key),
32
+ map: (src) => {
33
+ const raw = src[key];
34
+ const v = raw == null ? null : parseUrl(String(raw));
35
+ const out = {};
36
+ for (const p of URL_PARTS)
37
+ out[`${key}__${p}`] = v?.[p] ?? null;
38
+ return out;
39
+ },
40
+ };
41
+ }
42
+ export function scalarToArray(key) {
43
+ return {
44
+ from: [key],
45
+ to: [{ name: key, type: 'text' }],
46
+ map: (src) => {
47
+ const raw = src[key];
48
+ if (raw == null || raw === '')
49
+ return { [key]: null };
50
+ if (isJsonArray(raw))
51
+ return { [key]: raw };
52
+ return { [key]: JSON.stringify([raw]) };
53
+ },
54
+ };
55
+ }
56
+ export function arrayToScalar(key) {
57
+ return {
58
+ from: [key],
59
+ to: [{ name: key, type: 'text' }],
60
+ map: (src) => {
61
+ const raw = src[key];
62
+ if (raw == null || raw === '')
63
+ return { [key]: null };
64
+ if (!isJsonArray(raw))
65
+ return { [key]: raw };
66
+ try {
67
+ const arr = JSON.parse(String(raw));
68
+ const first = arr[0];
69
+ return { [key]: first == null ? null : typeof first === 'object' ? JSON.stringify(first) : first };
70
+ }
71
+ catch {
72
+ return { [key]: raw };
73
+ }
74
+ },
75
+ };
76
+ }
77
+ function isJsonArray(v) {
78
+ return typeof v === 'string' && v.trimStart().startsWith('[');
79
+ }
package/dist/fields.d.ts CHANGED
@@ -105,6 +105,7 @@ export interface FieldClient {
105
105
  export declare function group(o: {
106
106
  key?: string;
107
107
  label?: string;
108
+ icon?: string;
108
109
  fields: LayoutEl[];
109
110
  multiple?: boolean;
110
111
  required?: boolean;
@@ -115,34 +116,27 @@ export declare function group(o: {
115
116
  view?: {
116
117
  display?: GroupDisplay;
117
118
  kind?: string;
118
- icon?: string;
119
119
  };
120
120
  }): GroupEl;
121
121
  export declare function row(o: {
122
122
  label?: string;
123
+ icon?: string;
123
124
  fields: LayoutEl[];
124
- view?: {
125
- icon?: string;
126
- };
127
125
  }): GroupEl;
128
126
  export declare function table(o: {
129
127
  key: string;
130
128
  label: string;
129
+ icon?: string;
131
130
  fields: LayoutEl[];
132
131
  rules?: {
133
132
  unique?: string[];
134
133
  };
135
134
  required?: boolean;
136
- view?: {
137
- icon?: string;
138
- };
139
135
  }): GroupEl;
140
136
  export declare function sheet(o: {
141
137
  label?: string;
138
+ icon?: string;
142
139
  fields: LayoutEl[][];
143
- view?: {
144
- icon?: string;
145
- };
146
140
  }): GroupEl;
147
141
  export declare function url(o: {
148
142
  key: string;
@@ -153,15 +147,13 @@ type ContainerFactory = typeof row | typeof group | typeof table;
153
147
  export declare function keyed(o: {
154
148
  key: string;
155
149
  label: string;
150
+ icon?: string;
156
151
  container?: ContainerFactory;
157
152
  by: FieldItem;
158
153
  fields: LayoutEl[];
159
154
  fixed?: boolean;
160
155
  unique?: string[];
161
156
  required?: boolean;
162
- view?: {
163
- icon?: string;
164
- };
165
157
  }): GroupEl;
166
158
  export declare const isStorageGroup: (g: GroupEl) => boolean;
167
159
  export declare const isCollectionGroup: (g: GroupEl) => boolean;
@@ -208,6 +200,7 @@ export interface FieldMeta extends FieldClient {
208
200
  export declare function isJsonStored(field: FieldMeta | FieldClient): boolean;
209
201
  export { LANGUAGES, SEX_OPTIONS, WEEKDAY_OPTIONS } from './fields/constants.ts';
210
202
  export { parseUrl, buildUrl, hrefOf, type UrlValue } from './fields/url.ts';
203
+ export { URL_PARTS, urlToLink, linkToUrl, scalarToArray, arrayToScalar, type ColumnConversion, } from './fields/convert.ts';
211
204
  export declare function applyMultiple(base: FieldMeta, multiple: boolean): FieldMeta;
212
205
  export type StringOpts = FieldCoreOpts;
213
206
  export declare function string(o: StringOpts & {
package/dist/fields.js CHANGED
@@ -35,7 +35,7 @@ export function group(o) {
35
35
  required: o.required,
36
36
  unique: r.unique,
37
37
  label: o.label,
38
- icon: v.icon,
38
+ icon: o.icon,
39
39
  display: v.display ?? 'wrap',
40
40
  kind: v.kind,
41
41
  fixed: r.fixed,
@@ -43,17 +43,18 @@ export function group(o) {
43
43
  };
44
44
  }
45
45
  export function row(o) {
46
- return group({ label: o.label, fields: o.fields, view: { ...o.view, display: 'scroll' } });
46
+ return group({ label: o.label, icon: o.icon, fields: o.fields, view: { display: 'scroll' } });
47
47
  }
48
48
  export function table(o) {
49
49
  return group({
50
50
  key: o.key,
51
51
  label: o.label,
52
+ icon: o.icon,
52
53
  fields: o.fields,
53
54
  multiple: true,
54
55
  required: o.required,
55
56
  rules: o.rules,
56
- view: { ...o.view, display: 'table' },
57
+ view: { display: 'table' },
57
58
  });
58
59
  }
59
60
  export function sheet(o) {
@@ -63,7 +64,7 @@ export function sheet(o) {
63
64
  flat.push(brk());
64
65
  flat.push(...rowFields);
65
66
  });
66
- return group({ label: o.label, fields: flat, view: { ...o.view, display: 'sheet' } });
67
+ return group({ label: o.label, icon: o.icon, fields: flat, view: { display: 'sheet' } });
67
68
  }
68
69
  export function url(o) {
69
70
  return group({
@@ -87,7 +88,7 @@ export function keyed(o) {
87
88
  if (o.fixed && o.by.type.prim !== 'select')
88
89
  throw new Error(`[field.keyed] fixed requires by=select (enumerated), got '${o.by.type.prim}'`);
89
90
  const make = (o.container ?? group);
90
- const g = make({ label: o.label, fields: [o.by, ...o.fields], view: o.view });
91
+ const g = make({ label: o.label, icon: o.icon, fields: [o.by, ...o.fields] });
91
92
  return {
92
93
  ...g,
93
94
  key: o.key,
@@ -139,6 +140,7 @@ export function isJsonStored(field) {
139
140
  }
140
141
  export { LANGUAGES, SEX_OPTIONS, WEEKDAY_OPTIONS } from "./fields/constants.js";
141
142
  export { parseUrl, buildUrl, hrefOf } from "./fields/url.js";
143
+ export { URL_PARTS, urlToLink, linkToUrl, scalarToArray, arrayToScalar, } from "./fields/convert.js";
142
144
  function resolveDate(v) {
143
145
  return v === 'today' ? new Date().toISOString().slice(0, 10) : v;
144
146
  }
package/dist/shelf.d.ts CHANGED
@@ -43,6 +43,9 @@ export declare function inlineText(m: ShelfDef, row: Record<string, unknown>): s
43
43
  export declare function tableKeys(m: ShelfDef): string[];
44
44
  export declare function groupableFields(m: ShelfDef): string[];
45
45
  export declare function defaultGroupField(m: ShelfDef): string | undefined;
46
+ export declare function coverKey(m: ShelfDef): string | undefined;
47
+ export declare function listKeys(m: ShelfDef): string[];
48
+ export declare function storageColumnsFor(m: ShelfDef, keys: string[]): string[];
46
49
  export declare function buildShape(fields: LayoutEl[], partial: boolean): z.ZodRawShape;
47
50
  export declare function buildZodObject(m: ShelfDef): z.ZodTypeAny;
48
51
  export declare function buildZodObjectPartial(m: ShelfDef): z.ZodTypeAny;
package/dist/shelf.js CHANGED
@@ -132,6 +132,45 @@ export function defaultGroupField(m) {
132
132
  }
133
133
  return groupableFields(m)[0];
134
134
  }
135
+ export function coverKey(m) {
136
+ return fieldEntries(m.fields).find(([, f]) => f.kind === 'cover')?.[0];
137
+ }
138
+ export function listKeys(m) {
139
+ const fm = fieldMap(m.fields);
140
+ const out = [];
141
+ const add = (k) => {
142
+ if (!k || k === 'id' || out.includes(k))
143
+ return;
144
+ if (!fm[k] || fm[k].virtual)
145
+ return;
146
+ out.push(k);
147
+ };
148
+ add(titleKey(m));
149
+ tableKeys(m).forEach(add);
150
+ groupableFields(m).forEach(add);
151
+ inlineKeys(m).forEach(add);
152
+ add(inlineImageKey(m));
153
+ add(coverKey(m));
154
+ const sel = m.views?.select;
155
+ if (sel) {
156
+ add(sel.icon);
157
+ (Array.isArray(sel.title) ? sel.title : [sel.title]).forEach(add);
158
+ add(sel.subtitle);
159
+ }
160
+ return ['id', ...out];
161
+ }
162
+ export function storageColumnsFor(m, keys) {
163
+ const fm = fieldMap(m.fields);
164
+ const out = new Set(['id']);
165
+ for (const k of keys) {
166
+ const f = fm[k];
167
+ if (!f || f.virtual)
168
+ continue;
169
+ for (const [col] of storageColumns(k, f))
170
+ out.add(col);
171
+ }
172
+ return [...out];
173
+ }
135
174
  export function buildShape(fields, partial) {
136
175
  const shape = {};
137
176
  for (const it of fields) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coffer-org/sdk",
3
- "version": "1.6.0",
3
+ "version": "1.8.0",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=24"