@aglyn/plugins-data 1.0.0-beta.143

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +7 -0
  3. package/package.json +47 -0
  4. package/src/index.d.ts +19 -0
  5. package/src/index.js +20 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/components/data-console-page.d.ts +13 -0
  8. package/src/lib/components/data-console-page.js +63 -0
  9. package/src/lib/components/data-console-page.js.map +1 -0
  10. package/src/lib/components/dataset-record-dialog.component.d.ts +52 -0
  11. package/src/lib/components/dataset-record-dialog.component.js +249 -0
  12. package/src/lib/components/dataset-record-dialog.component.js.map +1 -0
  13. package/src/lib/components/dataset-schema-dialog.component.d.ts +51 -0
  14. package/src/lib/components/dataset-schema-dialog.component.js +979 -0
  15. package/src/lib/components/dataset-schema-dialog.component.js.map +1 -0
  16. package/src/lib/components/host-datasets-card.component.d.ts +39 -0
  17. package/src/lib/components/host-datasets-card.component.js +1831 -0
  18. package/src/lib/components/host-datasets-card.component.js.map +1 -0
  19. package/src/lib/constants/bundle-common.d.ts +8 -0
  20. package/src/lib/constants/bundle-common.js +9 -0
  21. package/src/lib/constants/bundle-common.js.map +1 -0
  22. package/src/lib/model/dataset-io.d.ts +43 -0
  23. package/src/lib/model/dataset-io.js +84 -0
  24. package/src/lib/model/dataset-io.js.map +1 -0
  25. package/src/lib/model/dataset-record-view.d.ts +157 -0
  26. package/src/lib/model/dataset-record-view.js +293 -0
  27. package/src/lib/model/dataset-record-view.js.map +1 -0
  28. package/src/lib/model/index.d.ts +22 -0
  29. package/src/lib/model/index.js +22 -0
  30. package/src/lib/model/index.js.map +1 -0
  31. package/src/lib/plugin.d.ts +35 -0
  32. package/src/lib/plugin.js +78 -0
  33. package/src/lib/plugin.js.map +1 -0
  34. package/src/lib/repeat/dataset-repeat-rows.d.ts +45 -0
  35. package/src/lib/repeat/dataset-repeat-rows.js +108 -0
  36. package/src/lib/repeat/dataset-repeat-rows.js.map +1 -0
  37. package/src/lib/repeat/dataset-repeat-source.d.ts +39 -0
  38. package/src/lib/repeat/dataset-repeat-source.js +95 -0
  39. package/src/lib/repeat/dataset-repeat-source.js.map +1 -0
@@ -0,0 +1,293 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ /**
3
+ * @license
4
+ * Copyright 2026 Aglyn LLC
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */ import { formatDatasetValue } from "@aglyn/aglyn/app-utils/dataset-models";
18
+ import { humanizeDatasetFieldId } from "@aglyn/aglyn/app-utils/datasets";
19
+ const NO_TEXT = {
20
+ text: '',
21
+ block: false
22
+ };
23
+ /** Firestore `Bytes`, `Uint8Array`, `Buffer` — anything holding raw octets. */ function byteLength(value) {
24
+ if (value instanceof Uint8Array) return value.byteLength;
25
+ if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {
26
+ return value.byteLength;
27
+ }
28
+ // Firestore's `Bytes` wrapper exposes its octets only through a method.
29
+ const asBytes = value;
30
+ if (typeof (asBytes == null ? void 0 : asBytes.toUint8Array) === 'function') {
31
+ try {
32
+ return asBytes.toUint8Array().byteLength;
33
+ } catch (unused) {
34
+ return null;
35
+ }
36
+ }
37
+ return null;
38
+ }
39
+ function describeBytes(value) {
40
+ const length = byteLength(value);
41
+ return {
42
+ kind: 'opaque',
43
+ text: length == null ? 'Binary value' : `Binary value · ${length} bytes`,
44
+ block: false
45
+ };
46
+ }
47
+ /**
48
+ * Nested structures, pretty-printed.
49
+ *
50
+ * A one-line `JSON.stringify` is what the table shows; a record view has the
51
+ * height to indent it, and an indented object is the difference between
52
+ * reading a nested value and squinting at one. A structure that will not
53
+ * serialize is reported as such rather than falling through to
54
+ * `String(value)`.
55
+ */ function describeStructure(value) {
56
+ try {
57
+ const text = JSON.stringify(value, null, 2);
58
+ // `undefined` in, `undefined` out — `JSON.stringify` answers that for a
59
+ // function or a symbol without throwing.
60
+ if (typeof text !== 'string') {
61
+ return {
62
+ kind: 'opaque',
63
+ text: 'Value cannot be displayed',
64
+ block: false
65
+ };
66
+ }
67
+ return {
68
+ kind: 'value',
69
+ text,
70
+ block: text.includes('\n')
71
+ };
72
+ } catch (unused) {
73
+ // A cycle, or a `toJSON` that throws.
74
+ return {
75
+ kind: 'opaque',
76
+ text: 'Value cannot be displayed',
77
+ block: false
78
+ };
79
+ }
80
+ }
81
+ /**
82
+ * A list's items, kept apart instead of joined.
83
+ *
84
+ * The join `formatDatasetValue` performs is lossy: `['a, b']` and
85
+ * `['a', 'b']` render to the identical string, so a reader cannot tell a
86
+ * one-item list holding a comma from a two-item list. One line per item
87
+ * removes the ambiguity, and `text` keeps the joined form for a flattened
88
+ * context such as a copy to the clipboard.
89
+ *
90
+ * An item that is itself a structure is serialized on its own; a list of
91
+ * objects reads as a list of objects rather than as `[object Object]`
92
+ * repeated.
93
+ */ function describeList(field, value) {
94
+ const items = value.map((item)=>{
95
+ if (typeof item === 'string') return item;
96
+ if (item === null) return 'null';
97
+ if (typeof item === 'object') {
98
+ const described = describeStructure(item);
99
+ return described.kind === 'value' ? described.text : described.text;
100
+ }
101
+ return String(item);
102
+ });
103
+ return {
104
+ kind: 'value',
105
+ text: field ? formatDatasetValue(field, value) : items.join(', '),
106
+ block: false,
107
+ items
108
+ };
109
+ }
110
+ /**
111
+ * The reference field's targets, each carrying whether it resolved.
112
+ *
113
+ * Both storage shapes flatten to the same list — a single ID string, or the
114
+ * `sorted` array a `multiple` reference holds — because the question asked of
115
+ * each entry is the same one.
116
+ */ function describeReference(fieldId, value, resolve) {
117
+ const raw = Array.isArray(value) ? value : [
118
+ value
119
+ ];
120
+ const references = raw.map((entry)=>typeof entry === 'string' ? entry.trim() : '').filter((id)=>id.length > 0).map((id)=>{
121
+ var _ref;
122
+ return {
123
+ id,
124
+ label: (_ref = resolve == null ? void 0 : resolve(fieldId, id)) != null ? _ref : null
125
+ };
126
+ });
127
+ if (!references.length) {
128
+ // An array that held nothing but blanks is an empty list, not a value;
129
+ // a non-string entry never was a reference and is reported by
130
+ // `validateDocument`, which the record view runs alongside this.
131
+ return _extends({
132
+ kind: Array.isArray(value) ? 'empty-list' : 'null'
133
+ }, NO_TEXT);
134
+ }
135
+ return {
136
+ kind: 'value',
137
+ // The label where there is one, the bare ID where there is not. The
138
+ // renderer marks the unresolved entries; this text is the fallback for
139
+ // anywhere the structure is flattened, such as a copy to the clipboard.
140
+ text: references.map((reference)=>{
141
+ var _reference_label;
142
+ return (_reference_label = reference.label) != null ? _reference_label : reference.id;
143
+ }).join(', '),
144
+ block: false,
145
+ references
146
+ };
147
+ }
148
+ /**
149
+ * What one field of one record holds, as a descriptor the renderer can be
150
+ * honest with.
151
+ *
152
+ * `values` and `fieldId` are taken separately rather than as one already-read
153
+ * value because "the key is missing" and "the key is present and empty" are
154
+ * two of the states being distinguished, and a read value cannot tell them
155
+ * apart.
156
+ *
157
+ * `field` may be undefined — a stored value the model does not declare. The
158
+ * value is then described from its own runtime shape, since there is no
159
+ * declared type to describe it by.
160
+ */ export function describeDatasetValue(field, values, fieldId, resolve) {
161
+ const present = values != null && Object.prototype.hasOwnProperty.call(values, fieldId) && values[fieldId] !== undefined;
162
+ if (!present) return _extends({
163
+ kind: 'absent'
164
+ }, NO_TEXT);
165
+ const value = values[fieldId];
166
+ if (value === null) return _extends({
167
+ kind: 'null'
168
+ }, NO_TEXT);
169
+ if (value === '') return _extends({
170
+ kind: 'empty-text'
171
+ }, NO_TEXT);
172
+ if (Array.isArray(value) && value.length === 0) {
173
+ return _extends({
174
+ kind: 'empty-list'
175
+ }, NO_TEXT);
176
+ }
177
+ if ((field == null ? void 0 : field.type) === 'reference') {
178
+ return describeReference(fieldId, value, resolve);
179
+ }
180
+ if ((field == null ? void 0 : field.type) === 'bytes') return describeBytes(value);
181
+ // An object with no keys is an empty map whether or not the model says
182
+ // `map` — an undeclared field has no declared type to consult.
183
+ const plainObject = typeof value === 'object' && !Array.isArray(value) && byteLength(value) == null;
184
+ if (plainObject && Object.keys(value).length === 0) {
185
+ return _extends({
186
+ kind: 'empty-map'
187
+ }, NO_TEXT);
188
+ }
189
+ // Raw octets stored against a field the model does not declare as `bytes`.
190
+ if (typeof value === 'object' && byteLength(value) != null) {
191
+ return describeBytes(value);
192
+ }
193
+ // A list is rendered per item rather than joined. An array stored against a
194
+ // field declared `map` is not one — `validateDocument` reports the mismatch
195
+ // and the value is pretty-printed as the structure it is.
196
+ if (Array.isArray(value) && (!field || field.type === 'sorted')) {
197
+ return describeList(field, value);
198
+ }
199
+ if (field) {
200
+ // `map` is the only declared type `formatDatasetValue` serializes, and it
201
+ // serializes to one line. Everything else it formats is already the short
202
+ // form a record view wants.
203
+ if (field.type === 'map') return describeStructure(value);
204
+ const text = formatDatasetValue(field, value);
205
+ // A non-empty value that formats to nothing would print as a blank line
206
+ // and read as an empty string. `formatDatasetValue` returns `''` only for
207
+ // the states already handled above, so this is a guard against a future
208
+ // formatter, not a state reachable today.
209
+ if (text === '') return {
210
+ kind: 'opaque',
211
+ text: 'Value cannot be displayed',
212
+ block: false
213
+ };
214
+ return {
215
+ kind: 'value',
216
+ text,
217
+ block: false
218
+ };
219
+ }
220
+ // Undeclared: describe the runtime shape rather than guessing a type.
221
+ if (typeof value === 'object') return describeStructure(value);
222
+ if (typeof value === 'boolean') {
223
+ return {
224
+ kind: 'value',
225
+ text: value ? 'true' : 'false',
226
+ block: false
227
+ };
228
+ }
229
+ if (typeof value === 'number' || typeof value === 'string') {
230
+ return {
231
+ kind: 'value',
232
+ text: String(value),
233
+ block: false
234
+ };
235
+ }
236
+ return {
237
+ kind: 'opaque',
238
+ text: 'Value cannot be displayed',
239
+ block: false
240
+ };
241
+ }
242
+ /**
243
+ * Every field of a record, in reading order: the model's declared order
244
+ * first, then anything the model declares but does not display, then every
245
+ * stored value the model does not declare at all.
246
+ *
247
+ * The union is the point. `model.order` is what the table's columns are built
248
+ * from, so a view built from `order` alone would be a wider row rather than
249
+ * the record — it would silently omit a reference field declared without a
250
+ * display slot, and every value left behind by a field the model no longer
251
+ * has. Both are real states of a stored document, and a viewer that drops
252
+ * them tells the reader the record is smaller than it is.
253
+ */ export function datasetRecordFields(model, values, resolve) {
254
+ var _model_order, _model_fields;
255
+ const order = (_model_order = model.order) != null ? _model_order : [];
256
+ const declared = (_model_fields = model.fields) != null ? _model_fields : {};
257
+ const seen = new Set();
258
+ const fields = [];
259
+ const pushDeclared = (fieldId)=>{
260
+ var _field_validation;
261
+ if (seen.has(fieldId)) return;
262
+ const field = declared[fieldId];
263
+ if (!field) return;
264
+ seen.add(fieldId);
265
+ fields.push(_extends({
266
+ fieldId,
267
+ label: field.name || humanizeDatasetFieldId(fieldId),
268
+ type: field.type
269
+ }, field.description ? {
270
+ description: field.description
271
+ } : {}, field.required || ((_field_validation = field.validation) == null ? void 0 : _field_validation.required) ? {
272
+ required: true
273
+ } : {}, {
274
+ source: 'model',
275
+ value: describeDatasetValue(field, values, fieldId, resolve)
276
+ }));
277
+ };
278
+ for (const fieldId of order)pushDeclared(fieldId);
279
+ for (const fieldId of Object.keys(declared))pushDeclared(fieldId);
280
+ for (const fieldId of Object.keys(values != null ? values : {})){
281
+ if (seen.has(fieldId)) continue;
282
+ seen.add(fieldId);
283
+ fields.push({
284
+ fieldId,
285
+ label: humanizeDatasetFieldId(fieldId),
286
+ source: 'extra',
287
+ value: describeDatasetValue(undefined, values, fieldId, resolve)
288
+ });
289
+ }
290
+ return fields;
291
+ }
292
+
293
+ //# sourceMappingURL=dataset-record-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/data/src/lib/model/dataset-record-view.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n type DatasetFieldDefinition,\n type DatasetFieldType,\n type DatasetModel,\n formatDatasetValue,\n} from '@aglyn/aglyn/app-utils/dataset-models'\nimport { humanizeDatasetFieldId } from '@aglyn/aglyn/app-utils/datasets'\n\n/**\n * Reading a whole record, as opposed to skimming a row of it.\n *\n * `formatDatasetValue` is the GRID formatter and is right for a grid: it\n * answers one short string per cell, and every state that has no short string\n * collapses to `''`, which the table then prints as `--`. A cell is one line\n * tall and one column wide, so that collapse is the only affordable answer.\n *\n * A record view has room to be exact, and the difference matters as soon as\n * anybody acts on what they read:\n *\n * * A field the record does not carry AT ALL, a field storing `null`, and a\n * field storing a real empty string are three different facts. They all\n * format to `''` and print as `--`. \"The address is blank\" and \"this\n * record predates the address field\" are not the same finding, and a CSV\n * export makes the difference visible where the table did not.\n * * A reference whose target cannot be resolved formats as the raw target\n * ID, which is indistinguishable from a resolved reference whose label\n * happens to look like an ID. One is a working link, the other is a\n * dangling one — a `setNull` that never ran, a target outside the picker's\n * window, or a record pointing at a deleted document.\n * * `bytes` reaches `String(value)`. A `Uint8Array` prints as its comma-\n * joined byte values and a Firestore `Bytes` prints `[object Object]`.\n * Neither is the value; both look like one.\n * * A `map` whose value cannot be serialized (a cycle) falls through\n * `JSON.stringify`'s throw to `String(value)`, which is `[object Object]`\n * again — a placeholder wearing the costume of data.\n *\n * So this module answers with a DESCRIPTOR rather than a string, and the\n * renderer decides how each state should look. Nothing here formats a value\n * a second time: a real value's text still comes from `formatDatasetValue`,\n * so the record view and the table can never disagree about one.\n */\n\n/** What a field slot actually holds — the four \"no value\" states are distinct. */\nexport type DatasetDisplayKind =\n /** The record has no such key. */\n | 'absent'\n /** The key is present and stores `null`. */\n | 'null'\n /** A real, stored empty string. */\n | 'empty-text'\n /** A real, stored empty array. */\n | 'empty-list'\n /** A real, stored empty object. */\n | 'empty-map'\n /** A value, rendered in `text`. */\n | 'value'\n /**\n * A value that exists and cannot be shown honestly as text — binary, or a\n * structure that will not serialize. `text` says which, and says so as a\n * description of the value rather than as the value.\n */\n | 'opaque'\n\n/** One target of a reference field, and whether it could be resolved. */\nexport interface DatasetDisplayReference {\n id: string\n /**\n * The target's display label, or `null` when this ID resolved to nothing.\n * An unresolved reference is not an error to hide: the ID is still shown,\n * marked as unresolved, because the ID is the only fact available.\n */\n label: string | null\n}\n\nexport interface DatasetDisplayValue {\n kind: DatasetDisplayKind\n /**\n * The rendered value for `value`, and the reason for `opaque`. Empty for\n * every other kind — those carry no text of their own, and the renderer\n * supplies the placeholder so a placeholder can never be mistaken for\n * stored content.\n */\n text: string\n /**\n * Pre-formatted across several lines. Nested JSON is pretty-printed, which\n * is only readable in a block that preserves its whitespace.\n */\n block: boolean\n /** Present only for a `reference` field, one entry per target ID. */\n references?: DatasetDisplayReference[]\n /**\n * A list field's items, one entry each.\n *\n * `formatDatasetValue` joins a `sorted` array with `\", \"`, which is the only\n * thing a cell has room for and is ambiguous in both directions: the\n * one-item list `['a, b']` and the two-item list `['a', 'b']` produce the\n * same string, and nothing in it says which was stored. A record view has a\n * line per item, so it renders the items rather than the join. `text` keeps\n * the joined form for anywhere the structure is flattened.\n */\n items?: string[]\n}\n\n/** A field slot in a record view: what it is called, and what it holds. */\nexport interface DatasetRecordField {\n fieldId: string\n /** Display label — the model's name, or a humanized ID for an extra. */\n label: string\n /** The declared type; absent for a stored value the model does not declare. */\n type?: DatasetFieldType\n description?: string\n required?: boolean\n /**\n * `extra` marks a stored value with no field in the model. It is not\n * corruption and not rare: a type or field removed from a model never\n * rewrites documents (the record editor strips orphans lazily, on the next\n * save), and the import and API legs accept any key the model names at the\n * time of the write. The table cannot show these — its columns come from\n * the model — which is exactly why a record view must.\n */\n source: 'model' | 'extra'\n value: DatasetDisplayValue\n}\n\n/** Resolves one reference target to its label, or `null` when unresolved. */\nexport type DatasetReferenceResolver = (\n fieldId: string,\n id: string,\n) => string | null\n\nconst NO_TEXT = { text: '', block: false } as const\n\n/** Firestore `Bytes`, `Uint8Array`, `Buffer` — anything holding raw octets. */\nfunction byteLength(value: unknown): number | null {\n if (value instanceof Uint8Array) return value.byteLength\n if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {\n return value.byteLength\n }\n // Firestore's `Bytes` wrapper exposes its octets only through a method.\n const asBytes = value as { toUint8Array?: () => Uint8Array }\n if (typeof asBytes?.toUint8Array === 'function') {\n try {\n return asBytes.toUint8Array().byteLength\n } catch {\n return null\n }\n }\n return null\n}\n\nfunction describeBytes(value: unknown): DatasetDisplayValue {\n const length = byteLength(value)\n return {\n kind: 'opaque',\n text: length == null ? 'Binary value' : `Binary value · ${length} bytes`,\n block: false,\n }\n}\n\n/**\n * Nested structures, pretty-printed.\n *\n * A one-line `JSON.stringify` is what the table shows; a record view has the\n * height to indent it, and an indented object is the difference between\n * reading a nested value and squinting at one. A structure that will not\n * serialize is reported as such rather than falling through to\n * `String(value)`.\n */\nfunction describeStructure(value: unknown): DatasetDisplayValue {\n try {\n const text = JSON.stringify(value, null, 2)\n // `undefined` in, `undefined` out — `JSON.stringify` answers that for a\n // function or a symbol without throwing.\n if (typeof text !== 'string') {\n return { kind: 'opaque', text: 'Value cannot be displayed', block: false }\n }\n return { kind: 'value', text, block: text.includes('\\n') }\n } catch {\n // A cycle, or a `toJSON` that throws.\n return { kind: 'opaque', text: 'Value cannot be displayed', block: false }\n }\n}\n\n/**\n * A list's items, kept apart instead of joined.\n *\n * The join `formatDatasetValue` performs is lossy: `['a, b']` and\n * `['a', 'b']` render to the identical string, so a reader cannot tell a\n * one-item list holding a comma from a two-item list. One line per item\n * removes the ambiguity, and `text` keeps the joined form for a flattened\n * context such as a copy to the clipboard.\n *\n * An item that is itself a structure is serialized on its own; a list of\n * objects reads as a list of objects rather than as `[object Object]`\n * repeated.\n */\nfunction describeList(\n field: DatasetFieldDefinition | undefined,\n value: unknown[],\n): DatasetDisplayValue {\n const items = value.map((item) => {\n if (typeof item === 'string') return item\n if (item === null) return 'null'\n if (typeof item === 'object') {\n const described = describeStructure(item)\n return described.kind === 'value' ? described.text : described.text\n }\n return String(item)\n })\n return {\n kind: 'value',\n text: field ? formatDatasetValue(field, value) : items.join(', '),\n block: false,\n items,\n }\n}\n\n/**\n * The reference field's targets, each carrying whether it resolved.\n *\n * Both storage shapes flatten to the same list — a single ID string, or the\n * `sorted` array a `multiple` reference holds — because the question asked of\n * each entry is the same one.\n */\nfunction describeReference(\n fieldId: string,\n value: unknown,\n resolve: DatasetReferenceResolver | undefined,\n): DatasetDisplayValue {\n const raw = Array.isArray(value) ? value : [value]\n const references: DatasetDisplayReference[] = raw\n .map((entry) => (typeof entry === 'string' ? entry.trim() : ''))\n .filter((id) => id.length > 0)\n .map((id) => ({ id, label: resolve?.(fieldId, id) ?? null }))\n if (!references.length) {\n // An array that held nothing but blanks is an empty list, not a value;\n // a non-string entry never was a reference and is reported by\n // `validateDocument`, which the record view runs alongside this.\n return { kind: Array.isArray(value) ? 'empty-list' : 'null', ...NO_TEXT }\n }\n return {\n kind: 'value',\n // The label where there is one, the bare ID where there is not. The\n // renderer marks the unresolved entries; this text is the fallback for\n // anywhere the structure is flattened, such as a copy to the clipboard.\n text: references\n .map((reference) => reference.label ?? reference.id)\n .join(', '),\n block: false,\n references,\n }\n}\n\n/**\n * What one field of one record holds, as a descriptor the renderer can be\n * honest with.\n *\n * `values` and `fieldId` are taken separately rather than as one already-read\n * value because \"the key is missing\" and \"the key is present and empty\" are\n * two of the states being distinguished, and a read value cannot tell them\n * apart.\n *\n * `field` may be undefined — a stored value the model does not declare. The\n * value is then described from its own runtime shape, since there is no\n * declared type to describe it by.\n */\nexport function describeDatasetValue(\n field: DatasetFieldDefinition | undefined,\n values: Record<string, unknown> | undefined,\n fieldId: string,\n resolve?: DatasetReferenceResolver,\n): DatasetDisplayValue {\n const present =\n values != null &&\n Object.prototype.hasOwnProperty.call(values, fieldId) &&\n values[fieldId] !== undefined\n if (!present) return { kind: 'absent', ...NO_TEXT }\n const value = values[fieldId]\n if (value === null) return { kind: 'null', ...NO_TEXT }\n if (value === '') return { kind: 'empty-text', ...NO_TEXT }\n if (Array.isArray(value) && value.length === 0) {\n return { kind: 'empty-list', ...NO_TEXT }\n }\n\n if (field?.type === 'reference') {\n return describeReference(fieldId, value, resolve)\n }\n if (field?.type === 'bytes') return describeBytes(value)\n\n // An object with no keys is an empty map whether or not the model says\n // `map` — an undeclared field has no declared type to consult.\n const plainObject =\n typeof value === 'object' &&\n !Array.isArray(value) &&\n byteLength(value) == null\n if (plainObject && Object.keys(value as object).length === 0) {\n return { kind: 'empty-map', ...NO_TEXT }\n }\n // Raw octets stored against a field the model does not declare as `bytes`.\n if (typeof value === 'object' && byteLength(value) != null) {\n return describeBytes(value)\n }\n // A list is rendered per item rather than joined. An array stored against a\n // field declared `map` is not one — `validateDocument` reports the mismatch\n // and the value is pretty-printed as the structure it is.\n if (Array.isArray(value) && (!field || field.type === 'sorted')) {\n return describeList(field, value)\n }\n\n if (field) {\n // `map` is the only declared type `formatDatasetValue` serializes, and it\n // serializes to one line. Everything else it formats is already the short\n // form a record view wants.\n if (field.type === 'map') return describeStructure(value)\n const text = formatDatasetValue(field, value)\n // A non-empty value that formats to nothing would print as a blank line\n // and read as an empty string. `formatDatasetValue` returns `''` only for\n // the states already handled above, so this is a guard against a future\n // formatter, not a state reachable today.\n if (text === '')\n return { kind: 'opaque', text: 'Value cannot be displayed', block: false }\n return { kind: 'value', text, block: false }\n }\n\n // Undeclared: describe the runtime shape rather than guessing a type.\n if (typeof value === 'object') return describeStructure(value)\n if (typeof value === 'boolean') {\n return { kind: 'value', text: value ? 'true' : 'false', block: false }\n }\n if (typeof value === 'number' || typeof value === 'string') {\n return { kind: 'value', text: String(value), block: false }\n }\n return { kind: 'opaque', text: 'Value cannot be displayed', block: false }\n}\n\n/**\n * Every field of a record, in reading order: the model's declared order\n * first, then anything the model declares but does not display, then every\n * stored value the model does not declare at all.\n *\n * The union is the point. `model.order` is what the table's columns are built\n * from, so a view built from `order` alone would be a wider row rather than\n * the record — it would silently omit a reference field declared without a\n * display slot, and every value left behind by a field the model no longer\n * has. Both are real states of a stored document, and a viewer that drops\n * them tells the reader the record is smaller than it is.\n */\nexport function datasetRecordFields(\n model: DatasetModel,\n values: Record<string, unknown> | undefined,\n resolve?: DatasetReferenceResolver,\n): DatasetRecordField[] {\n const order = model.order ?? []\n const declared = model.fields ?? {}\n const seen = new Set<string>()\n const fields: DatasetRecordField[] = []\n\n const pushDeclared = (fieldId: string) => {\n if (seen.has(fieldId)) return\n const field = declared[fieldId]\n if (!field) return\n seen.add(fieldId)\n fields.push({\n fieldId,\n label: field.name || humanizeDatasetFieldId(fieldId),\n type: field.type,\n ...(field.description ? { description: field.description } : {}),\n ...(field.required || field.validation?.required\n ? { required: true }\n : {}),\n source: 'model',\n value: describeDatasetValue(field, values, fieldId, resolve),\n })\n }\n\n for (const fieldId of order) pushDeclared(fieldId)\n for (const fieldId of Object.keys(declared)) pushDeclared(fieldId)\n\n for (const fieldId of Object.keys(values ?? {})) {\n if (seen.has(fieldId)) continue\n seen.add(fieldId)\n fields.push({\n fieldId,\n label: humanizeDatasetFieldId(fieldId),\n source: 'extra',\n value: describeDatasetValue(undefined, values, fieldId, resolve),\n })\n }\n return fields\n}\n"],"names":["formatDatasetValue","humanizeDatasetFieldId","NO_TEXT","text","block","byteLength","value","Uint8Array","ArrayBuffer","asBytes","toUint8Array","describeBytes","length","kind","describeStructure","JSON","stringify","includes","describeList","field","items","map","item","described","String","join","describeReference","fieldId","resolve","raw","Array","isArray","references","entry","trim","filter","id","label","reference","describeDatasetValue","values","present","Object","prototype","hasOwnProperty","call","undefined","type","plainObject","keys","datasetRecordFields","model","order","declared","fields","seen","Set","pushDeclared","has","add","push","name","description","required","validation","source"],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * Dataset io model (AGL-413): CSV serialize/parse for dataset records relocated from core app-utils.
19
+ * Context-free — importable by client components, /server handlers, and
20
+ * other plugins/apps via `@aglyn/plugins-data/model`.
21
+ */
22
+ export * from './dataset-io';
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ /**
17
+ * Dataset io model (AGL-413): CSV serialize/parse for dataset records relocated from core app-utils.
18
+ * Context-free — importable by client components, /server handlers, and
19
+ * other plugins/apps via `@aglyn/plugins-data/model`.
20
+ */ export * from "./dataset-io.js";
21
+
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/data/src/lib/model/index.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Dataset io model (AGL-413): CSV serialize/parse for dataset records relocated from core app-utils.\n * Context-free — importable by client components, /server handlers, and\n * other plugins/apps via `@aglyn/plugins-data/model`.\n */\nexport * from './dataset-io'\n"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;CAIC,GACD,cAAc,kBAAc"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * Data feature plugin (AGL-395). Console-only — datasets are org-shared
19
+ * document collections consumed by repeatable components at render time
20
+ * through binding resolution, not a canvas element of their own, so there
21
+ * is no UI bundle. The console half declares the host Data nav + page
22
+ * through the ConsoleExtension registry, gated by the `dataStore`
23
+ * entitlement. The org Data page (`Route.ORG_DATA`) is an org-scoped app route
24
+ * that imports {@link HostDatasetsCard} directly.
25
+ *
26
+ * It also registers datasets as a repeat source (AGL-3111), which is what puts
27
+ * "Repeat over dataset" on every element's Attributes panel and draws a
28
+ * repeat's copies from the real rows on the besigner canvas. Registered here,
29
+ * inside the function the loader calls by name, and never by a module's own
30
+ * load: this package declares no side effects, so a bundler deletes a module
31
+ * imported only to run one (AGL-3025).
32
+ */
33
+ export declare function registerDataConsole(): void;
34
+ export { default as HostDatasetsCard } from './components/host-datasets-card.component';
35
+ export type { HostDatasetsCardProps } from './components/host-datasets-card.component';
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import HostDatasetsCard from "./components/host-datasets-card.component.js";
17
+ import * as Aglyn from "@aglyn/aglyn";
18
+ import { registerRepeatSource } from "@aglyn/aglyn/app-utils/repeat-sources";
19
+ import { mdiDatabaseOutline } from "@aglyn/shared-data-mdi";
20
+ import { lazy } from "react";
21
+ import { BUNDLE_ID } from "./constants/bundle-common.js";
22
+ import { DATASET_REPEAT_SOURCE } from "./repeat/dataset-repeat-source.js";
23
+ /** Code-split: the Data console page only loads when opened. */ const DataConsolePage = lazy(()=>import("./components/data-console-page.js"));
24
+ /**
25
+ * Data feature plugin (AGL-395). Console-only — datasets are org-shared
26
+ * document collections consumed by repeatable components at render time
27
+ * through binding resolution, not a canvas element of their own, so there
28
+ * is no UI bundle. The console half declares the host Data nav + page
29
+ * through the ConsoleExtension registry, gated by the `dataStore`
30
+ * entitlement. The org Data page (`Route.ORG_DATA`) is an org-scoped app route
31
+ * that imports {@link HostDatasetsCard} directly.
32
+ *
33
+ * It also registers datasets as a repeat source (AGL-3111), which is what puts
34
+ * "Repeat over dataset" on every element's Attributes panel and draws a
35
+ * repeat's copies from the real rows on the besigner canvas. Registered here,
36
+ * inside the function the loader calls by name, and never by a module's own
37
+ * load: this package declares no side effects, so a bundler deletes a module
38
+ * imported only to run one (AGL-3025).
39
+ */ export function registerDataConsole() {
40
+ registerRepeatSource(DATASET_REPEAT_SOURCE);
41
+ Aglyn.registerConsoleExtension({
42
+ // Org datasets card (AGL-419): org/data renders it through the
43
+ // 'orgData' widget slot.
44
+ widgets: [
45
+ {
46
+ slot: 'orgData',
47
+ widgetId: 'data-org-datasets',
48
+ Component: HostDatasetsCard
49
+ }
50
+ ],
51
+ pluginId: BUNDLE_ID,
52
+ displayName: 'Data',
53
+ featureFlag: 'dataStore',
54
+ navItems: [
55
+ {
56
+ label: 'Data',
57
+ href: '/data',
58
+ // Reuse the existing release-flag nav-tab so staff-preview gating is
59
+ // unchanged now that the tab comes from the plugin (AGL-395).
60
+ navTabId: 'nav-tab-data',
61
+ icon: {
62
+ path: mdiDatabaseOutline.path
63
+ },
64
+ header: {
65
+ title: 'Data',
66
+ icon: {
67
+ path: mdiDatabaseOutline.path
68
+ },
69
+ docsTopic: 'datasets'
70
+ },
71
+ Component: DataConsolePage
72
+ }
73
+ ]
74
+ });
75
+ }
76
+ export { default as HostDatasetsCard } from "./components/host-datasets-card.component.js";
77
+
78
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../libs/plugins/data/src/lib/plugin.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport HostDatasetsCard from './components/host-datasets-card.component'\nimport * as Aglyn from '@aglyn/aglyn'\nimport { registerRepeatSource } from '@aglyn/aglyn/app-utils/repeat-sources'\nimport { mdiDatabaseOutline } from '@aglyn/shared-data-mdi'\nimport { lazy } from 'react'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport { DATASET_REPEAT_SOURCE } from './repeat/dataset-repeat-source'\n\n/** Code-split: the Data console page only loads when opened. */\nconst DataConsolePage = lazy(() => import('./components/data-console-page'))\n\n/**\n * Data feature plugin (AGL-395). Console-only — datasets are org-shared\n * document collections consumed by repeatable components at render time\n * through binding resolution, not a canvas element of their own, so there\n * is no UI bundle. The console half declares the host Data nav + page\n * through the ConsoleExtension registry, gated by the `dataStore`\n * entitlement. The org Data page (`Route.ORG_DATA`) is an org-scoped app route\n * that imports {@link HostDatasetsCard} directly.\n *\n * It also registers datasets as a repeat source (AGL-3111), which is what puts\n * \"Repeat over dataset\" on every element's Attributes panel and draws a\n * repeat's copies from the real rows on the besigner canvas. Registered here,\n * inside the function the loader calls by name, and never by a module's own\n * load: this package declares no side effects, so a bundler deletes a module\n * imported only to run one (AGL-3025).\n */\nexport function registerDataConsole(): void {\n registerRepeatSource(DATASET_REPEAT_SOURCE)\n Aglyn.registerConsoleExtension({\n // Org datasets card (AGL-419): org/data renders it through the\n // 'orgData' widget slot.\n widgets: [\n {\n slot: 'orgData',\n widgetId: 'data-org-datasets',\n Component: HostDatasetsCard,\n },\n ],\n pluginId: BUNDLE_ID,\n displayName: 'Data',\n featureFlag: 'dataStore',\n navItems: [\n {\n label: 'Data',\n href: '/data',\n // Reuse the existing release-flag nav-tab so staff-preview gating is\n // unchanged now that the tab comes from the plugin (AGL-395).\n navTabId: 'nav-tab-data',\n icon: { path: mdiDatabaseOutline.path },\n header: {\n title: 'Data',\n icon: { path: mdiDatabaseOutline.path },\n docsTopic: 'datasets',\n },\n Component: DataConsolePage,\n },\n ],\n })\n}\n\nexport { default as HostDatasetsCard } from './components/host-datasets-card.component'\nexport type { HostDatasetsCardProps } from './components/host-datasets-card.component'\n"],"names":["HostDatasetsCard","Aglyn","registerRepeatSource","mdiDatabaseOutline","lazy","BUNDLE_ID","DATASET_REPEAT_SOURCE","DataConsolePage","registerDataConsole","registerConsoleExtension","widgets","slot","widgetId","Component","pluginId","displayName","featureFlag","navItems","label","href","navTabId","icon","path","header","title","docsTopic","default"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,OAAOA,sBAAsB,+CAA2C;AACxE,YAAYC,WAAW,eAAc;AACrC,SAASC,oBAAoB,QAAQ,wCAAuC;AAC5E,SAASC,kBAAkB,QAAQ,yBAAwB;AAC3D,SAASC,IAAI,QAAQ,QAAO;AAC5B,SAASC,SAAS,QAAQ,+BAA2B;AACrD,SAASC,qBAAqB,QAAQ,oCAAgC;AAEtE,8DAA8D,GAC9D,MAAMC,kBAAkBH,KAAK,IAAM,MAAM,CAAC;AAE1C;;;;;;;;;;;;;;;CAeC,GACD,OAAO,SAASI;IACdN,qBAAqBI;IACrBL,MAAMQ,wBAAwB,CAAC;QAC7B,+DAA+D;QAC/D,yBAAyB;QACzBC,SAAS;YACP;gBACEC,MAAM;gBACNC,UAAU;gBACVC,WAAWb;YACb;SACD;QACDc,UAAUT;QACVU,aAAa;QACbC,aAAa;QACbC,UAAU;YACR;gBACEC,OAAO;gBACPC,MAAM;gBACN,qEAAqE;gBACrE,8DAA8D;gBAC9DC,UAAU;gBACVC,MAAM;oBAAEC,MAAMnB,mBAAmBmB,IAAI;gBAAC;gBACtCC,QAAQ;oBACNC,OAAO;oBACPH,MAAM;wBAAEC,MAAMnB,mBAAmBmB,IAAI;oBAAC;oBACtCG,WAAW;gBACb;gBACAZ,WAAWN;YACb;SACD;IACH;AACF;AAEA,SAASmB,WAAW1B,gBAAgB,QAAQ,+CAA2C"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import type { RepeatRowsAnswer } from '@aglyn/aglyn/app-utils/repeat-sources';
18
+ import { type Firestore } from 'firebase/firestore';
19
+ export interface DatasetRepeatRowsRequest {
20
+ firestore: Firestore;
21
+ /** `['orgs', orgId]` — where the site's organization keeps its datasets. */
22
+ scope: readonly [string, string];
23
+ /** The site the canvas edits. */
24
+ hostId: string;
25
+ /** The dataset key exactly as the node stores it: an id or a display name. */
26
+ key: string;
27
+ }
28
+ /**
29
+ * A dataset's rows for the besigner's canvas preview, read the way the
30
+ * published page's composition reads them (`getDatasets` in the tenant
31
+ * runtime), with the client SDK instead of the Admin one (AGL-3111).
32
+ *
33
+ * - The key resolves as the page resolves it: an id first, then a display
34
+ * name within what this site may see. An id that exists but that this site
35
+ * cannot see does not fall through to the name — that would answer "which
36
+ * dataset is called X" for a key that already named a specific one.
37
+ * - A dataset shared with other sites but not this one, or deleted, answers
38
+ * `missing`: the page renders the element once, as written.
39
+ * - The rows are the two bounded reads and the one ordering rule the page
40
+ * uses, {@link repeatRecordsFromPages}, so a canvas copy is a row the page
41
+ * renders.
42
+ * - One reference hop (AGL-180) is loaded as the page loads it, so
43
+ * `{{item.author.name}}` previews too.
44
+ */
45
+ export declare function readDatasetRepeatRows(request: DatasetRepeatRowsRequest): Promise<RepeatRowsAnswer>;