airtable-ts 1.9.0 → 1.10.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.
@@ -24,6 +24,26 @@ const coerce = (airtableType, tsType) => (value) => {
24
24
  if (parsedType.nullable && (value === undefined || value === null || (Array.isArray(value) && value.length === 0))) {
25
25
  return null;
26
26
  }
27
+ // ISO date strings (e.g. from date lookup/rollup fields) coerced to Unix timestamps
28
+ if (parsedType.single === 'number' && !parsedType.array && typeof value === 'string' && /^\d{4}-\d{2}-\d{2}/.test(value)) {
29
+ const date = new Date(value);
30
+ if (!Number.isNaN(date.getTime())) {
31
+ return Math.floor(date.getTime() / 1000);
32
+ }
33
+ }
34
+ if (parsedType.single === 'number' && parsedType.array && Array.isArray(value) && value.every((v) => typeof v === 'string' && /^\d{4}-\d{2}-\d{2}/.test(v))) {
35
+ const timestamps = value.map((v) => {
36
+ const date = new Date(v);
37
+ if (Number.isNaN(date.getTime())) {
38
+ throw new AirtableTsError_1.AirtableTsError({
39
+ message: `Invalid date value '${v}' in array from airtable type '${airtableType}'.`,
40
+ type: AirtableTsError_1.ErrorType.SCHEMA_VALIDATION,
41
+ });
42
+ }
43
+ return Math.floor(date.getTime() / 1000);
44
+ });
45
+ return timestamps;
46
+ }
27
47
  if (parsedType.array && typeof value === parsedType.single) {
28
48
  return [value];
29
49
  }
@@ -147,13 +167,23 @@ const multipleCollaboratorsMapperPair = {
147
167
  },
148
168
  };
149
169
  const multipleAttachmentsMapperPair = {
150
- toAirtable: readonly('multipleAttachments'),
170
+ toAirtable(value) {
171
+ if (value === null || value === undefined) {
172
+ return null;
173
+ }
174
+ return value.map((url) => ({ url }));
175
+ },
151
176
  fromAirtable(obj) {
152
177
  return obj?.map((v) => ('url' in v && typeof v.url === 'string' ? v.url : null)).filter(Boolean) ?? null;
153
178
  },
154
179
  };
155
180
  const multipleAttachmentsWithMetadataMapperPair = {
156
- toAirtable: readonly('multipleAttachments'),
181
+ toAirtable(value) {
182
+ if (value === null || value === undefined) {
183
+ return null;
184
+ }
185
+ return value.map((att) => ({ url: att.url, filename: att.filename }));
186
+ },
157
187
  fromAirtable(obj) {
158
188
  if (!obj) {
159
189
  return null;
@@ -242,7 +272,12 @@ const stringOrNull = {
242
272
  fromAirtable: collaboratorMapperPair.fromAirtable,
243
273
  },
244
274
  multipleAttachments: {
245
- toAirtable: readonly('multipleAttachments'),
275
+ toAirtable(value) {
276
+ if (value === null || value === undefined) {
277
+ return null;
278
+ }
279
+ return [{ url: value }];
280
+ },
246
281
  fromAirtable: (value) => coerce('multipleAttachments', 'string | null')(multipleAttachmentsMapperPair.fromAirtable(value)),
247
282
  },
248
283
  multipleSelects: {
@@ -426,6 +461,22 @@ const stringArrayOrNull = {
426
461
  },
427
462
  },
428
463
  };
464
+ const numberArrayOrNull = {
465
+ 'number[] | null': {
466
+ multipleLookupValues: {
467
+ toAirtable: readonly('multipleLookupValues'),
468
+ fromAirtable: coerce('multipleLookupValues', 'number[] | null'),
469
+ },
470
+ rollup: {
471
+ toAirtable: readonly('rollup'),
472
+ fromAirtable: coerce('rollup', 'number[] | null'),
473
+ },
474
+ unknown: {
475
+ toAirtable: (value) => value,
476
+ fromAirtable: coerce('unknown', 'number[] | null'),
477
+ },
478
+ },
479
+ };
429
480
  exports.fieldMappers = {
430
481
  ...stringOrNull,
431
482
  string: {
@@ -483,13 +534,32 @@ exports.fieldMappers = {
483
534
  }];
484
535
  })),
485
536
  },
537
+ ...numberArrayOrNull,
538
+ 'number[]': {
539
+ ...Object.fromEntries(Object.entries(numberArrayOrNull['number[] | null']).map(([airtableType, nullablePair]) => {
540
+ return [airtableType, {
541
+ toAirtable: nullablePair.toAirtable,
542
+ fromAirtable: (value) => nullablePair.fromAirtable(value) ?? [],
543
+ }];
544
+ })),
545
+ },
486
546
  'Attachment[] | null': {
487
547
  multipleAttachments: multipleAttachmentsWithMetadataMapperPair,
548
+ // Lookup fields that reference attachment fields return the same flattened structure
549
+ multipleLookupValues: {
550
+ toAirtable: readonly('multipleLookupValues'),
551
+ fromAirtable: (value) => multipleAttachmentsWithMetadataMapperPair.fromAirtable(value),
552
+ },
488
553
  },
489
554
  'Attachment[]': {
490
555
  multipleAttachments: {
491
556
  toAirtable: multipleAttachmentsWithMetadataMapperPair.toAirtable,
492
557
  fromAirtable: (value) => multipleAttachmentsWithMetadataMapperPair.fromAirtable(value) ?? [],
493
558
  },
559
+ // Lookup fields that reference attachment fields return the same flattened structure
560
+ multipleLookupValues: {
561
+ toAirtable: readonly('multipleLookupValues'),
562
+ fromAirtable: (value) => multipleAttachmentsWithMetadataMapperPair.fromAirtable(value) ?? [],
563
+ },
494
564
  },
495
565
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "airtable-ts",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "description": "A type-safe Airtable SDK",
5
5
  "license": "MIT",
6
6
  "author": "Adam Jones (domdomegg)",