0
# Data Utilities
1
2
Comprehensive data processing utilities including country code lookup, CORS origin parsing, field transformations, and validation functions for common data operations.
3
4
## Capabilities
5
6
### Country Data and Lookup
7
8
Complete country information with ISO codes and lookup functionality.
9
10
```typescript { .api }
11
/**
12
* Country information structure
13
*/
14
type Country = {
15
/** ISO 3166-1 alpha-2 country code */
16
alpha2: string;
17
/** Country name */
18
name: string;
19
/** ISO 3166-1 alpha-3 country code */
20
alpha3: string;
21
/** ISO 3166-1 numeric country code */
22
numeric: string;
23
};
24
25
/**
26
* Complete array of all countries with ISO codes
27
*/
28
const countries: Country[];
29
30
/**
31
* Looks up ISO alpha-2 country code from country name or other ISO codes
32
* @param country - Country name, alpha-2, or alpha-3 code (case-insensitive)
33
* @returns ISO alpha-2 country code
34
* @throws Error if country is not found
35
*/
36
function isoCountryLookup(country: string): string;
37
```
38
39
**Usage Examples:**
40
41
```typescript
42
import { countries, isoCountryLookup } from "medusa-core-utils";
43
44
// Access complete country list
45
console.log(`Total countries: ${countries.length}`); // 249 countries
46
47
// Find specific country
48
const usa = countries.find(c => c.alpha2 === "US");
49
console.log(usa);
50
// { alpha2: "US", name: "United States", alpha3: "USA", numeric: "840" }
51
52
// Lookup by country name
53
const usCode = isoCountryLookup("United States"); // "US"
54
const ukCode = isoCountryLookup("United Kingdom"); // "GB"
55
56
// Lookup by alpha-3 code
57
const deCode = isoCountryLookup("DEU"); // "DE"
58
59
// Case-insensitive lookup
60
const frCode = isoCountryLookup("france"); // "FR"
61
const caCode = isoCountryLookup("CAN"); // "CA"
62
63
// Error handling
64
try {
65
const invalidCode = isoCountryLookup("Invalid Country");
66
} catch (error) {
67
console.log(error.message); // "Invalid country name"
68
}
69
70
// Validate shipping addresses
71
function validateShippingCountry(countryInput: string): string {
72
try {
73
return isoCountryLookup(countryInput);
74
} catch (error) {
75
throw new Error(`Invalid shipping country: ${countryInput}`);
76
}
77
}
78
```
79
80
### CORS Origin Parsing
81
82
Parse and convert CORS origin strings into arrays of strings and regular expressions.
83
84
```typescript { .api }
85
/**
86
* Parses a comma-separated CORS origin string into an array of origins
87
* Automatically converts regex patterns to RegExp objects
88
* @param str - Comma-separated string of origins, may include regex patterns
89
* @returns Array of origin strings and RegExp objects
90
*/
91
function parseCorsOrigins(str: string): (string | RegExp)[];
92
```
93
94
**Usage Examples:**
95
96
```typescript
97
import { parseCorsOrigins } from "medusa-core-utils";
98
99
// Simple origins
100
const simpleOrigins = parseCorsOrigins("http://localhost:3000,https://example.com");
101
// ["http://localhost:3000", "https://example.com"]
102
103
// Mixed origins with regex patterns
104
const mixedOrigins = parseCorsOrigins(
105
"http://localhost:3000,/https:\\/\\/.*\\.example\\.com/i,https://api.test.com"
106
);
107
// ["http://localhost:3000", /https:\/\/.*\.example\.com/i, "https://api.test.com"]
108
109
// Empty string handling
110
const emptyOrigins = parseCorsOrigins(""); // []
111
112
// Use with Express CORS
113
import cors from "cors";
114
115
const corsOptions = {
116
origin: parseCorsOrigins(process.env.ALLOWED_ORIGINS || ""),
117
credentials: true
118
};
119
120
app.use(cors(corsOptions));
121
122
// Dynamic CORS configuration
123
function setupCORS(environment: string) {
124
let allowedOrigins = "";
125
126
switch (environment) {
127
case "development":
128
allowedOrigins = "http://localhost:3000,http://localhost:3001";
129
break;
130
case "staging":
131
allowedOrigins = "/https:\\/\\/.*\\.staging\\.example\\.com/i";
132
break;
133
case "production":
134
allowedOrigins = "https://example.com,https://www.example.com";
135
break;
136
}
137
138
return parseCorsOrigins(allowedOrigins);
139
}
140
```
141
142
### Field Transformation
143
144
Transform object fields by appending '_id' suffix to string values, useful for API payload normalization.
145
146
```typescript { .api }
147
/**
148
* Transform object fields by appending '_id' suffix to string values
149
* @param obj - The object to transform
150
* @param fields - Array of field names to apply transformation to
151
* @returns New object with transformed field names
152
*/
153
function transformIdableFields<
154
T extends object = Record<string, unknown>,
155
TFields extends (keyof T | string)[] = (keyof T | string)[],
156
TOutput = {
157
[P in ComputePropertyNames<T, keyof T & string, TFields>]: P extends keyof T
158
? T[P]
159
: string
160
}
161
>(obj: T, fields: TFields): TOutput;
162
163
/**
164
* Type utility for computing transformed property names
165
*/
166
type ComputePropertyNames<
167
T,
168
TKey extends keyof T & string,
169
TFields extends (keyof T | string)[] = (keyof T | string)[]
170
> = TKey extends TFields[number]
171
? T[TKey] extends string
172
? `${TKey}_id`
173
: TKey
174
: TKey;
175
```
176
177
**Usage Examples:**
178
179
```typescript
180
import { transformIdableFields } from "medusa-core-utils";
181
182
// Basic transformation
183
const input = {
184
user: "user123", // string - will be transformed
185
category: "electronics", // string - will be transformed
186
price: 29.99, // number - will not be transformed
187
active: true // boolean - will not be transformed
188
};
189
190
const transformed = transformIdableFields(input, ["user", "category"]);
191
console.log(transformed);
192
// {
193
// user_id: "user123",
194
// category_id: "electronics",
195
// price: 29.99,
196
// active: true
197
// }
198
199
// API payload normalization
200
interface ProductInput {
201
name: string;
202
category: string | { id: string; name: string };
203
brand: string | { id: string; name: string };
204
price: number;
205
}
206
207
function normalizeProductPayload(payload: ProductInput) {
208
// Transform string references to _id fields
209
return transformIdableFields(payload, ["category", "brand"]);
210
}
211
212
const apiPayload = {
213
name: "Laptop",
214
category: "electronics", // String ID reference
215
brand: "apple", // String ID reference
216
price: 999.99
217
};
218
219
const normalized = normalizeProductPayload(apiPayload);
220
// { name: "Laptop", category_id: "electronics", brand_id: "apple", price: 999.99 }
221
222
// Handling mixed field types
223
const mixedInput = {
224
user: { id: "user123", name: "John" }, // Object - not transformed
225
role: "admin", // String - will be transformed
226
permissions: ["read", "write"], // Array - not transformed
227
status: "active" // String - will be transformed
228
};
229
230
const mixedResult = transformIdableFields(mixedInput, ["user", "role", "status"]);
231
// { user: { id: "user123", name: "John" }, role_id: "admin", permissions: ["read", "write"], status_id: "active" }
232
```
233
234
### Type-Safe Validation
235
236
Type-safe undefined checking with proper type guards.
237
238
```typescript { .api }
239
/**
240
* Type-safe check for defined values with proper type narrowing
241
* @param val - Value to check for undefined
242
* @returns Type predicate indicating if value is defined
243
*/
244
function isDefined<T = undefined | unknown>(
245
val: T
246
): val is T extends undefined ? never : T;
247
```
248
249
**Usage Examples:**
250
251
```typescript
252
import { isDefined } from "medusa-core-utils";
253
254
// Basic undefined checking
255
const maybeString: string | undefined = getValue();
256
257
if (isDefined(maybeString)) {
258
// TypeScript knows maybeString is string here
259
console.log(maybeString.toUpperCase()); // No type error
260
}
261
262
// Array filtering
263
const mixedArray: (string | undefined | null)[] = [
264
"hello",
265
undefined,
266
"world",
267
null,
268
"test"
269
];
270
271
const definedStrings = mixedArray.filter(isDefined);
272
// TypeScript infers definedStrings as (string | null)[]
273
274
// Function parameter validation
275
function processUserData(user: {
276
id?: string;
277
name?: string;
278
email?: string;
279
}) {
280
const requiredFields = [user.id, user.name, user.email];
281
282
if (!requiredFields.every(isDefined)) {
283
throw new Error("Missing required user fields");
284
}
285
286
// TypeScript knows all fields are defined here
287
return {
288
id: user.id, // string (not string | undefined)
289
name: user.name, // string (not string | undefined)
290
email: user.email // string (not string | undefined)
291
};
292
}
293
294
// Optional chaining with type safety
295
interface NestedData {
296
user?: {
297
profile?: {
298
settings?: {
299
theme: string;
300
};
301
};
302
};
303
}
304
305
function getTheme(data: NestedData): string | undefined {
306
const theme = data.user?.profile?.settings?.theme;
307
308
if (isDefined(theme)) {
309
return theme; // TypeScript knows this is string
310
}
311
312
return undefined;
313
}
314
```
315
316
### Index Types
317
318
Constants for indexing and search operations.
319
320
```typescript { .api }
321
/**
322
* Index type constants for search and indexing operations
323
*/
324
const indexTypes: {
325
products: "products";
326
};
327
```
328
329
**Usage Examples:**
330
331
```typescript
332
import { indexTypes } from "medusa-core-utils";
333
334
// Search index configuration
335
const searchConfig = {
336
[indexTypes.products]: {
337
mappings: {
338
title: { type: "text", analyzer: "standard" },
339
description: { type: "text", analyzer: "standard" },
340
price: { type: "float" },
341
category: { type: "keyword" }
342
}
343
}
344
};
345
346
// Index type validation
347
function validateIndexType(type: string): boolean {
348
return Object.values(indexTypes).includes(type as any);
349
}
350
351
// Search operations
352
async function searchIndex(type: keyof typeof indexTypes, query: string) {
353
if (type === indexTypes.products) {
354
return await searchProducts(query);
355
}
356
357
throw new Error(`Unsupported index type: ${type}`);
358
}