@youversion/platform-core 1.2.0 → 1.3.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.
- package/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +20 -0
- package/dist/index.cjs +19 -10
- package/dist/index.d.cts +7 -6
- package/dist/index.d.ts +7 -6
- package/dist/index.js +19 -10
- package/package.json +1 -1
- package/src/__tests__/{MockLangauges.ts → MockLanguages.ts} +3 -3
- package/src/__tests__/bible.test.ts +50 -0
- package/src/__tests__/client.test.ts +55 -0
- package/src/__tests__/handlers.ts +1 -1
- package/src/__tests__/languages.test.ts +9 -8
- package/src/bible.ts +11 -5
- package/src/client.ts +14 -4
- package/src/languages.ts +7 -6
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @youversion/platform-core@1.
|
|
2
|
+
> @youversion/platform-core@1.3.0 build /home/runner/work/platform-sdk-react/platform-sdk-react/packages/core
|
|
3
3
|
> tsup src/index.ts --format cjs,esm --dts
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
[34mCLI[39m Target: es2022
|
|
9
9
|
[34mCJS[39m Build start
|
|
10
10
|
[34mESM[39m Build start
|
|
11
|
-
[
|
|
12
|
-
[
|
|
13
|
-
[
|
|
14
|
-
[
|
|
11
|
+
[32mESM[39m [1mdist/index.js [22m[32m41.47 KB[39m
|
|
12
|
+
[32mESM[39m ⚡️ Build success in 34ms
|
|
13
|
+
[32mCJS[39m [1mdist/index.cjs [22m[32m43.29 KB[39m
|
|
14
|
+
[32mCJS[39m ⚡️ Build success in 35ms
|
|
15
15
|
[34mDTS[39m Build start
|
|
16
|
-
[32mDTS[39m ⚡️ Build success in
|
|
17
|
-
[32mDTS[39m [1mdist/index.d.cts [22m[32m32.
|
|
18
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m32.
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 1804ms
|
|
17
|
+
[32mDTS[39m [1mdist/index.d.cts [22m[32m32.84 KB[39m
|
|
18
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m32.84 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @youversion/platform-core
|
|
2
2
|
|
|
3
|
+
## 1.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- b2b86c2: Add support for array query parameters in API client and improve language range handling
|
|
8
|
+
- **API Client**: Enhanced query string serialization to support array parameters, properly formatting them as repeated keys (e.g., `?param=one¶m=two`)
|
|
9
|
+
- **Bible Client**: Updated `getVersions()` method to accept either a single language range string or an array of language ranges, providing more flexibility for filtering Bible versions
|
|
10
|
+
- **Schema**: Renamed language range schema to use plural naming convention for consistency
|
|
11
|
+
- **Testing**: Added comprehensive test coverage for query string building with both scalar and array parameters
|
|
12
|
+
|
|
13
|
+
This change maintains backward compatibility while providing more flexible API parameter handling.
|
|
14
|
+
|
|
15
|
+
## 1.2.1
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- e845974: fix: make country parameter optional for getLanguages
|
|
20
|
+
|
|
21
|
+
The country parameter is now optional when fetching languages, allowing developers to retrieve all available languages without filtering by country. This improves developer experience by providing a more flexible API while maintaining backward compatibility for existing code that provides a country filter.
|
|
22
|
+
|
|
3
23
|
## 1.2.0
|
|
4
24
|
|
|
5
25
|
### Minor Changes
|
package/dist/index.cjs
CHANGED
|
@@ -69,9 +69,15 @@ var ApiClient = class {
|
|
|
69
69
|
*/
|
|
70
70
|
buildQueryString(params) {
|
|
71
71
|
if (!params) return "";
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
const searchParams = new URLSearchParams();
|
|
73
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
74
|
+
if (Array.isArray(value)) {
|
|
75
|
+
value.forEach((item) => searchParams.append(key, String(item)));
|
|
76
|
+
} else {
|
|
77
|
+
searchParams.append(key, String(value));
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
const queryString = searchParams.toString();
|
|
75
81
|
return queryString ? `?${queryString}` : "";
|
|
76
82
|
}
|
|
77
83
|
/**
|
|
@@ -205,14 +211,15 @@ var BibleClient = class {
|
|
|
205
211
|
/**
|
|
206
212
|
* Fetches a collection of Bible versions filtered by language ranges.
|
|
207
213
|
*
|
|
208
|
-
* @param language_ranges -
|
|
214
|
+
* @param language_ranges - One or more language codes or ranges to filter the versions (required).
|
|
209
215
|
* @param license_id - Optional license ID to filter versions by license.
|
|
210
216
|
* @returns A promise that resolves to a collection of BibleVersion objects.
|
|
211
217
|
*/
|
|
212
218
|
async getVersions(language_ranges, license_id) {
|
|
213
|
-
|
|
219
|
+
const languageRangeArray = Array.isArray(language_ranges) ? language_ranges : [language_ranges];
|
|
220
|
+
const parsedLanguageRanges = import_zod.z.array(this.languageRangesSchema).nonempty("At least one language range is required").parse(languageRangeArray);
|
|
214
221
|
const params = {
|
|
215
|
-
"language_ranges[]":
|
|
222
|
+
"language_ranges[]": parsedLanguageRanges
|
|
216
223
|
};
|
|
217
224
|
if (license_id !== void 0) {
|
|
218
225
|
params.license_id = license_id;
|
|
@@ -409,13 +416,15 @@ var LanguagesClient = class {
|
|
|
409
416
|
}
|
|
410
417
|
/**
|
|
411
418
|
* Fetches a collection of languages supported in the Platform.
|
|
412
|
-
* @param options Query parameters for pagination and filtering
|
|
419
|
+
* @param options Query parameters for pagination and filtering.
|
|
413
420
|
* @returns A collection of Language objects.
|
|
414
421
|
*/
|
|
415
|
-
async getLanguages(options) {
|
|
422
|
+
async getLanguages(options = {}) {
|
|
416
423
|
const params = {};
|
|
417
|
-
|
|
418
|
-
|
|
424
|
+
if (options.country !== void 0) {
|
|
425
|
+
const country = this.countrySchema.parse(options.country);
|
|
426
|
+
params.country = country;
|
|
427
|
+
}
|
|
419
428
|
if (options.page_size !== void 0) {
|
|
420
429
|
const pageSizeSchema = import_zod2.z.number().int().positive();
|
|
421
430
|
pageSizeSchema.parse(options.page_size);
|
package/dist/index.d.cts
CHANGED
|
@@ -258,7 +258,8 @@ interface HighlightColor {
|
|
|
258
258
|
label: string;
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
-
type
|
|
261
|
+
type PrimitiveQueryParam = string | number | boolean;
|
|
262
|
+
type QueryParams = Record<string, PrimitiveQueryParam | PrimitiveQueryParam[]>;
|
|
262
263
|
type RequestData = Record<string, string | number | boolean | object>;
|
|
263
264
|
type RequestHeaders = Record<string, string>;
|
|
264
265
|
/**
|
|
@@ -333,11 +334,11 @@ declare class BibleClient {
|
|
|
333
334
|
/**
|
|
334
335
|
* Fetches a collection of Bible versions filtered by language ranges.
|
|
335
336
|
*
|
|
336
|
-
* @param language_ranges -
|
|
337
|
+
* @param language_ranges - One or more language codes or ranges to filter the versions (required).
|
|
337
338
|
* @param license_id - Optional license ID to filter versions by license.
|
|
338
339
|
* @returns A promise that resolves to a collection of BibleVersion objects.
|
|
339
340
|
*/
|
|
340
|
-
getVersions(language_ranges: string, license_id?: string | number): Promise<Collection<BibleVersion>>;
|
|
341
|
+
getVersions(language_ranges: string | string[], license_id?: string | number): Promise<Collection<BibleVersion>>;
|
|
341
342
|
/**
|
|
342
343
|
* Fetches a Bible version by its ID.
|
|
343
344
|
* @param id The version ID.
|
|
@@ -449,7 +450,7 @@ declare class BibleClient {
|
|
|
449
450
|
type GetLanguagesOptions = {
|
|
450
451
|
page_size?: number;
|
|
451
452
|
page_token?: string;
|
|
452
|
-
country
|
|
453
|
+
country?: string;
|
|
453
454
|
};
|
|
454
455
|
/**
|
|
455
456
|
* Client for interacting with Languages API endpoints.
|
|
@@ -465,10 +466,10 @@ declare class LanguagesClient {
|
|
|
465
466
|
constructor(client: ApiClient);
|
|
466
467
|
/**
|
|
467
468
|
* Fetches a collection of languages supported in the Platform.
|
|
468
|
-
* @param options Query parameters for pagination and filtering
|
|
469
|
+
* @param options Query parameters for pagination and filtering.
|
|
469
470
|
* @returns A collection of Language objects.
|
|
470
471
|
*/
|
|
471
|
-
getLanguages(options
|
|
472
|
+
getLanguages(options?: GetLanguagesOptions): Promise<Collection<Language>>;
|
|
472
473
|
/**
|
|
473
474
|
* Fetches details about a specific language in the Platform.
|
|
474
475
|
* @param languageId The BCP 47 language code (optionally including script, e.g., "en" or "sr-Latn").
|
package/dist/index.d.ts
CHANGED
|
@@ -258,7 +258,8 @@ interface HighlightColor {
|
|
|
258
258
|
label: string;
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
-
type
|
|
261
|
+
type PrimitiveQueryParam = string | number | boolean;
|
|
262
|
+
type QueryParams = Record<string, PrimitiveQueryParam | PrimitiveQueryParam[]>;
|
|
262
263
|
type RequestData = Record<string, string | number | boolean | object>;
|
|
263
264
|
type RequestHeaders = Record<string, string>;
|
|
264
265
|
/**
|
|
@@ -333,11 +334,11 @@ declare class BibleClient {
|
|
|
333
334
|
/**
|
|
334
335
|
* Fetches a collection of Bible versions filtered by language ranges.
|
|
335
336
|
*
|
|
336
|
-
* @param language_ranges -
|
|
337
|
+
* @param language_ranges - One or more language codes or ranges to filter the versions (required).
|
|
337
338
|
* @param license_id - Optional license ID to filter versions by license.
|
|
338
339
|
* @returns A promise that resolves to a collection of BibleVersion objects.
|
|
339
340
|
*/
|
|
340
|
-
getVersions(language_ranges: string, license_id?: string | number): Promise<Collection<BibleVersion>>;
|
|
341
|
+
getVersions(language_ranges: string | string[], license_id?: string | number): Promise<Collection<BibleVersion>>;
|
|
341
342
|
/**
|
|
342
343
|
* Fetches a Bible version by its ID.
|
|
343
344
|
* @param id The version ID.
|
|
@@ -449,7 +450,7 @@ declare class BibleClient {
|
|
|
449
450
|
type GetLanguagesOptions = {
|
|
450
451
|
page_size?: number;
|
|
451
452
|
page_token?: string;
|
|
452
|
-
country
|
|
453
|
+
country?: string;
|
|
453
454
|
};
|
|
454
455
|
/**
|
|
455
456
|
* Client for interacting with Languages API endpoints.
|
|
@@ -465,10 +466,10 @@ declare class LanguagesClient {
|
|
|
465
466
|
constructor(client: ApiClient);
|
|
466
467
|
/**
|
|
467
468
|
* Fetches a collection of languages supported in the Platform.
|
|
468
|
-
* @param options Query parameters for pagination and filtering
|
|
469
|
+
* @param options Query parameters for pagination and filtering.
|
|
469
470
|
* @returns A collection of Language objects.
|
|
470
471
|
*/
|
|
471
|
-
getLanguages(options
|
|
472
|
+
getLanguages(options?: GetLanguagesOptions): Promise<Collection<Language>>;
|
|
472
473
|
/**
|
|
473
474
|
* Fetches details about a specific language in the Platform.
|
|
474
475
|
* @param languageId The BCP 47 language code (optionally including script, e.g., "en" or "sr-Latn").
|
package/dist/index.js
CHANGED
|
@@ -30,9 +30,15 @@ var ApiClient = class {
|
|
|
30
30
|
*/
|
|
31
31
|
buildQueryString(params) {
|
|
32
32
|
if (!params) return "";
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
const searchParams = new URLSearchParams();
|
|
34
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
35
|
+
if (Array.isArray(value)) {
|
|
36
|
+
value.forEach((item) => searchParams.append(key, String(item)));
|
|
37
|
+
} else {
|
|
38
|
+
searchParams.append(key, String(value));
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
const queryString = searchParams.toString();
|
|
36
42
|
return queryString ? `?${queryString}` : "";
|
|
37
43
|
}
|
|
38
44
|
/**
|
|
@@ -166,14 +172,15 @@ var BibleClient = class {
|
|
|
166
172
|
/**
|
|
167
173
|
* Fetches a collection of Bible versions filtered by language ranges.
|
|
168
174
|
*
|
|
169
|
-
* @param language_ranges -
|
|
175
|
+
* @param language_ranges - One or more language codes or ranges to filter the versions (required).
|
|
170
176
|
* @param license_id - Optional license ID to filter versions by license.
|
|
171
177
|
* @returns A promise that resolves to a collection of BibleVersion objects.
|
|
172
178
|
*/
|
|
173
179
|
async getVersions(language_ranges, license_id) {
|
|
174
|
-
|
|
180
|
+
const languageRangeArray = Array.isArray(language_ranges) ? language_ranges : [language_ranges];
|
|
181
|
+
const parsedLanguageRanges = z.array(this.languageRangesSchema).nonempty("At least one language range is required").parse(languageRangeArray);
|
|
175
182
|
const params = {
|
|
176
|
-
"language_ranges[]":
|
|
183
|
+
"language_ranges[]": parsedLanguageRanges
|
|
177
184
|
};
|
|
178
185
|
if (license_id !== void 0) {
|
|
179
186
|
params.license_id = license_id;
|
|
@@ -370,13 +377,15 @@ var LanguagesClient = class {
|
|
|
370
377
|
}
|
|
371
378
|
/**
|
|
372
379
|
* Fetches a collection of languages supported in the Platform.
|
|
373
|
-
* @param options Query parameters for pagination and filtering
|
|
380
|
+
* @param options Query parameters for pagination and filtering.
|
|
374
381
|
* @returns A collection of Language objects.
|
|
375
382
|
*/
|
|
376
|
-
async getLanguages(options) {
|
|
383
|
+
async getLanguages(options = {}) {
|
|
377
384
|
const params = {};
|
|
378
|
-
|
|
379
|
-
|
|
385
|
+
if (options.country !== void 0) {
|
|
386
|
+
const country = this.countrySchema.parse(options.country);
|
|
387
|
+
params.country = country;
|
|
388
|
+
}
|
|
380
389
|
if (options.page_size !== void 0) {
|
|
381
390
|
const pageSizeSchema = z2.number().int().positive();
|
|
382
391
|
pageSizeSchema.parse(options.page_size);
|
package/package.json
CHANGED
|
@@ -76,8 +76,8 @@ export const mockLanguages: Language[] = [
|
|
|
76
76
|
speaking_population: 8000000,
|
|
77
77
|
default_bible_version_id: null,
|
|
78
78
|
},
|
|
79
|
-
// Add more languages to
|
|
80
|
-
...Array.from({ length:
|
|
79
|
+
// Add more languages to exceed the maximum page size and exercise pagination
|
|
80
|
+
...Array.from({ length: 120 }, (_, i) => ({
|
|
81
81
|
id: `lang${i + 1}`,
|
|
82
82
|
language: `lang${i + 1}`,
|
|
83
83
|
script: 'Latn',
|
|
@@ -86,7 +86,7 @@ export const mockLanguages: Language[] = [
|
|
|
86
86
|
display_names: {},
|
|
87
87
|
scripts: ['Latn'],
|
|
88
88
|
variants: [],
|
|
89
|
-
countries: ['US'],
|
|
89
|
+
countries: i % 2 === 0 ? ['US', 'CA'] : ['BR'],
|
|
90
90
|
text_direction: 'ltr' as const,
|
|
91
91
|
writing_population: 1000000,
|
|
92
92
|
speaking_population: 1000000,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { http, HttpResponse } from 'msw';
|
|
2
3
|
import { ApiClient } from '../client';
|
|
3
4
|
import { BibleClient } from '../bible';
|
|
4
5
|
import {
|
|
@@ -9,6 +10,8 @@ import {
|
|
|
9
10
|
BibleVersionSchema,
|
|
10
11
|
VOTDSchema,
|
|
11
12
|
} from '../schemas';
|
|
13
|
+
import { server } from './setup';
|
|
14
|
+
import { mockVersions } from './MockVersions';
|
|
12
15
|
|
|
13
16
|
describe('BibleClient', () => {
|
|
14
17
|
let apiClient: ApiClient;
|
|
@@ -34,6 +37,50 @@ describe('BibleClient', () => {
|
|
|
34
37
|
expect(hasNIV).toBe(true);
|
|
35
38
|
});
|
|
36
39
|
|
|
40
|
+
it('should send multiple language ranges when provided', async () => {
|
|
41
|
+
server.use(
|
|
42
|
+
http.get('https://api.youversion.com/v1/bibles', ({ request }) => {
|
|
43
|
+
const url = new URL(request.url);
|
|
44
|
+
const languageRanges = url.searchParams.getAll('language_ranges[]');
|
|
45
|
+
|
|
46
|
+
expect(languageRanges).toEqual(['en*', 'es*']);
|
|
47
|
+
|
|
48
|
+
return HttpResponse.json({
|
|
49
|
+
data: mockVersions,
|
|
50
|
+
next_page_token: null,
|
|
51
|
+
total_size: mockVersions.length,
|
|
52
|
+
});
|
|
53
|
+
}),
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const versions = await bibleClient.getVersions(['en*', 'es*']);
|
|
57
|
+
|
|
58
|
+
const { success } = BibleVersionSchema.safeParse(versions.data[0]);
|
|
59
|
+
expect(success).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should accept a wildcard language range', async () => {
|
|
63
|
+
server.use(
|
|
64
|
+
http.get('https://api.youversion.com/v1/bibles', ({ request }) => {
|
|
65
|
+
const url = new URL(request.url);
|
|
66
|
+
const languageRanges = url.searchParams.getAll('language_ranges[]');
|
|
67
|
+
|
|
68
|
+
expect(languageRanges).toEqual(['*']);
|
|
69
|
+
|
|
70
|
+
return HttpResponse.json({
|
|
71
|
+
data: mockVersions,
|
|
72
|
+
next_page_token: null,
|
|
73
|
+
total_size: mockVersions.length,
|
|
74
|
+
});
|
|
75
|
+
}),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const versions = await bibleClient.getVersions('*');
|
|
79
|
+
|
|
80
|
+
const { success } = BibleVersionSchema.safeParse(versions.data[0]);
|
|
81
|
+
expect(success).toBe(true);
|
|
82
|
+
});
|
|
83
|
+
|
|
37
84
|
it('should throw an error for invalid language ranges', async () => {
|
|
38
85
|
await expect(bibleClient.getVersions('')).rejects.toThrow(
|
|
39
86
|
'Language ranges must be a non-empty string',
|
|
@@ -41,6 +88,9 @@ describe('BibleClient', () => {
|
|
|
41
88
|
await expect(bibleClient.getVersions(' ')).rejects.toThrow(
|
|
42
89
|
'Language ranges must be a non-empty string',
|
|
43
90
|
);
|
|
91
|
+
await expect(bibleClient.getVersions([])).rejects.toThrow(
|
|
92
|
+
'At least one language range is required',
|
|
93
|
+
);
|
|
44
94
|
});
|
|
45
95
|
});
|
|
46
96
|
|
|
@@ -43,6 +43,45 @@ describe('ApiClient', () => {
|
|
|
43
43
|
});
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
+
describe('buildQueryString', () => {
|
|
47
|
+
const buildQueryString = (params?: Parameters<ApiClient['get']>[1]) =>
|
|
48
|
+
(
|
|
49
|
+
apiClient as unknown as {
|
|
50
|
+
buildQueryString: (params?: Parameters<ApiClient['get']>[1]) => string;
|
|
51
|
+
}
|
|
52
|
+
).buildQueryString(params);
|
|
53
|
+
|
|
54
|
+
it('should serialize single scalar parameter', () => {
|
|
55
|
+
const query = buildQueryString({ param: 'value' });
|
|
56
|
+
|
|
57
|
+
expect(query).toBe('?param=value');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should serialize an array of length 1 as repeated key', () => {
|
|
61
|
+
const query = buildQueryString({ param: ['only'] });
|
|
62
|
+
|
|
63
|
+
expect(query).toBe('?param=only');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should serialize an array of length 2 as repeated keys', () => {
|
|
67
|
+
const query = buildQueryString({ param: ['one', 'two'] });
|
|
68
|
+
|
|
69
|
+
expect(query).toBe('?param=one¶m=two');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should serialize an array of length 3 as repeated keys', () => {
|
|
73
|
+
const query = buildQueryString({ param: ['one', 'two', 'three'] });
|
|
74
|
+
|
|
75
|
+
expect(query).toBe('?param=one¶m=two¶m=three');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should handle both scalar and array parameters together', () => {
|
|
79
|
+
const query = buildQueryString({ param: 'value', list: ['one', 'two'] });
|
|
80
|
+
|
|
81
|
+
expect(query).toBe('?param=value&list=one&list=two');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
46
85
|
describe('get', () => {
|
|
47
86
|
it('should make GET request and return data', async () => {
|
|
48
87
|
server.use(
|
|
@@ -71,6 +110,22 @@ describe('ApiClient', () => {
|
|
|
71
110
|
|
|
72
111
|
expect(result).toEqual({ param: 'value' });
|
|
73
112
|
});
|
|
113
|
+
|
|
114
|
+
it('should include array query parameters as repeated keys', async () => {
|
|
115
|
+
server.use(
|
|
116
|
+
http.get('https://test_placeholder.youversion.com/test', ({ request }) => {
|
|
117
|
+
const url = new URL(request.url);
|
|
118
|
+
const params = url.searchParams.getAll('param');
|
|
119
|
+
return HttpResponse.json({ params });
|
|
120
|
+
}),
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const result = await apiClient.get<{ params: string[] }>('/test', {
|
|
124
|
+
param: ['one', 'two'],
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
expect(result).toEqual({ params: ['one', 'two'] });
|
|
128
|
+
});
|
|
74
129
|
});
|
|
75
130
|
|
|
76
131
|
describe('post', () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { http, HttpResponse } from 'msw';
|
|
2
2
|
import type { Collection, Highlight, Language } from '../types';
|
|
3
|
-
import { mockLanguages } from './
|
|
3
|
+
import { mockLanguages } from './MockLanguages';
|
|
4
4
|
import { mockVersions, mockVersionKJV } from './MockVersions';
|
|
5
5
|
import { mockBibleGenesis, mockBibleBooks } from './MockBibles';
|
|
6
6
|
import { mockChapterGenesis1, mockGenesisChapters } from './MockChapters';
|
|
@@ -17,22 +17,23 @@ describe('LanguagesClient', () => {
|
|
|
17
17
|
});
|
|
18
18
|
|
|
19
19
|
describe('getLanguages', () => {
|
|
20
|
-
it('should fetch languages
|
|
21
|
-
const languages = await languagesClient.getLanguages({
|
|
20
|
+
it('should fetch languages without country filter', async () => {
|
|
21
|
+
const languages = await languagesClient.getLanguages({ page_size: 99 });
|
|
22
22
|
|
|
23
23
|
const { success } = LanguageSchema.safeParse(languages.data[0]);
|
|
24
24
|
expect(success).toBe(true);
|
|
25
|
-
expect(languages.data).toHaveLength(
|
|
26
|
-
expect(languages.
|
|
25
|
+
expect(languages.data).toHaveLength(99);
|
|
26
|
+
expect(languages.next_page_token).not.toBeNull();
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
it('should fetch languages with
|
|
30
|
-
const languages = await languagesClient.getLanguages({ country: 'US', page_size:
|
|
29
|
+
it('should fetch languages with country filter', async () => {
|
|
30
|
+
const languages = await languagesClient.getLanguages({ country: 'US', page_size: 20 });
|
|
31
31
|
|
|
32
32
|
const { success } = LanguageSchema.safeParse(languages.data[0]);
|
|
33
33
|
expect(success).toBe(true);
|
|
34
|
-
expect(languages.data).toHaveLength(
|
|
35
|
-
expect(languages.
|
|
34
|
+
expect(languages.data).toHaveLength(20);
|
|
35
|
+
expect(languages.data.every((language) => language.countries?.includes('US'))).toBe(true);
|
|
36
|
+
expect(languages.next_page_token).not.toBeNull();
|
|
36
37
|
});
|
|
37
38
|
|
|
38
39
|
it('should throw an error for invalid country code - empty string', async () => {
|
package/src/bible.ts
CHANGED
|
@@ -50,17 +50,23 @@ export class BibleClient {
|
|
|
50
50
|
/**
|
|
51
51
|
* Fetches a collection of Bible versions filtered by language ranges.
|
|
52
52
|
*
|
|
53
|
-
* @param language_ranges -
|
|
53
|
+
* @param language_ranges - One or more language codes or ranges to filter the versions (required).
|
|
54
54
|
* @param license_id - Optional license ID to filter versions by license.
|
|
55
55
|
* @returns A promise that resolves to a collection of BibleVersion objects.
|
|
56
56
|
*/
|
|
57
57
|
async getVersions(
|
|
58
|
-
language_ranges: string,
|
|
58
|
+
language_ranges: string | string[],
|
|
59
59
|
license_id?: string | number,
|
|
60
60
|
): Promise<Collection<BibleVersion>> {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
const languageRangeArray = Array.isArray(language_ranges) ? language_ranges : [language_ranges];
|
|
62
|
+
|
|
63
|
+
const parsedLanguageRanges = z
|
|
64
|
+
.array(this.languageRangesSchema)
|
|
65
|
+
.nonempty('At least one language range is required')
|
|
66
|
+
.parse(languageRangeArray);
|
|
67
|
+
|
|
68
|
+
const params: Record<string, string | number | string[]> = {
|
|
69
|
+
'language_ranges[]': parsedLanguageRanges,
|
|
64
70
|
};
|
|
65
71
|
if (license_id !== undefined) {
|
|
66
72
|
params.license_id = license_id;
|
package/src/client.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ApiConfig } from './types';
|
|
2
2
|
|
|
3
|
-
type
|
|
3
|
+
type PrimitiveQueryParam = string | number | boolean;
|
|
4
|
+
type QueryParams = Record<string, PrimitiveQueryParam | PrimitiveQueryParam[]>;
|
|
4
5
|
type RequestData = Record<string, string | number | boolean | object>;
|
|
5
6
|
type RequestHeaders = Record<string, string>;
|
|
6
7
|
|
|
@@ -41,9 +42,18 @@ export class ApiClient {
|
|
|
41
42
|
*/
|
|
42
43
|
private buildQueryString(params?: QueryParams): string {
|
|
43
44
|
if (!params) return '';
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
|
|
46
|
+
const searchParams = new URLSearchParams();
|
|
47
|
+
|
|
48
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
49
|
+
if (Array.isArray(value)) {
|
|
50
|
+
value.forEach((item) => searchParams.append(key, String(item)));
|
|
51
|
+
} else {
|
|
52
|
+
searchParams.append(key, String(value));
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const queryString = searchParams.toString();
|
|
47
57
|
return queryString ? `?${queryString}` : '';
|
|
48
58
|
}
|
|
49
59
|
|
package/src/languages.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type { Collection, Language } from './types';
|
|
|
8
8
|
export type GetLanguagesOptions = {
|
|
9
9
|
page_size?: number;
|
|
10
10
|
page_token?: string;
|
|
11
|
-
country
|
|
11
|
+
country?: string; // ISO 3166-1 alpha-2 country code
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -41,15 +41,16 @@ export class LanguagesClient {
|
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* Fetches a collection of languages supported in the Platform.
|
|
44
|
-
* @param options Query parameters for pagination and filtering
|
|
44
|
+
* @param options Query parameters for pagination and filtering.
|
|
45
45
|
* @returns A collection of Language objects.
|
|
46
46
|
*/
|
|
47
|
-
async getLanguages(options: GetLanguagesOptions): Promise<Collection<Language>> {
|
|
47
|
+
async getLanguages(options: GetLanguagesOptions = {}): Promise<Collection<Language>> {
|
|
48
48
|
const params: Record<string, string | number> = {};
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
if (options.country !== undefined) {
|
|
51
|
+
const country = this.countrySchema.parse(options.country);
|
|
52
|
+
params.country = country;
|
|
53
|
+
}
|
|
53
54
|
|
|
54
55
|
if (options.page_size !== undefined) {
|
|
55
56
|
const pageSizeSchema = z.number().int().positive();
|