@propertysimple/client 0.1.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.
Files changed (54) hide show
  1. package/API.md +79 -0
  2. package/README.md +348 -0
  3. package/client/src/directory-sync.d.ts +123 -0
  4. package/client/src/directory-sync.js +404 -0
  5. package/client/src/index.d.ts +5123 -0
  6. package/client/src/index.js +285 -0
  7. package/client/src/managed-sync.d.ts +129 -0
  8. package/client/src/managed-sync.js +410 -0
  9. package/contracts/src/catalog-derived.d.ts +7 -0
  10. package/contracts/src/catalog-derived.js +78 -0
  11. package/contracts/src/catalog-fields.d.ts +231 -0
  12. package/contracts/src/catalog-fields.js +194 -0
  13. package/contracts/src/catalog-inventory.d.ts +14 -0
  14. package/contracts/src/catalog-inventory.js +10 -0
  15. package/contracts/src/directory-execution.d.ts +320 -0
  16. package/contracts/src/directory-execution.js +122 -0
  17. package/contracts/src/directory-identity.d.ts +1255 -0
  18. package/contracts/src/directory-identity.js +129 -0
  19. package/contracts/src/directory-sales.d.ts +333 -0
  20. package/contracts/src/directory-sales.js +102 -0
  21. package/contracts/src/directory.d.ts +1088 -0
  22. package/contracts/src/directory.js +179 -0
  23. package/contracts/src/index.d.ts +18 -0
  24. package/contracts/src/index.js +18 -0
  25. package/contracts/src/intelligence.d.ts +366 -0
  26. package/contracts/src/intelligence.js +157 -0
  27. package/contracts/src/location-serving.d.ts +13 -0
  28. package/contracts/src/location-serving.js +89 -0
  29. package/contracts/src/location.d.ts +73 -0
  30. package/contracts/src/location.js +75 -0
  31. package/contracts/src/openapi.d.ts +22 -0
  32. package/contracts/src/openapi.js +109 -0
  33. package/contracts/src/operations.d.ts +8316 -0
  34. package/contracts/src/operations.js +56 -0
  35. package/contracts/src/opportunity-events.d.ts +38 -0
  36. package/contracts/src/opportunity-events.js +69 -0
  37. package/contracts/src/platform-api.d.ts +12 -0
  38. package/contracts/src/platform-api.js +1 -0
  39. package/contracts/src/professional-intelligence.d.ts +256 -0
  40. package/contracts/src/professional-intelligence.js +90 -0
  41. package/contracts/src/property-features.d.ts +94 -0
  42. package/contracts/src/property-features.js +398 -0
  43. package/contracts/src/publication.d.ts +44 -0
  44. package/contracts/src/publication.js +42 -0
  45. package/contracts/src/routes.d.ts +437 -0
  46. package/contracts/src/routes.js +496 -0
  47. package/contracts/src/schemas.d.ts +3198 -0
  48. package/contracts/src/schemas.js +674 -0
  49. package/contracts/src/search.d.ts +2630 -0
  50. package/contracts/src/search.js +223 -0
  51. package/contracts/src/smart-feed.d.ts +3731 -0
  52. package/contracts/src/smart-feed.js +109 -0
  53. package/openapi.json +43542 -0
  54. package/package.json +60 -0
@@ -0,0 +1,231 @@
1
+ import { z } from 'zod';
2
+ /** Additive shared contract. An absent block means an older parser, not empty source data. */
3
+ export declare const CATALOG_FIELDS_VERSION = "catalog-fields-v2";
4
+ export declare const SourceFieldsSchema: z.ZodObject<{
5
+ listhub: z.ZodRecord<z.ZodString, z.ZodJSONSchema>;
6
+ }, z.core.$strict>;
7
+ export declare const SourceDateSchema: z.ZodObject<{
8
+ value: z.ZodNullable<z.ZodString>;
9
+ precision: z.ZodEnum<{
10
+ unknown: "unknown";
11
+ date: "date";
12
+ instant: "instant";
13
+ }>;
14
+ }, z.core.$strict>;
15
+ export declare const ProfessionalsSchema: z.ZodObject<{
16
+ agent: z.ZodObject<{
17
+ full_name: z.ZodNullable<z.ZodString>;
18
+ first_name: z.ZodNullable<z.ZodString>;
19
+ last_name: z.ZodNullable<z.ZodString>;
20
+ license: z.ZodNullable<z.ZodString>;
21
+ }, z.core.$strict>;
22
+ office: z.ZodObject<{
23
+ key: z.ZodNullable<z.ZodString>;
24
+ mls_id: z.ZodNullable<z.ZodString>;
25
+ name: z.ZodNullable<z.ZodString>;
26
+ broker_mls_id: z.ZodNullable<z.ZodString>;
27
+ corporate_id: z.ZodNullable<z.ZodString>;
28
+ main_office_id: z.ZodNullable<z.ZodString>;
29
+ website_url: z.ZodNullable<z.ZodURL>;
30
+ address: z.ZodObject<{
31
+ street: z.ZodNullable<z.ZodString>;
32
+ unit: z.ZodNullable<z.ZodString>;
33
+ city: z.ZodNullable<z.ZodString>;
34
+ region: z.ZodNullable<z.ZodString>;
35
+ postal_code: z.ZodNullable<z.ZodString>;
36
+ country: z.ZodNullable<z.ZodString>;
37
+ }, z.core.$strict>;
38
+ }, z.core.$strict>;
39
+ brokerage: z.ZodObject<{
40
+ name: z.ZodNullable<z.ZodString>;
41
+ website_url: z.ZodNullable<z.ZodURL>;
42
+ logo_url: z.ZodNullable<z.ZodURL>;
43
+ address: z.ZodObject<{
44
+ street: z.ZodNullable<z.ZodString>;
45
+ unit: z.ZodNullable<z.ZodString>;
46
+ city: z.ZodNullable<z.ZodString>;
47
+ region: z.ZodNullable<z.ZodString>;
48
+ postal_code: z.ZodNullable<z.ZodString>;
49
+ country: z.ZodNullable<z.ZodString>;
50
+ }, z.core.$strict>;
51
+ }, z.core.$strict>;
52
+ builder: z.ZodObject<{
53
+ name: z.ZodNullable<z.ZodString>;
54
+ }, z.core.$strict>;
55
+ franchise: z.ZodNullable<z.ZodString>;
56
+ }, z.core.$strict>;
57
+ export declare const ProfessionalContactsSchema: z.ZodObject<{
58
+ agent: z.ZodObject<{
59
+ email: z.ZodNullable<z.ZodEmail>;
60
+ preferred_phone: z.ZodNullable<z.ZodString>;
61
+ direct_phone: z.ZodNullable<z.ZodString>;
62
+ office_phone: z.ZodNullable<z.ZodString>;
63
+ fax: z.ZodNullable<z.ZodString>;
64
+ website_url: z.ZodNullable<z.ZodURL>;
65
+ }, z.core.$strict>;
66
+ office: z.ZodObject<{
67
+ email: z.ZodNullable<z.ZodEmail>;
68
+ phone: z.ZodNullable<z.ZodString>;
69
+ }, z.core.$strict>;
70
+ brokerage: z.ZodObject<{
71
+ email: z.ZodNullable<z.ZodEmail>;
72
+ phone: z.ZodNullable<z.ZodString>;
73
+ }, z.core.$strict>;
74
+ builder: z.ZodObject<{
75
+ email: z.ZodNullable<z.ZodEmail>;
76
+ phone: z.ZodNullable<z.ZodString>;
77
+ fax: z.ZodNullable<z.ZodString>;
78
+ }, z.core.$strict>;
79
+ }, z.core.$strict>;
80
+ export declare const SharedListingFields: {
81
+ source_amenities: z.ZodOptional<z.ZodObject<{
82
+ version: z.ZodLiteral<"source-amenities-v1">;
83
+ values: z.ZodRecord<z.ZodEnum<{
84
+ hardwood: "hardwood";
85
+ solar: "solar";
86
+ ev_charger: "ev_charger";
87
+ rv_parking: "rv_parking";
88
+ view: "view";
89
+ }>, z.ZodObject<{
90
+ value: z.ZodNullable<z.ZodBoolean>;
91
+ state: z.ZodEnum<{
92
+ supported: "supported";
93
+ not_stated: "not_stated";
94
+ conflicting: "conflicting";
95
+ }>;
96
+ source_paths: z.ZodArray<z.ZodString>;
97
+ }, z.core.$strict>>;
98
+ }, z.core.$strict>>;
99
+ search_document: z.ZodOptional<z.ZodObject<{
100
+ version: z.ZodLiteral<"catalog-search-text-v1">;
101
+ text: z.ZodString;
102
+ }, z.core.$strict>>;
103
+ content_hash: z.ZodOptional<z.ZodString>;
104
+ source_fields: z.ZodOptional<z.ZodObject<{
105
+ listhub: z.ZodRecord<z.ZodString, z.ZodJSONSchema>;
106
+ }, z.core.$strict>>;
107
+ source_metadata: z.ZodOptional<z.ZodObject<{
108
+ contract_version: z.ZodLiteral<"catalog-fields-v2">;
109
+ parser_version: z.ZodString;
110
+ exposure_version: z.ZodString;
111
+ source_system_id: z.ZodNullable<z.ZodString>;
112
+ source_system_name: z.ZodNullable<z.ZodString>;
113
+ originating_system_name: z.ZodNullable<z.ZodString>;
114
+ source_photo_count: z.ZodNullable<z.ZodNumber>;
115
+ supplied_paths: z.ZodArray<z.ZodString>;
116
+ }, z.core.$strict>>;
117
+ market_dates: z.ZodOptional<z.ZodObject<{
118
+ listing_contract: z.ZodObject<{
119
+ value: z.ZodNullable<z.ZodString>;
120
+ precision: z.ZodEnum<{
121
+ unknown: "unknown";
122
+ date: "date";
123
+ instant: "instant";
124
+ }>;
125
+ }, z.core.$strict>;
126
+ on_market: z.ZodObject<{
127
+ value: z.ZodNullable<z.ZodString>;
128
+ precision: z.ZodEnum<{
129
+ unknown: "unknown";
130
+ date: "date";
131
+ instant: "instant";
132
+ }>;
133
+ }, z.core.$strict>;
134
+ source_days_on_market: z.ZodNullable<z.ZodNumber>;
135
+ source_cumulative_days_on_market: z.ZodNullable<z.ZodNumber>;
136
+ }, z.core.$strict>>;
137
+ taxes: z.ZodOptional<z.ZodObject<{
138
+ annual_amount: z.ZodNullable<z.ZodString>;
139
+ currency: z.ZodNullable<z.ZodString>;
140
+ year: z.ZodNullable<z.ZodNumber>;
141
+ }, z.core.$strict>>;
142
+ schools: z.ZodOptional<z.ZodArray<z.ZodObject<{
143
+ level: z.ZodEnum<{
144
+ elementary: "elementary";
145
+ middle: "middle";
146
+ high: "high";
147
+ }>;
148
+ name: z.ZodNullable<z.ZodString>;
149
+ district: z.ZodNullable<z.ZodString>;
150
+ }, z.core.$strict>>>;
151
+ price_history: z.ZodOptional<z.ZodObject<{
152
+ original_amount: z.ZodNullable<z.ZodString>;
153
+ previous_amount: z.ZodNullable<z.ZodString>;
154
+ low_amount: z.ZodNullable<z.ZodString>;
155
+ currency: z.ZodNullable<z.ZodString>;
156
+ original_currency: z.ZodNullable<z.ZodString>;
157
+ previous_currency: z.ZodNullable<z.ZodString>;
158
+ low_currency: z.ZodNullable<z.ZodString>;
159
+ changed_at: z.ZodObject<{
160
+ value: z.ZodNullable<z.ZodString>;
161
+ precision: z.ZodEnum<{
162
+ unknown: "unknown";
163
+ date: "date";
164
+ instant: "instant";
165
+ }>;
166
+ }, z.core.$strict>;
167
+ }, z.core.$strict>>;
168
+ virtual_tours: z.ZodOptional<z.ZodObject<{
169
+ branded_url: z.ZodNullable<z.ZodURL>;
170
+ unbranded_url: z.ZodNullable<z.ZodURL>;
171
+ }, z.core.$strict>>;
172
+ additional_media: z.ZodOptional<z.ZodArray<z.ZodObject<{
173
+ url: z.ZodURL;
174
+ categories: z.ZodArray<z.ZodString>;
175
+ order: z.ZodNumber;
176
+ caption: z.ZodNullable<z.ZodString>;
177
+ }, z.core.$strict>>>;
178
+ professionals: z.ZodOptional<z.ZodObject<{
179
+ agent: z.ZodObject<{
180
+ full_name: z.ZodNullable<z.ZodString>;
181
+ first_name: z.ZodNullable<z.ZodString>;
182
+ last_name: z.ZodNullable<z.ZodString>;
183
+ license: z.ZodNullable<z.ZodString>;
184
+ }, z.core.$strict>;
185
+ office: z.ZodObject<{
186
+ key: z.ZodNullable<z.ZodString>;
187
+ mls_id: z.ZodNullable<z.ZodString>;
188
+ name: z.ZodNullable<z.ZodString>;
189
+ broker_mls_id: z.ZodNullable<z.ZodString>;
190
+ corporate_id: z.ZodNullable<z.ZodString>;
191
+ main_office_id: z.ZodNullable<z.ZodString>;
192
+ website_url: z.ZodNullable<z.ZodURL>;
193
+ address: z.ZodObject<{
194
+ street: z.ZodNullable<z.ZodString>;
195
+ unit: z.ZodNullable<z.ZodString>;
196
+ city: z.ZodNullable<z.ZodString>;
197
+ region: z.ZodNullable<z.ZodString>;
198
+ postal_code: z.ZodNullable<z.ZodString>;
199
+ country: z.ZodNullable<z.ZodString>;
200
+ }, z.core.$strict>;
201
+ }, z.core.$strict>;
202
+ brokerage: z.ZodObject<{
203
+ name: z.ZodNullable<z.ZodString>;
204
+ website_url: z.ZodNullable<z.ZodURL>;
205
+ logo_url: z.ZodNullable<z.ZodURL>;
206
+ address: z.ZodObject<{
207
+ street: z.ZodNullable<z.ZodString>;
208
+ unit: z.ZodNullable<z.ZodString>;
209
+ city: z.ZodNullable<z.ZodString>;
210
+ region: z.ZodNullable<z.ZodString>;
211
+ postal_code: z.ZodNullable<z.ZodString>;
212
+ country: z.ZodNullable<z.ZodString>;
213
+ }, z.core.$strict>;
214
+ }, z.core.$strict>;
215
+ builder: z.ZodObject<{
216
+ name: z.ZodNullable<z.ZodString>;
217
+ }, z.core.$strict>;
218
+ franchise: z.ZodNullable<z.ZodString>;
219
+ }, z.core.$strict>>;
220
+ permissions: z.ZodOptional<z.ZodObject<{
221
+ internet_display: z.ZodNullable<z.ZodBoolean>;
222
+ entire_listing_display: z.ZodNullable<z.ZodBoolean>;
223
+ address_display: z.ZodNullable<z.ZodBoolean>;
224
+ automated_valuation_display: z.ZodNullable<z.ZodBoolean>;
225
+ consumer_comment: z.ZodNullable<z.ZodBoolean>;
226
+ }, z.core.$strict>>;
227
+ };
228
+ /** Unit conversions are shared by adapters. Unknown units never become square feet. */
229
+ export declare function convertArea(value: number | null | undefined, unit: string | null | undefined, target: 'sqft' | 'acres'): number | null;
230
+ /** Recursively remove location-bearing aliases from extensions, including old snapshots. */
231
+ export declare function redactSourceAddress(fields: z.infer<typeof SourceFieldsSchema>): z.infer<typeof SourceFieldsSchema>;
@@ -0,0 +1,194 @@
1
+ import { z } from 'zod';
2
+ /** Additive shared contract. An absent block means an older parser, not empty source data. */
3
+ export const CATALOG_FIELDS_VERSION = 'catalog-fields-v2';
4
+ export const SourceFieldsSchema = z.strictObject({ listhub: z.record(z.string(), z.json()) });
5
+ const text = z.string().nullable();
6
+ const count = z.number().nonnegative().nullable();
7
+ const amount = z
8
+ .string()
9
+ .regex(/^\d+(?:\.\d{1,2})?$/)
10
+ .nullable();
11
+ const currency = z
12
+ .string()
13
+ .regex(/^[A-Z]{3}$/)
14
+ .nullable();
15
+ const httpUrl = z.url({ protocol: /^https?$/ }).nullable();
16
+ export const SourceDateSchema = z.strictObject({
17
+ value: text,
18
+ precision: z.enum(['date', 'instant', 'unknown']),
19
+ });
20
+ const businessAddress = z.strictObject({
21
+ street: text,
22
+ unit: text,
23
+ city: text,
24
+ region: text,
25
+ postal_code: text,
26
+ country: text,
27
+ });
28
+ export const ProfessionalsSchema = z.strictObject({
29
+ agent: z.strictObject({
30
+ full_name: text,
31
+ first_name: text,
32
+ last_name: text,
33
+ license: text,
34
+ }),
35
+ office: z.strictObject({
36
+ key: text,
37
+ mls_id: text,
38
+ name: text,
39
+ broker_mls_id: text,
40
+ corporate_id: text,
41
+ main_office_id: text,
42
+ website_url: httpUrl,
43
+ address: businessAddress,
44
+ }),
45
+ brokerage: z.strictObject({
46
+ name: text,
47
+ website_url: httpUrl,
48
+ logo_url: httpUrl,
49
+ address: businessAddress,
50
+ }),
51
+ builder: z.strictObject({ name: text }),
52
+ franchise: text,
53
+ });
54
+ export const ProfessionalContactsSchema = z.strictObject({
55
+ agent: z.strictObject({
56
+ email: z.email().nullable(),
57
+ preferred_phone: text,
58
+ direct_phone: text,
59
+ office_phone: text,
60
+ fax: text,
61
+ website_url: httpUrl,
62
+ }),
63
+ office: z.strictObject({ email: z.email().nullable(), phone: text }),
64
+ brokerage: z.strictObject({ email: z.email().nullable(), phone: text }),
65
+ builder: z.strictObject({ email: z.email().nullable(), phone: text, fax: text }),
66
+ });
67
+ export const SharedListingFields = {
68
+ source_amenities: z
69
+ .strictObject({
70
+ version: z.literal('source-amenities-v1'),
71
+ values: z.record(z.enum(['hardwood', 'solar', 'ev_charger', 'rv_parking', 'view']), z.strictObject({
72
+ value: z.boolean().nullable(),
73
+ state: z.enum(['supported', 'not_stated', 'conflicting']),
74
+ source_paths: z.array(z.string()),
75
+ })),
76
+ })
77
+ .optional(),
78
+ search_document: z
79
+ .strictObject({ version: z.literal('catalog-search-text-v1'), text: z.string() })
80
+ .optional(),
81
+ content_hash: z
82
+ .string()
83
+ .regex(/^[a-f0-9]{64}$/)
84
+ .optional(),
85
+ source_fields: SourceFieldsSchema.optional(),
86
+ source_metadata: z
87
+ .strictObject({
88
+ contract_version: z.literal(CATALOG_FIELDS_VERSION),
89
+ parser_version: z.string(),
90
+ exposure_version: z.string(),
91
+ source_system_id: text,
92
+ source_system_name: text,
93
+ originating_system_name: text,
94
+ source_photo_count: z.number().int().nonnegative().nullable(),
95
+ // Presence covers permitted paths only. Unreviewed names/values stay private.
96
+ supplied_paths: z.array(z.string()),
97
+ })
98
+ .optional(),
99
+ market_dates: z
100
+ .strictObject({
101
+ listing_contract: SourceDateSchema,
102
+ on_market: SourceDateSchema,
103
+ source_days_on_market: count,
104
+ source_cumulative_days_on_market: count,
105
+ })
106
+ .optional(),
107
+ taxes: z
108
+ .strictObject({ annual_amount: amount, currency, year: z.number().int().nullable() })
109
+ .optional(),
110
+ schools: z
111
+ .array(z.strictObject({
112
+ level: z.enum(['elementary', 'middle', 'high']),
113
+ name: text,
114
+ district: text,
115
+ }))
116
+ .optional(),
117
+ price_history: z
118
+ .strictObject({
119
+ original_amount: amount,
120
+ previous_amount: amount,
121
+ low_amount: amount,
122
+ currency,
123
+ original_currency: currency,
124
+ previous_currency: currency,
125
+ low_currency: currency,
126
+ changed_at: SourceDateSchema,
127
+ })
128
+ .optional(),
129
+ virtual_tours: z.strictObject({ branded_url: httpUrl, unbranded_url: httpUrl }).optional(),
130
+ additional_media: z
131
+ .array(z.strictObject({
132
+ url: z.url({ protocol: /^https?$/ }),
133
+ categories: z.array(z.string()),
134
+ order: z.number().int().nonnegative(),
135
+ caption: text,
136
+ }))
137
+ .optional(),
138
+ professionals: ProfessionalsSchema.optional(),
139
+ permissions: z
140
+ .strictObject({
141
+ internet_display: z.boolean().nullable(),
142
+ entire_listing_display: z.boolean().nullable(),
143
+ address_display: z.boolean().nullable(),
144
+ automated_valuation_display: z.boolean().nullable(),
145
+ consumer_comment: z.boolean().nullable(),
146
+ })
147
+ .optional(),
148
+ };
149
+ /** Unit conversions are shared by adapters. Unknown units never become square feet. */
150
+ export function convertArea(value, unit, target) {
151
+ if (value == null || !Number.isFinite(value) || value < 0)
152
+ return null;
153
+ const normalized = unit?.trim().toLowerCase();
154
+ const sqft = normalized === 'sqft' || normalized === 'square feet'
155
+ ? value
156
+ : normalized === 'sqm' || normalized === 'square meters'
157
+ ? value / 0.09290304
158
+ : normalized === 'acres' || normalized === 'acre'
159
+ ? value * 43560
160
+ : null;
161
+ return sqft === null ? null : target === 'sqft' ? sqft : sqft / 43560;
162
+ }
163
+ /** Recursively remove location-bearing aliases from extensions, including old snapshots. */
164
+ export function redactSourceAddress(fields) {
165
+ const hidden = new Set([
166
+ 'UnparsedAddress',
167
+ 'UnitNumber',
168
+ 'StreetNumber',
169
+ 'StreetNumberNumeric',
170
+ 'StreetName',
171
+ 'StreetDirPrefix',
172
+ 'StreetDirSuffix',
173
+ 'StreetSuffix',
174
+ 'Latitude',
175
+ 'Longitude',
176
+ 'Location',
177
+ 'GeocodeOptions',
178
+ 'SubdivisionName',
179
+ 'Directions',
180
+ 'ParcelNumber',
181
+ 'TaxLegalDescription',
182
+ 'Neighborhoods',
183
+ ]);
184
+ const walk = (value) => {
185
+ if (Array.isArray(value))
186
+ return value.map(walk);
187
+ if (value && typeof value === 'object')
188
+ return Object.fromEntries(Object.entries(value)
189
+ .filter(([key]) => !hidden.has(key))
190
+ .map(([key, child]) => [key, walk(child)]));
191
+ return value;
192
+ };
193
+ return { listhub: walk(fields.listhub) };
194
+ }
@@ -0,0 +1,14 @@
1
+ import { z } from 'zod';
2
+ /** Inventory progress is distinct from a completed source refresh. Processed
3
+ * source records include non-displayable records; they are not a search total. */
4
+ export declare const CatalogInventoryStatusSchema: z.ZodObject<{
5
+ state: z.ZodEnum<{
6
+ partial: "partial";
7
+ complete: "complete";
8
+ }>;
9
+ source_observed_at: z.ZodNullable<z.ZodISODateTime>;
10
+ expected_source_records: z.ZodNullable<z.ZodNumber>;
11
+ processed_source_records: z.ZodNullable<z.ZodNumber>;
12
+ valid_until: z.ZodISODateTime;
13
+ }, z.core.$strict>;
14
+ export type CatalogInventoryStatus = z.infer<typeof CatalogInventoryStatusSchema>;
@@ -0,0 +1,10 @@
1
+ import { z } from 'zod';
2
+ /** Inventory progress is distinct from a completed source refresh. Processed
3
+ * source records include non-displayable records; they are not a search total. */
4
+ export const CatalogInventoryStatusSchema = z.strictObject({
5
+ state: z.enum(['partial', 'complete']),
6
+ source_observed_at: z.iso.datetime({ offset: true }).nullable(),
7
+ expected_source_records: z.number().int().nonnegative().nullable(),
8
+ processed_source_records: z.number().int().nonnegative().nullable(),
9
+ valid_until: z.iso.datetime({ offset: true }),
10
+ });