@youversion/platform-core 0.4.2 → 0.4.3

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,23 @@ 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 ?? process.env.YVP_API_HOST ?? "api.youversion.com";
17
+ if (!apiHost) {
18
+ throw new Error(
19
+ "ApiClient requires a host name. Provide an apiHost in the config or set the YVP_API_HOST environment variable."
20
+ );
21
+ }
22
+ this.baseURL = "https://" + apiHost;
18
23
  this.timeout = config.timeout || 1e4;
19
24
  this.defaultHeaders = {
20
25
  "Content-Type": "application/json",
21
- "X-YVP-App-Key": this.config.appId,
26
+ "X-YVP-App-Key": this.config.appKey,
22
27
  "X-YVP-Installation-Id": this.config.installationId || "web-sdk-default"
23
28
  };
24
29
  }
@@ -160,9 +165,6 @@ var BibleClient = class {
160
165
  constructor(client) {
161
166
  this.client = client;
162
167
  }
163
- get rootPath() {
164
- return `/${this.client.config.version}`;
165
- }
166
168
  /**
167
169
  * Fetches a collection of Bible versions filtered by language ranges.
168
170
  *
@@ -178,7 +180,7 @@ var BibleClient = class {
178
180
  if (license_id !== void 0) {
179
181
  params.license_id = license_id;
180
182
  }
181
- return this.client.get(`${this.rootPath}/bibles`, params);
183
+ return this.client.get(`/v1/bibles`, params);
182
184
  }
183
185
  /**
184
186
  * Fetches a Bible version by its ID.
@@ -187,7 +189,7 @@ var BibleClient = class {
187
189
  */
188
190
  async getVersion(id) {
189
191
  this.versionIdSchema.parse(id);
190
- return this.client.get(`${this.rootPath}/bibles/${id}`);
192
+ return this.client.get(`/v1/bibles/${id}`);
191
193
  }
192
194
  /**
193
195
  * Fetches all books for a given Bible version.
@@ -197,7 +199,7 @@ var BibleClient = class {
197
199
  */
198
200
  async getBooks(versionId, canon) {
199
201
  this.versionIdSchema.parse(versionId);
200
- return this.client.get(`${this.rootPath}/bibles/${versionId}/books`, {
202
+ return this.client.get(`/v1/bibles/${versionId}/books`, {
201
203
  ...canon && { canon }
202
204
  });
203
205
  }
@@ -210,7 +212,7 @@ var BibleClient = class {
210
212
  async getBook(versionId, book) {
211
213
  this.versionIdSchema.parse(versionId);
212
214
  this.bookSchema.parse(book);
213
- return this.client.get(`${this.rootPath}/bibles/${versionId}/books/${book}`);
215
+ return this.client.get(`/v1/bibles/${versionId}/books/${book}`);
214
216
  }
215
217
  /**
216
218
  * Fetches all chapters for a specific book in a version.
@@ -222,7 +224,7 @@ var BibleClient = class {
222
224
  this.versionIdSchema.parse(versionId);
223
225
  this.bookSchema.parse(book);
224
226
  return this.client.get(
225
- `${this.rootPath}/bibles/${versionId}/books/${book}/chapters`
227
+ `/v1/bibles/${versionId}/books/${book}/chapters`
226
228
  );
227
229
  }
228
230
  /**
@@ -237,7 +239,7 @@ var BibleClient = class {
237
239
  this.bookSchema.parse(book);
238
240
  this.chapterSchema.parse(chapter);
239
241
  return this.client.get(
240
- `${this.rootPath}/bibles/${versionId}/books/${book}/chapters/${chapter}`
242
+ `/v1/bibles/${versionId}/books/${book}/chapters/${chapter}`
241
243
  );
242
244
  }
243
245
  /**
@@ -252,7 +254,7 @@ var BibleClient = class {
252
254
  this.bookSchema.parse(book);
253
255
  this.chapterSchema.parse(chapter);
254
256
  return this.client.get(
255
- `${this.rootPath}/bibles/${versionId}/books/${book}/chapters/${chapter}/verses`
257
+ `/v1/bibles/${versionId}/books/${book}/chapters/${chapter}/verses`
256
258
  );
257
259
  }
258
260
  /**
@@ -269,7 +271,7 @@ var BibleClient = class {
269
271
  this.chapterSchema.parse(chapter);
270
272
  this.verseSchema.parse(verse);
271
273
  return this.client.get(
272
- `${this.rootPath}/bibles/${versionId}/books/${book}/chapters/${chapter}/verses/${verse}`
274
+ `/v1/bibles/${versionId}/books/${book}/chapters/${chapter}/verses/${verse}`
273
275
  );
274
276
  }
275
277
  /**
@@ -310,10 +312,7 @@ var BibleClient = class {
310
312
  if (include_notes !== void 0) {
311
313
  params.include_notes = include_notes;
312
314
  }
313
- return this.client.get(
314
- `${this.rootPath}/bibles/${versionId}/passages/${usfm}`,
315
- params
316
- );
315
+ return this.client.get(`/v1/bibles/${versionId}/passages/${usfm}`, params);
317
316
  }
318
317
  /**
319
318
  * Fetches the indexing structure for a Bible version.
@@ -322,14 +321,14 @@ var BibleClient = class {
322
321
  */
323
322
  async getIndex(versionId) {
324
323
  this.versionIdSchema.parse(versionId);
325
- return this.client.get(`${this.rootPath}/bibles/${versionId}/index`);
324
+ return this.client.get(`/v1/bibles/${versionId}/index`);
326
325
  }
327
326
  /**
328
327
  * Fetches the verse of the day calendar for an entire year.
329
328
  * @returns A collection of VOTD objects for all days of the year.
330
329
  */
331
330
  async getAllVOTDs() {
332
- return this.client.get(`${this.rootPath}/verse_of_the_days`);
331
+ return this.client.get(`/v1/verse_of_the_days`);
333
332
  }
334
333
  /**
335
334
  * Fetches the passage_id for the Verse Of The Day.
@@ -347,7 +346,7 @@ var BibleClient = class {
347
346
  async getVOTD(day) {
348
347
  const daySchema = z.number().int().min(1).max(366);
349
348
  daySchema.parse(day);
350
- return this.client.get(`${this.rootPath}/verse_of_the_days/${day}`);
349
+ return this.client.get(`/v1/verse_of_the_days/${day}`);
351
350
  }
352
351
  };
353
352
 
@@ -367,9 +366,6 @@ var LanguagesClient = class {
367
366
  constructor(client) {
368
367
  this.client = client;
369
368
  }
370
- get rootPath() {
371
- return `/${this.client.config.version}`;
372
- }
373
369
  /**
374
370
  * Fetches a collection of languages supported in the Platform.
375
371
  * @param options Query parameters for pagination and filtering (country is required).
@@ -387,7 +383,7 @@ var LanguagesClient = class {
387
383
  if (options.page_token !== void 0) {
388
384
  params.page_token = options.page_token;
389
385
  }
390
- return this.client.get(`${this.rootPath}/languages`, params);
386
+ return this.client.get(`/v1/languages`, params);
391
387
  }
392
388
  /**
393
389
  * Fetches details about a specific language in the Platform.
@@ -396,7 +392,7 @@ var LanguagesClient = class {
396
392
  */
397
393
  async getLanguage(languageId) {
398
394
  this.languageIdSchema.parse(languageId);
399
- return this.client.get(`${this.rootPath}/languages/${languageId}`);
395
+ return this.client.get(`/v1/languages/${languageId}`);
400
396
  }
401
397
  };
402
398
 
@@ -405,10 +401,10 @@ import { z as z3 } from "zod";
405
401
 
406
402
  // src/YouVersionPlatformConfiguration.ts
407
403
  var YouVersionPlatformConfiguration = class {
408
- static _appId = null;
404
+ static _appKey = null;
409
405
  static _installationId = null;
410
406
  static _accessToken = null;
411
- static _apiHost = "api-dev.youversion.com";
407
+ static _apiHost = "api.youversion.com";
412
408
  static _isPreviewMode = false;
413
409
  static _previewUserInfo = null;
414
410
  static getOrSetInstallationId() {
@@ -423,11 +419,11 @@ var YouVersionPlatformConfiguration = class {
423
419
  localStorage.setItem("x-yvp-installation-id", newId);
424
420
  return newId;
425
421
  }
426
- static get appId() {
427
- return this._appId;
422
+ static get appKey() {
423
+ return this._appKey;
428
424
  }
429
- static set appId(value) {
430
- this._appId = value;
425
+ static set appKey(value) {
426
+ this._appKey = value;
431
427
  }
432
428
  static get installationId() {
433
429
  if (!this._installationId) {
@@ -480,9 +476,6 @@ var HighlightsClient = class {
480
476
  constructor(client) {
481
477
  this.client = client;
482
478
  }
483
- get rootPath() {
484
- return `/${this.client.config.version}`;
485
- }
486
479
  /**
487
480
  * Gets the authentication token, either from the provided parameter or from the platform configuration.
488
481
  * @param lat Optional explicit long access token. If not provided, retrieves from YouVersionPlatformConfiguration.
@@ -552,7 +545,7 @@ var HighlightsClient = class {
552
545
  this.validatePassageId(options.passage_id);
553
546
  params.passage_id = options.passage_id;
554
547
  }
555
- return this.client.get(`${this.rootPath}/highlights`, params);
548
+ return this.client.get(`/v1/highlights`, params);
556
549
  }
557
550
  /**
558
551
  * Creates or updates a highlight on a passage.
@@ -567,7 +560,7 @@ var HighlightsClient = class {
567
560
  this.validatePassageId(data.passage_id);
568
561
  this.validateColor(data.color);
569
562
  const token = this.getAuthToken(lat);
570
- return this.client.post(`${this.rootPath}/highlights`, data, { lat: token });
563
+ return this.client.post(`/v1/highlights`, data, { lat: token });
571
564
  }
572
565
  /**
573
566
  * Clears highlights for a passage.
@@ -587,7 +580,7 @@ var HighlightsClient = class {
587
580
  this.validateVersionId(options.version_id);
588
581
  params.version_id = options.version_id;
589
582
  }
590
- await this.client.delete(`${this.rootPath}/highlights/${passageId}`, params);
583
+ await this.client.delete(`/v1/highlights/${passageId}`, params);
591
584
  }
592
585
  };
593
586
 
@@ -885,13 +878,13 @@ var YouVersionAPI = class {
885
878
  Accept: "application/json",
886
879
  "Content-Type": "application/json"
887
880
  };
888
- const appId = YouVersionPlatformConfiguration.appId;
889
- if (appId) {
890
- headers["X-App-Id"] = appId;
881
+ const appKey = YouVersionPlatformConfiguration.appKey;
882
+ if (appKey) {
883
+ headers["X-YVP-App-Key"] = appKey;
891
884
  }
892
885
  const installationId = YouVersionPlatformConfiguration.installationId;
893
886
  if (installationId) {
894
- headers["x-yvp-installation-id"] = installationId;
887
+ headers["X-YVP-Installation-ID"] = installationId;
895
888
  }
896
889
  const request = new Request(url.toString(), {
897
890
  headers
@@ -905,15 +898,15 @@ var URLBuilder = class {
905
898
  static get baseURL() {
906
899
  return new URL(`https://${YouVersionPlatformConfiguration.apiHost}`);
907
900
  }
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");
901
+ static authURL(appKey, requiredPermissions = /* @__PURE__ */ new Set(), optionalPermissions = /* @__PURE__ */ new Set()) {
902
+ if (typeof appKey !== "string" || appKey.trim().length === 0) {
903
+ throw new Error("appKey must be a non-empty string");
911
904
  }
912
905
  try {
913
906
  const url = new URL(this.baseURL);
914
907
  url.pathname = "/auth/login";
915
908
  const searchParams = new URLSearchParams();
916
- searchParams.append("app_id", appId);
909
+ searchParams.append("APP_KEY", appKey);
917
910
  searchParams.append("language", "en");
918
911
  if (requiredPermissions.size > 0) {
919
912
  const requiredList = Array.from(requiredPermissions).map((p) => p.toString());
@@ -977,11 +970,11 @@ var YouVersionAPIUsers = class {
977
970
  if (!optionalPermissions || !(optionalPermissions instanceof Set)) {
978
971
  throw new Error("Invalid optionalPermissions: must be a Set");
979
972
  }
980
- const appId = YouVersionPlatformConfiguration.appId;
981
- if (!appId) {
982
- throw new Error("YouVersionPlatformConfiguration.appId must be set before calling signIn");
973
+ const appKey = YouVersionPlatformConfiguration.appKey;
974
+ if (!appKey) {
975
+ throw new Error("YouVersionPlatformConfiguration.appKey must be set before calling signIn");
983
976
  }
984
- const url = URLBuilder.authURL(appId, requiredPermissions, optionalPermissions);
977
+ const url = URLBuilder.authURL(appKey, requiredPermissions, optionalPermissions);
985
978
  const strategy = AuthenticationStrategyRegistry.get();
986
979
  const callbackUrl = await strategy.authenticate(url);
987
980
  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.3",
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,7 @@ 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',
19
17
  });
20
18
  authClient = new AuthClient(apiClient);
21
19
  });
@@ -16,9 +16,7 @@ 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
+ appKey: process.env.YVP_APP_KEY || '',
22
20
  installationId: 'test-installation',
23
21
  });
24
22
  bibleClient = new BibleClient(apiClient);