form0-core 0.1.19 → 0.1.20

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "form0-core",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/"
6
6
  },
@@ -12,6 +12,44 @@ const AI_ATTRIBUTE_DEFINITION = {
12
12
  nullable: true,
13
13
  };
14
14
 
15
+ const MEDIA_REFERENCE_FIELDS = [
16
+ 'asset_id',
17
+ 'upload_id',
18
+ 'upload_status',
19
+ 'mime_type',
20
+ 'size',
21
+ 'size_bytes',
22
+ 'checksum_sha256',
23
+ 'original_filename',
24
+ 'thumbnail_url',
25
+ 'preview_url',
26
+ 'url',
27
+ 'public_url',
28
+ 'field_key',
29
+ 'field_data_name',
30
+ 'attached_at_client',
31
+ 'captured_at_client',
32
+ 'signed_at_client',
33
+ 'uploaded_at_server',
34
+ 'ready_at_server',
35
+ 'error',
36
+ ];
37
+
38
+ const isObjectRecord = (value) =>
39
+ Boolean(value) && typeof value === 'object' && !Array.isArray(value);
40
+
41
+ const copyPresentMediaFields = (source, target) => {
42
+ MEDIA_REFERENCE_FIELDS.forEach((fieldName) => {
43
+ if (Object.prototype.hasOwnProperty.call(source, fieldName)) {
44
+ target[fieldName] = source[fieldName];
45
+ }
46
+ });
47
+ return target;
48
+ };
49
+
50
+ const normalizeMediaId = (value, primaryKey) =>
51
+ value[primaryKey] || value.media_id || value.asset_id || null;
52
+
15
53
  /**
16
54
  * Central field specification registry
17
55
  * Each field type defines its attributes, validation rules, and behavior
@@ -1104,17 +1142,19 @@ export const FIELD_SPECS = {
1104
1142
  return field.default_value || null;
1105
1143
  },
1106
1144
  outputProducer: (field, value) => {
1107
- // SignatureField output structure: {signature_id: null, data: base64String}
1108
- if (value && typeof value === 'object' && value.data) {
1109
- // Value is already in the correct structure from form-renderer.js
1110
- return {
1111
- signature_id: value.signature_id || null,
1112
- data: value.data,
1113
- };
1145
+ // SignatureField preserves storage-agnostic upload metadata.
1146
+ if (isObjectRecord(value)) {
1147
+ const output = copyPresentMediaFields(value, {
1148
+ signature_id: normalizeMediaId(value, 'signature_id'),
1149
+ media_id: value.media_id || value.signature_id || value.asset_id || null,
1150
+ data: value.data || null,
1151
+ });
1152
+ return output.data || output.asset_id || output.upload_id || output.media_id ? output : null;
1114
1153
  } else if (value && typeof value === 'string') {
1115
1154
  // Fallback: if value is just the base64 string
1116
1155
  return {
1117
1156
  signature_id: null,
1157
+ media_id: null,
1118
1158
  data: value,
1119
1159
  };
1120
1160
  }
@@ -1200,13 +1240,18 @@ export const FIELD_SPECS = {
1200
1240
  return null; // PhotoField default_value must be null
1201
1241
  },
1202
1242
  outputProducer: (field, value) => {
1203
- // PhotoField output structure: array of {photo_id: null|uuid, filename: string, caption: string|null}
1243
+ // PhotoField output preserves stable client IDs and upload metadata.
1204
1244
  if (Array.isArray(value)) {
1205
- return value.map((photo) => ({
1206
- photo_id: photo.photo_id || null,
1207
- filename: photo.filename || photo.name || 'unknown',
1208
- caption: photo.caption || null,
1209
- }));
1245
+ return value
1246
+ .filter((photo) => isObjectRecord(photo))
1247
+ .map((photo) =>
1248
+ copyPresentMediaFields(photo, {
1249
+ photo_id: normalizeMediaId(photo, 'photo_id'),
1250
+ media_id: photo.media_id || photo.photo_id || photo.asset_id || null,
1251
+ filename: photo.filename || photo.name || photo.original_filename || 'unknown',
1252
+ caption: photo.caption || null,
1253
+ })
1254
+ );
1210
1255
  }
1211
1256
  return [];
1212
1257
  },
@@ -1296,14 +1341,19 @@ export const FIELD_SPECS = {
1296
1341
  return null; // VideoField default_value must be null
1297
1342
  },
1298
1343
  outputProducer: (field, value) => {
1299
- // VideoField output structure: array of {video_id: null|uuid, filename: string, duration: number, caption: string|null}
1344
+ // VideoField output preserves stable client IDs and upload metadata.
1300
1345
  if (Array.isArray(value)) {
1301
- return value.map((video) => ({
1302
- video_id: video.video_id || null,
1303
- filename: video.filename || video.name || 'unknown',
1304
- duration: video.duration || 0,
1305
- caption: video.caption || null,
1306
- }));
1346
+ return value
1347
+ .filter((video) => isObjectRecord(video))
1348
+ .map((video) =>
1349
+ copyPresentMediaFields(video, {
1350
+ video_id: normalizeMediaId(video, 'video_id'),
1351
+ media_id: video.media_id || video.video_id || video.asset_id || null,
1352
+ filename: video.filename || video.name || video.original_filename || 'unknown',
1353
+ duration: video.duration || 0,
1354
+ caption: video.caption || null,
1355
+ })
1356
+ );
1307
1357
  }
1308
1358
  return [];
1309
1359
  },