@youversion/platform-core 0.4.2 → 0.4.4

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/dist/index.js CHANGED
@@ -7,18 +7,21 @@ var ApiClient = class {
7
7
  /**
8
8
  * Creates an instance of ApiClient.
9
9
  *
10
- * @param config - The API configuration object containing baseUrl, timeout, and appId.
10
+ * @param config - The API configuration object containing baseUrl, timeout, and appKey.
11
11
  */
12
12
  constructor(config) {
13
13
  this.config = {
14
- version: config.version || "v1",
15
14
  ...config
16
15
  };
17
- this.baseURL = config.baseUrl || "https://api-dev.youversion.com";
16
+ const apiHost = config.apiHost || "api.youversion.com";
17
+ if (!apiHost) {
18
+ throw new Error("ApiClient requires a host name. Provide an apiHost in the config.");
19
+ }
20
+ this.baseURL = "https://" + apiHost;
18
21
  this.timeout = config.timeout || 1e4;
19
22
  this.defaultHeaders = {
20
23
  "Content-Type": "application/json",
21
- "X-YVP-App-Key": this.config.appId,
24
+ "X-YVP-App-Key": this.config.appKey,
22
25
  "X-YVP-Installation-Id": this.config.installationId || "web-sdk-default"
23
26
  };
24
27
  }
@@ -160,9 +163,6 @@ var BibleClient = class {
160
163
  constructor(client) {
161
164
  this.client = client;
162
165
  }
163
- get rootPath() {
164
- return `/${this.client.config.version}`;
165
- }
166
166
  /**
167
167
  * Fetches a collection of Bible versions filtered by language ranges.
168
168
  *
@@ -178,7 +178,7 @@ var BibleClient = class {
178
178
  if (license_id !== void 0) {
179
179
  params.license_id = license_id;
180
180
  }
181
- return this.client.get(`${this.rootPath}/bibles`, params);
181
+ return this.client.get(`/v1/bibles`, params);
182
182
  }
183
183
  /**
184
184
  * Fetches a Bible version by its ID.
@@ -187,7 +187,7 @@ var BibleClient = class {
187
187
  */
188
188
  async getVersion(id) {
189
189
  this.versionIdSchema.parse(id);
190
- return this.client.get(`${this.rootPath}/bibles/${id}`);
190
+ return this.client.get(`/v1/bibles/${id}`);
191
191
  }
192
192
  /**
193
193
  * Fetches all books for a given Bible version.
@@ -197,7 +197,7 @@ var BibleClient = class {
197
197
  */
198
198
  async getBooks(versionId, canon) {
199
199
  this.versionIdSchema.parse(versionId);
200
- return this.client.get(`${this.rootPath}/bibles/${versionId}/books`, {
200
+ return this.client.get(`/v1/bibles/${versionId}/books`, {
201
201
  ...canon && { canon }
202
202
  });
203
203
  }
@@ -210,7 +210,7 @@ var BibleClient = class {
210
210
  async getBook(versionId, book) {
211
211
  this.versionIdSchema.parse(versionId);
212
212
  this.bookSchema.parse(book);
213
- return this.client.get(`${this.rootPath}/bibles/${versionId}/books/${book}`);
213
+ return this.client.get(`/v1/bibles/${versionId}/books/${book}`);
214
214
  }
215
215
  /**
216
216
  * Fetches all chapters for a specific book in a version.
@@ -222,7 +222,7 @@ var BibleClient = class {
222
222
  this.versionIdSchema.parse(versionId);
223
223
  this.bookSchema.parse(book);
224
224
  return this.client.get(
225
- `${this.rootPath}/bibles/${versionId}/books/${book}/chapters`
225
+ `/v1/bibles/${versionId}/books/${book}/chapters`
226
226
  );
227
227
  }
228
228
  /**
@@ -237,7 +237,7 @@ var BibleClient = class {
237
237
  this.bookSchema.parse(book);
238
238
  this.chapterSchema.parse(chapter);
239
239
  return this.client.get(
240
- `${this.rootPath}/bibles/${versionId}/books/${book}/chapters/${chapter}`
240
+ `/v1/bibles/${versionId}/books/${book}/chapters/${chapter}`
241
241
  );
242
242
  }
243
243
  /**
@@ -252,7 +252,7 @@ var BibleClient = class {
252
252
  this.bookSchema.parse(book);
253
253
  this.chapterSchema.parse(chapter);
254
254
  return this.client.get(
255
- `${this.rootPath}/bibles/${versionId}/books/${book}/chapters/${chapter}/verses`
255
+ `/v1/bibles/${versionId}/books/${book}/chapters/${chapter}/verses`
256
256
  );
257
257
  }
258
258
  /**
@@ -269,7 +269,7 @@ var BibleClient = class {
269
269
  this.chapterSchema.parse(chapter);
270
270
  this.verseSchema.parse(verse);
271
271
  return this.client.get(
272
- `${this.rootPath}/bibles/${versionId}/books/${book}/chapters/${chapter}/verses/${verse}`
272
+ `/v1/bibles/${versionId}/books/${book}/chapters/${chapter}/verses/${verse}`
273
273
  );
274
274
  }
275
275
  /**
@@ -310,10 +310,7 @@ var BibleClient = class {
310
310
  if (include_notes !== void 0) {
311
311
  params.include_notes = include_notes;
312
312
  }
313
- return this.client.get(
314
- `${this.rootPath}/bibles/${versionId}/passages/${usfm}`,
315
- params
316
- );
313
+ return this.client.get(`/v1/bibles/${versionId}/passages/${usfm}`, params);
317
314
  }
318
315
  /**
319
316
  * Fetches the indexing structure for a Bible version.
@@ -322,14 +319,14 @@ var BibleClient = class {
322
319
  */
323
320
  async getIndex(versionId) {
324
321
  this.versionIdSchema.parse(versionId);
325
- return this.client.get(`${this.rootPath}/bibles/${versionId}/index`);
322
+ return this.client.get(`/v1/bibles/${versionId}/index`);
326
323
  }
327
324
  /**
328
325
  * Fetches the verse of the day calendar for an entire year.
329
326
  * @returns A collection of VOTD objects for all days of the year.
330
327
  */
331
328
  async getAllVOTDs() {
332
- return this.client.get(`${this.rootPath}/verse_of_the_days`);
329
+ return this.client.get(`/v1/verse_of_the_days`);
333
330
  }
334
331
  /**
335
332
  * Fetches the passage_id for the Verse Of The Day.
@@ -347,7 +344,7 @@ var BibleClient = class {
347
344
  async getVOTD(day) {
348
345
  const daySchema = z.number().int().min(1).max(366);
349
346
  daySchema.parse(day);
350
- return this.client.get(`${this.rootPath}/verse_of_the_days/${day}`);
347
+ return this.client.get(`/v1/verse_of_the_days/${day}`);
351
348
  }
352
349
  };
353
350
 
@@ -367,9 +364,6 @@ var LanguagesClient = class {
367
364
  constructor(client) {
368
365
  this.client = client;
369
366
  }
370
- get rootPath() {
371
- return `/${this.client.config.version}`;
372
- }
373
367
  /**
374
368
  * Fetches a collection of languages supported in the Platform.
375
369
  * @param options Query parameters for pagination and filtering (country is required).
@@ -387,7 +381,7 @@ var LanguagesClient = class {
387
381
  if (options.page_token !== void 0) {
388
382
  params.page_token = options.page_token;
389
383
  }
390
- return this.client.get(`${this.rootPath}/languages`, params);
384
+ return this.client.get(`/v1/languages`, params);
391
385
  }
392
386
  /**
393
387
  * Fetches details about a specific language in the Platform.
@@ -396,7 +390,7 @@ var LanguagesClient = class {
396
390
  */
397
391
  async getLanguage(languageId) {
398
392
  this.languageIdSchema.parse(languageId);
399
- return this.client.get(`${this.rootPath}/languages/${languageId}`);
393
+ return this.client.get(`/v1/languages/${languageId}`);
400
394
  }
401
395
  };
402
396
 
@@ -405,10 +399,10 @@ import { z as z3 } from "zod";
405
399
 
406
400
  // src/YouVersionPlatformConfiguration.ts
407
401
  var YouVersionPlatformConfiguration = class {
408
- static _appId = null;
402
+ static _appKey = null;
409
403
  static _installationId = null;
410
404
  static _accessToken = null;
411
- static _apiHost = "api-dev.youversion.com";
405
+ static _apiHost = "api.youversion.com";
412
406
  static _isPreviewMode = false;
413
407
  static _previewUserInfo = null;
414
408
  static getOrSetInstallationId() {
@@ -423,11 +417,11 @@ var YouVersionPlatformConfiguration = class {
423
417
  localStorage.setItem("x-yvp-installation-id", newId);
424
418
  return newId;
425
419
  }
426
- static get appId() {
427
- return this._appId;
420
+ static get appKey() {
421
+ return this._appKey;
428
422
  }
429
- static set appId(value) {
430
- this._appId = value;
423
+ static set appKey(value) {
424
+ this._appKey = value;
431
425
  }
432
426
  static get installationId() {
433
427
  if (!this._installationId) {
@@ -480,9 +474,6 @@ var HighlightsClient = class {
480
474
  constructor(client) {
481
475
  this.client = client;
482
476
  }
483
- get rootPath() {
484
- return `/${this.client.config.version}`;
485
- }
486
477
  /**
487
478
  * Gets the authentication token, either from the provided parameter or from the platform configuration.
488
479
  * @param lat Optional explicit long access token. If not provided, retrieves from YouVersionPlatformConfiguration.
@@ -552,7 +543,7 @@ var HighlightsClient = class {
552
543
  this.validatePassageId(options.passage_id);
553
544
  params.passage_id = options.passage_id;
554
545
  }
555
- return this.client.get(`${this.rootPath}/highlights`, params);
546
+ return this.client.get(`/v1/highlights`, params);
556
547
  }
557
548
  /**
558
549
  * Creates or updates a highlight on a passage.
@@ -567,7 +558,7 @@ var HighlightsClient = class {
567
558
  this.validatePassageId(data.passage_id);
568
559
  this.validateColor(data.color);
569
560
  const token = this.getAuthToken(lat);
570
- return this.client.post(`${this.rootPath}/highlights`, data, { lat: token });
561
+ return this.client.post(`/v1/highlights`, data, { lat: token });
571
562
  }
572
563
  /**
573
564
  * Clears highlights for a passage.
@@ -587,7 +578,7 @@ var HighlightsClient = class {
587
578
  this.validateVersionId(options.version_id);
588
579
  params.version_id = options.version_id;
589
580
  }
590
- await this.client.delete(`${this.rootPath}/highlights/${passageId}`, params);
581
+ await this.client.delete(`/v1/highlights/${passageId}`, params);
591
582
  }
592
583
  };
593
584
 
@@ -885,13 +876,13 @@ var YouVersionAPI = class {
885
876
  Accept: "application/json",
886
877
  "Content-Type": "application/json"
887
878
  };
888
- const appId = YouVersionPlatformConfiguration.appId;
889
- if (appId) {
890
- headers["X-App-Id"] = appId;
879
+ const appKey = YouVersionPlatformConfiguration.appKey;
880
+ if (appKey) {
881
+ headers["X-YVP-App-Key"] = appKey;
891
882
  }
892
883
  const installationId = YouVersionPlatformConfiguration.installationId;
893
884
  if (installationId) {
894
- headers["x-yvp-installation-id"] = installationId;
885
+ headers["X-YVP-Installation-ID"] = installationId;
895
886
  }
896
887
  const request = new Request(url.toString(), {
897
888
  headers
@@ -905,15 +896,15 @@ var URLBuilder = class {
905
896
  static get baseURL() {
906
897
  return new URL(`https://${YouVersionPlatformConfiguration.apiHost}`);
907
898
  }
908
- static authURL(appId, requiredPermissions = /* @__PURE__ */ new Set(), optionalPermissions = /* @__PURE__ */ new Set()) {
909
- if (typeof appId !== "string" || appId.trim().length === 0) {
910
- throw new Error("appId must be a non-empty string");
899
+ static authURL(appKey, requiredPermissions = /* @__PURE__ */ new Set(), optionalPermissions = /* @__PURE__ */ new Set()) {
900
+ if (typeof appKey !== "string" || appKey.trim().length === 0) {
901
+ throw new Error("appKey must be a non-empty string");
911
902
  }
912
903
  try {
913
904
  const url = new URL(this.baseURL);
914
905
  url.pathname = "/auth/login";
915
906
  const searchParams = new URLSearchParams();
916
- searchParams.append("app_id", appId);
907
+ searchParams.append("APP_KEY", appKey);
917
908
  searchParams.append("language", "en");
918
909
  if (requiredPermissions.size > 0) {
919
910
  const requiredList = Array.from(requiredPermissions).map((p) => p.toString());
@@ -977,11 +968,11 @@ var YouVersionAPIUsers = class {
977
968
  if (!optionalPermissions || !(optionalPermissions instanceof Set)) {
978
969
  throw new Error("Invalid optionalPermissions: must be a Set");
979
970
  }
980
- const appId = YouVersionPlatformConfiguration.appId;
981
- if (!appId) {
982
- throw new Error("YouVersionPlatformConfiguration.appId must be set before calling signIn");
971
+ const appKey = YouVersionPlatformConfiguration.appKey;
972
+ if (!appKey) {
973
+ throw new Error("YouVersionPlatformConfiguration.appKey must be set before calling signIn");
983
974
  }
984
- const url = URLBuilder.authURL(appId, requiredPermissions, optionalPermissions);
975
+ const url = URLBuilder.authURL(appKey, requiredPermissions, optionalPermissions);
985
976
  const strategy = AuthenticationStrategyRegistry.get();
986
977
  const callbackUrl = await strategy.authenticate(url);
987
978
  const result = new SignInWithYouVersionResult(callbackUrl);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@youversion/platform-core",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -28,8 +28,8 @@
28
28
  "msw": "2.11.6",
29
29
  "typescript": "5.9.3",
30
30
  "vitest": "4.0.4",
31
- "@internal/tsconfig": "0.0.0",
32
- "@internal/eslint-config": "0.0.0"
31
+ "@internal/eslint-config": "0.0.0",
32
+ "@internal/tsconfig": "0.0.0"
33
33
  },
34
34
  "dependencies": {
35
35
  "tsup": "8.5.0",
package/src/URLBuilder.ts CHANGED
@@ -7,12 +7,12 @@ export class URLBuilder {
7
7
  }
8
8
 
9
9
  static authURL(
10
- appId: string,
10
+ appKey: string,
11
11
  requiredPermissions: Set<SignInWithYouVersionPermissionValues> = new Set<SignInWithYouVersionPermissionValues>(),
12
12
  optionalPermissions: Set<SignInWithYouVersionPermissionValues> = new Set<SignInWithYouVersionPermissionValues>(),
13
13
  ): URL {
14
- if (typeof appId !== 'string' || appId.trim().length === 0) {
15
- throw new Error('appId must be a non-empty string');
14
+ if (typeof appKey !== 'string' || appKey.trim().length === 0) {
15
+ throw new Error('appKey must be a non-empty string');
16
16
  }
17
17
 
18
18
  try {
@@ -21,7 +21,7 @@ export class URLBuilder {
21
21
 
22
22
  // Add query parameters
23
23
  const searchParams = new URLSearchParams();
24
- searchParams.append('app_id', appId);
24
+ searchParams.append('APP_KEY', appKey);
25
25
  searchParams.append('language', 'en'); // TODO: load from system
26
26
 
27
27
  if (requiredPermissions.size > 0) {
package/src/Users.ts CHANGED
@@ -34,12 +34,12 @@ export class YouVersionAPIUsers {
34
34
  throw new Error('Invalid optionalPermissions: must be a Set');
35
35
  }
36
36
 
37
- const appId = YouVersionPlatformConfiguration.appId;
38
- if (!appId) {
39
- throw new Error('YouVersionPlatformConfiguration.appId must be set before calling signIn');
37
+ const appKey = YouVersionPlatformConfiguration.appKey;
38
+ if (!appKey) {
39
+ throw new Error('YouVersionPlatformConfiguration.appKey must be set before calling signIn');
40
40
  }
41
41
 
42
- const url = URLBuilder.authURL(appId, requiredPermissions, optionalPermissions);
42
+ const url = URLBuilder.authURL(appKey, requiredPermissions, optionalPermissions);
43
43
 
44
44
  // Use the registered authentication strategy
45
45
  const strategy = AuthenticationStrategyRegistry.get();
@@ -7,16 +7,14 @@ export class YouVersionAPI {
7
7
  'Content-Type': 'application/json',
8
8
  };
9
9
 
10
- // Add app ID header
11
- const appId = YouVersionPlatformConfiguration.appId;
12
- if (appId) {
13
- headers['X-App-Id'] = appId;
10
+ const appKey = YouVersionPlatformConfiguration.appKey;
11
+ if (appKey) {
12
+ headers['X-YVP-App-Key'] = appKey;
14
13
  }
15
14
 
16
- // Add installation ID header
17
15
  const installationId = YouVersionPlatformConfiguration.installationId;
18
16
  if (installationId) {
19
- headers['x-yvp-installation-id'] = installationId;
17
+ headers['X-YVP-Installation-ID'] = installationId;
20
18
  }
21
19
 
22
20
  const request = new Request(url.toString(), {
@@ -1,10 +1,10 @@
1
1
  import type { YouVersionUserInfo } from './YouVersionUserInfo';
2
2
 
3
3
  export class YouVersionPlatformConfiguration {
4
- private static _appId: string | null = null;
4
+ private static _appKey: string | null = null;
5
5
  private static _installationId: string | null = null;
6
6
  private static _accessToken: string | null = null;
7
- private static _apiHost: string = 'api-dev.youversion.com';
7
+ private static _apiHost: string = 'api.youversion.com';
8
8
  private static _isPreviewMode: boolean = false;
9
9
  private static _previewUserInfo: YouVersionUserInfo | null = null;
10
10
 
@@ -23,12 +23,12 @@ export class YouVersionPlatformConfiguration {
23
23
  return newId;
24
24
  }
25
25
 
26
- static get appId(): string | null {
27
- return this._appId;
26
+ static get appKey(): string | null {
27
+ return this._appKey;
28
28
  }
29
29
 
30
- static set appId(value: string | null) {
31
- this._appId = value;
30
+ static set appKey(value: string | null) {
31
+ this._appKey = value;
32
32
  }
33
33
 
34
34
  static get installationId(): string {
@@ -5,7 +5,7 @@ import type { SignInWithYouVersionPermissionValues } from '../types';
5
5
 
6
6
  describe('URLBuilder - Input Validation', () => {
7
7
  let originalApiHost: string;
8
- let originalInstallationId: string | undefined;
8
+ let originalInstallationId: string | null;
9
9
 
10
10
  beforeEach(() => {
11
11
  // Store original config
@@ -13,7 +13,11 @@ describe('URLBuilder - Input Validation', () => {
13
13
  originalInstallationId = YouVersionPlatformConfiguration.installationId;
14
14
 
15
15
  // Set test config
16
- YouVersionPlatformConfiguration.apiHost = 'api-dev.youversion.com';
16
+ const apiHost = process.env.YVP_API_HOST;
17
+ if (!apiHost) {
18
+ throw new Error('YVP_API_HOST environment variable must be set for URLBuilder tests.');
19
+ }
20
+ YouVersionPlatformConfiguration.apiHost = apiHost;
17
21
  YouVersionPlatformConfiguration.installationId = 'test-installation-id';
18
22
  });
19
23
 
@@ -23,23 +27,23 @@ describe('URLBuilder - Input Validation', () => {
23
27
  YouVersionPlatformConfiguration.installationId = originalInstallationId;
24
28
  });
25
29
 
26
- describe('authURL - appId validation', () => {
27
- it('should throw error for empty string appId', () => {
30
+ describe('authURL - appKey validation', () => {
31
+ it('should throw error for empty string appKey', () => {
28
32
  expect(() => {
29
33
  URLBuilder.authURL('');
30
- }).toThrow('appId must be a non-empty string');
34
+ }).toThrow('appKey must be a non-empty string');
31
35
  });
32
36
 
33
- it('should throw error for whitespace-only appId', () => {
37
+ it('should throw error for whitespace-only appKey', () => {
34
38
  expect(() => {
35
39
  URLBuilder.authURL(' ');
36
- }).toThrow('appId must be a non-empty string');
40
+ }).toThrow('appKey must be a non-empty string');
37
41
  });
38
42
 
39
- it('should throw error for tab/newline-only appId', () => {
43
+ it('should throw error for tab/newline-only appKey', () => {
40
44
  expect(() => {
41
45
  URLBuilder.authURL('\t\n ');
42
- }).toThrow('appId must be a non-empty string');
46
+ }).toThrow('appKey must be a non-empty string');
43
47
  });
44
48
 
45
49
  it('should throw descriptive error message', () => {
@@ -49,34 +53,34 @@ describe('URLBuilder - Input Validation', () => {
49
53
  expect.fail('Should have thrown an error');
50
54
  } catch (error) {
51
55
  expect(error).toBeInstanceOf(Error);
52
- expect((error as Error).message).toContain('appId');
56
+ expect((error as Error).message).toContain('appKey');
53
57
  expect((error as Error).message).toContain('non-empty string');
54
58
  }
55
59
  });
56
60
 
57
- it('should accept valid non-empty appId', () => {
58
- const url = URLBuilder.authURL('valid-app-id');
61
+ it('should accept valid non-empty appKey', () => {
62
+ const url = URLBuilder.authURL('valid-app-key');
59
63
 
60
64
  expect(url).toBeInstanceOf(URL);
61
- expect(url.hostname).toBe('api-dev.youversion.com');
65
+ expect(url.hostname.endsWith('.youversion.com')).toBe(true);
62
66
  expect(url.pathname).toBe('/auth/login');
63
- expect(url.searchParams.get('app_id')).toBe('valid-app-id');
67
+ expect(url.searchParams.get('APP_KEY')).toBe('valid-app-key');
64
68
  });
65
69
 
66
- it('should trim and accept appId with surrounding whitespace', () => {
70
+ it('should trim and accept appKey with surrounding whitespace', () => {
67
71
  // Note: The validation checks trim().length, so this should pass
68
- const url = URLBuilder.authURL(' valid-app-id ');
72
+ const url = URLBuilder.authURL(' valid-app-key ');
69
73
 
70
74
  expect(url).toBeInstanceOf(URL);
71
75
  // The actual value passed has whitespace preserved in the URL
72
- expect(url.searchParams.get('app_id')).toBe(' valid-app-id ');
76
+ expect(url.searchParams.get('APP_KEY')).toBe(' valid-app-key ');
73
77
  });
74
78
 
75
- it('should accept appId with special characters', () => {
76
- const specialAppId = 'app-id_123.test';
77
- const url = URLBuilder.authURL(specialAppId);
79
+ it('should accept appKey with special characters', () => {
80
+ const specialAppKey = 'app-key_123.test';
81
+ const url = URLBuilder.authURL(specialAppKey);
78
82
 
79
- expect(url.searchParams.get('app_id')).toBe(specialAppId);
83
+ expect(url.searchParams.get('APP_KEY')).toBe(specialAppKey);
80
84
  });
81
85
  });
82
86
 
@@ -85,14 +89,14 @@ describe('URLBuilder - Input Validation', () => {
85
89
  const url = URLBuilder.authURL('test-app');
86
90
 
87
91
  expect(url.protocol).toBe('https:');
88
- expect(url.hostname).toBe('api-dev.youversion.com');
92
+ expect(url.hostname.endsWith('.youversion.com')).toBe(true);
89
93
  expect(url.pathname).toBe('/auth/login');
90
94
  });
91
95
 
92
- it('should include app_id in query parameters', () => {
93
- const url = URLBuilder.authURL('my-app-id');
96
+ it('should include APP_KEY in query parameters', () => {
97
+ const url = URLBuilder.authURL('my-app-key');
94
98
 
95
- expect(url.searchParams.get('app_id')).toBe('my-app-id');
99
+ expect(url.searchParams.get('APP_KEY')).toBe('my-app-key');
96
100
  });
97
101
 
98
102
  it('should include default language parameter', () => {
@@ -109,7 +113,7 @@ describe('URLBuilder - Input Validation', () => {
109
113
  });
110
114
 
111
115
  it('should not include installation ID when not configured', () => {
112
- YouVersionPlatformConfiguration.installationId = undefined;
116
+ YouVersionPlatformConfiguration.installationId = null;
113
117
  const url = URLBuilder.authURL('test-app');
114
118
 
115
119
  expect(url.searchParams.get('x-yvp-installation-id')).toBeNull();
@@ -187,7 +191,7 @@ describe('URLBuilder - Input Validation', () => {
187
191
  const url = URLBuilder.userURL('valid-access-token-123');
188
192
 
189
193
  expect(url).toBeInstanceOf(URL);
190
- expect(url.hostname).toBe('api-dev.youversion.com');
194
+ expect(url.hostname.endsWith('.youversion.com')).toBe(true);
191
195
  expect(url.pathname).toBe('/auth/me');
192
196
  expect(url.searchParams.get('lat')).toBe('valid-access-token-123');
193
197
  });
@@ -205,7 +209,7 @@ describe('URLBuilder - Input Validation', () => {
205
209
  const url = URLBuilder.userURL('test-token');
206
210
 
207
211
  expect(url.protocol).toBe('https:');
208
- expect(url.hostname).toBe('api-dev.youversion.com');
212
+ expect(url.hostname.endsWith('.youversion.com')).toBe(true);
209
213
  expect(url.pathname).toBe('/auth/me');
210
214
  });
211
215
 
@@ -227,7 +231,7 @@ describe('URLBuilder - Input Validation', () => {
227
231
  });
228
232
 
229
233
  describe('Error handling', () => {
230
- it('should throw errors instead of returning null for invalid appId', () => {
234
+ it('should throw errors instead of returning null for invalid appKey', () => {
231
235
  // Verify that the method throws, not returns null
232
236
  let threwError = false;
233
237
  let returnValue: any;
@@ -260,7 +264,7 @@ describe('URLBuilder - Input Validation', () => {
260
264
  // This is hard to trigger, but we can at least verify the pattern exists
261
265
  // by checking that valid inputs don't trigger the catch block
262
266
  expect(() => {
263
- URLBuilder.authURL('valid-app-id');
267
+ URLBuilder.authURL('valid-app-key');
264
268
  }).not.toThrow(/Failed to construct auth URL/);
265
269
  });
266
270
 
@@ -14,13 +14,20 @@ vi.stubGlobal('localStorage', { getItem: mockGetItem, setItem: mockSetItem });
14
14
 
15
15
  import { YouVersionPlatformConfiguration } from '../YouVersionPlatformConfiguration';
16
16
 
17
+ const envApiHost = process.env.YVP_API_HOST || 'api.youversion.com';
18
+ if (!envApiHost) {
19
+ throw new Error(
20
+ 'YVP_API_HOST environment variable must be set for YouVersionPlatformConfiguration tests.',
21
+ );
22
+ }
23
+
17
24
  describe('YouVersionPlatformConfiguration', () => {
18
25
  beforeEach(() => {
19
26
  // Reset all static properties
20
- YouVersionPlatformConfiguration.appId = null;
27
+ YouVersionPlatformConfiguration.appKey = null;
21
28
  YouVersionPlatformConfiguration.installationId = null;
22
29
  YouVersionPlatformConfiguration.setAccessToken(null);
23
- YouVersionPlatformConfiguration.apiHost = 'api-dev.youversion.com';
30
+ YouVersionPlatformConfiguration.apiHost = envApiHost;
24
31
  YouVersionPlatformConfiguration.isPreviewMode = false;
25
32
  YouVersionPlatformConfiguration.previewUserInfo = null;
26
33
 
@@ -37,15 +44,15 @@ describe('YouVersionPlatformConfiguration', () => {
37
44
  vi.restoreAllMocks();
38
45
  });
39
46
 
40
- describe('appId', () => {
41
- it('should get and set appId', () => {
42
- expect(YouVersionPlatformConfiguration.appId).toBeNull();
47
+ describe('appKey', () => {
48
+ it('should get and set appKey', () => {
49
+ expect(YouVersionPlatformConfiguration.appKey).toBeNull();
43
50
 
44
- YouVersionPlatformConfiguration.appId = 'test-app-id';
45
- expect(YouVersionPlatformConfiguration.appId).toBe('test-app-id');
51
+ YouVersionPlatformConfiguration.appKey = 'test-app-key';
52
+ expect(YouVersionPlatformConfiguration.appKey).toBe('test-app-key');
46
53
 
47
- YouVersionPlatformConfiguration.appId = null;
48
- expect(YouVersionPlatformConfiguration.appId).toBeNull();
54
+ YouVersionPlatformConfiguration.appKey = null;
55
+ expect(YouVersionPlatformConfiguration.appKey).toBeNull();
49
56
  });
50
57
  });
51
58
 
@@ -104,10 +111,12 @@ describe('YouVersionPlatformConfiguration', () => {
104
111
 
105
112
  describe('apiHost', () => {
106
113
  it('should get and set apiHost', () => {
107
- expect(YouVersionPlatformConfiguration.apiHost).toBe('api-dev.youversion.com');
108
-
109
- YouVersionPlatformConfiguration.apiHost = 'api.youversion.com';
110
- expect(YouVersionPlatformConfiguration.apiHost).toBe('api.youversion.com');
114
+ const apiHost = process.env.YVP_API_HOST || 'api.youversion.com';
115
+ expect(YouVersionPlatformConfiguration.apiHost).toBe(apiHost);
116
+ YouVersionPlatformConfiguration.apiHost = 'somethingelse.youversion.com';
117
+ expect(YouVersionPlatformConfiguration.apiHost).toBe('somethingelse.youversion.com');
118
+ YouVersionPlatformConfiguration.apiHost = apiHost;
119
+ expect(YouVersionPlatformConfiguration.apiHost).toBe(apiHost);
111
120
  });
112
121
  });
113
122
 
@@ -13,9 +13,8 @@ describe('AuthClient', () => {
13
13
  beforeEach(() => {
14
14
  global.fetch = vi.fn();
15
15
  apiClient = new ApiClient({
16
- baseUrl: 'https://api-dev.youversion.com',
17
- appId: 'test-app-id',
18
- version: 'v1',
16
+ appKey: 'test-app-key',
17
+ apiHost: process.env.YVP_API_HOST || '',
19
18
  });
20
19
  authClient = new AuthClient(apiClient);
21
20
  });
@@ -16,9 +16,8 @@ describe('BibleClient', () => {
16
16
 
17
17
  beforeEach(() => {
18
18
  apiClient = new ApiClient({
19
- baseUrl: 'https://api-dev.youversion.com',
20
- appId: process.env.YVP_APP_ID || '',
21
- version: 'v1',
19
+ apiHost: process.env.YVP_API_HOST || '',
20
+ appKey: process.env.YVP_APP_KEY || '',
22
21
  installationId: 'test-installation',
23
22
  });
24
23
  bibleClient = new BibleClient(apiClient);