@youversion/platform-core 0.5.1 → 0.5.6
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 +6 -6
- package/CHANGELOG.md +32 -0
- package/README.md +11 -70
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/package.json +5 -4
- package/src/__tests__/MockBibles.ts +1628 -0
- package/src/__tests__/MockChapters.ts +1958 -0
- package/src/__tests__/MockPassages.ts +52 -0
- package/src/__tests__/MockVOTDs.ts +1466 -0
- package/src/__tests__/MockVerses.ts +178 -0
- package/src/__tests__/MockVersions.ts +1238 -0
- package/src/__tests__/URLBuilder.test.ts +9 -12
- package/src/__tests__/authentication.test.ts +23 -11
- package/src/__tests__/handlers.ts +98 -0
- package/src/schemas/version.ts +4 -2
|
@@ -120,33 +120,30 @@ describe('URLBuilder - Input Validation', () => {
|
|
|
120
120
|
});
|
|
121
121
|
|
|
122
122
|
it('should include required permissions when provided', () => {
|
|
123
|
-
const permissions = new Set<SignInWithYouVersionPermissionValues>([
|
|
124
|
-
'plans.read',
|
|
125
|
-
'user.read',
|
|
126
|
-
]);
|
|
123
|
+
const permissions = new Set<SignInWithYouVersionPermissionValues>(['bibles', 'votd']);
|
|
127
124
|
const url = URLBuilder.authURL('test-app', permissions);
|
|
128
125
|
|
|
129
126
|
const requiredPerms = url.searchParams.get('required_perms');
|
|
130
127
|
expect(requiredPerms).toBeTruthy();
|
|
131
|
-
expect(requiredPerms?.split(',')).toContain('
|
|
132
|
-
expect(requiredPerms?.split(',')).toContain('
|
|
128
|
+
expect(requiredPerms?.split(',')).toContain('bibles');
|
|
129
|
+
expect(requiredPerms?.split(',')).toContain('votd');
|
|
133
130
|
});
|
|
134
131
|
|
|
135
132
|
it('should include optional permissions when provided', () => {
|
|
136
|
-
const optionalPermissions = new Set<SignInWithYouVersionPermissionValues>(['
|
|
133
|
+
const optionalPermissions = new Set<SignInWithYouVersionPermissionValues>(['demographics']);
|
|
137
134
|
const url = URLBuilder.authURL('test-app', new Set(), optionalPermissions);
|
|
138
135
|
|
|
139
136
|
const optPerms = url.searchParams.get('opt_perms');
|
|
140
|
-
expect(optPerms).toBe('
|
|
137
|
+
expect(optPerms).toBe('demographics');
|
|
141
138
|
});
|
|
142
139
|
|
|
143
140
|
it('should include both required and optional permissions', () => {
|
|
144
|
-
const required = new Set<SignInWithYouVersionPermissionValues>(['
|
|
145
|
-
const optional = new Set<SignInWithYouVersionPermissionValues>(['
|
|
141
|
+
const required = new Set<SignInWithYouVersionPermissionValues>(['bibles']);
|
|
142
|
+
const optional = new Set<SignInWithYouVersionPermissionValues>(['bible_activity']);
|
|
146
143
|
const url = URLBuilder.authURL('test-app', required, optional);
|
|
147
144
|
|
|
148
|
-
expect(url.searchParams.get('required_perms')).toBe('
|
|
149
|
-
expect(url.searchParams.get('opt_perms')).toBe('
|
|
145
|
+
expect(url.searchParams.get('required_perms')).toBe('bibles');
|
|
146
|
+
expect(url.searchParams.get('opt_perms')).toBe('bible_activity');
|
|
150
147
|
});
|
|
151
148
|
|
|
152
149
|
it('should handle empty permission sets', () => {
|
|
@@ -38,7 +38,7 @@ describe('AuthClient', () => {
|
|
|
38
38
|
headers: {
|
|
39
39
|
get: vi.fn((name: string) => (name === 'content-type' ? 'application/json' : null)),
|
|
40
40
|
},
|
|
41
|
-
} as Response);
|
|
41
|
+
} as unknown as Response);
|
|
42
42
|
|
|
43
43
|
const user = await authClient.getUser('test-token');
|
|
44
44
|
|
|
@@ -58,14 +58,23 @@ describe('WebAuthenticationStrategy', () => {
|
|
|
58
58
|
beforeEach(() => {
|
|
59
59
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
60
60
|
delete (window as any).location;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
61
|
+
const newLocation = new URL('http://localhost:3000');
|
|
62
|
+
// Add mocked functions with proper descriptors
|
|
63
|
+
Object.defineProperty(newLocation, 'assign', {
|
|
64
|
+
configurable: true,
|
|
65
|
+
value: vi.fn(),
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
Object.defineProperty(newLocation, 'replace', {
|
|
69
|
+
configurable: true,
|
|
70
|
+
value: vi.fn(),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Assign the new location object to window.location
|
|
74
|
+
Object.defineProperty(window, 'location', {
|
|
75
|
+
configurable: true,
|
|
76
|
+
value: newLocation,
|
|
77
|
+
});
|
|
69
78
|
|
|
70
79
|
const sessionStorageMock = (() => {
|
|
71
80
|
let store: Record<string, string> = {};
|
|
@@ -97,7 +106,10 @@ describe('WebAuthenticationStrategy', () => {
|
|
|
97
106
|
});
|
|
98
107
|
|
|
99
108
|
afterEach(() => {
|
|
100
|
-
window
|
|
109
|
+
Object.defineProperty(window, 'location', {
|
|
110
|
+
configurable: true,
|
|
111
|
+
value: oldWindowLocation,
|
|
112
|
+
});
|
|
101
113
|
WebAuthenticationStrategy.cleanup();
|
|
102
114
|
vi.clearAllMocks();
|
|
103
115
|
});
|
|
@@ -112,7 +124,7 @@ describe('WebAuthenticationStrategy', () => {
|
|
|
112
124
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
113
125
|
expect(sessionStorage.setItem).toHaveBeenCalledWith(
|
|
114
126
|
'youversion-auth-return',
|
|
115
|
-
'http://localhost:3000',
|
|
127
|
+
'http://localhost:3000/',
|
|
116
128
|
);
|
|
117
129
|
});
|
|
118
130
|
});
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { http, HttpResponse } from 'msw';
|
|
2
2
|
import type { Collection, Highlight, Language } from '../types';
|
|
3
3
|
import { mockLanguages } from './MockLangauges';
|
|
4
|
+
import { mockVersions, mockVersionKJV } from './MockVersions';
|
|
5
|
+
import { mockBibleGenesis, mockBibleBooks } from './MockBibles';
|
|
6
|
+
import { mockChapterGenesis1, mockGenesisChapters } from './MockChapters';
|
|
7
|
+
import { mockGen1Verse1, mockGen1Verses } from './MockVerses';
|
|
8
|
+
import {
|
|
9
|
+
mockNIVGen1PassageHTML,
|
|
10
|
+
mockNIVGen1PassageText,
|
|
11
|
+
mockNIVGen1Verse1PassageHTML,
|
|
12
|
+
mockNIVGen1Verse1PassageText,
|
|
13
|
+
mockNIVRom1PassageHTMLHeadings,
|
|
14
|
+
mockNIVRom1PassageHTMLHeadingsNotes,
|
|
15
|
+
mockNIVRom1PassageHTMLNotes,
|
|
16
|
+
} from './MockPassages';
|
|
17
|
+
import { mockAllVOTDs } from './MockVOTDs';
|
|
4
18
|
|
|
5
19
|
const apiHost = process.env.YVP_API_HOST;
|
|
6
20
|
if (!apiHost) {
|
|
@@ -90,4 +104,88 @@ export const handlers = [
|
|
|
90
104
|
http.delete(`https://${apiHost}/v1/highlights/:passageId`, () => {
|
|
91
105
|
return new HttpResponse(null, { status: 204 });
|
|
92
106
|
}),
|
|
107
|
+
|
|
108
|
+
// Versions endpoints
|
|
109
|
+
http.get(`https://${apiHost}/v1/bibles`, () => {
|
|
110
|
+
return HttpResponse.json({
|
|
111
|
+
data: mockVersions,
|
|
112
|
+
next_page_token: null,
|
|
113
|
+
total_size: 14,
|
|
114
|
+
});
|
|
115
|
+
}),
|
|
116
|
+
|
|
117
|
+
http.get(`https://${apiHost}/v1/bibles/:id`, () => {
|
|
118
|
+
return HttpResponse.json(mockVersionKJV);
|
|
119
|
+
}),
|
|
120
|
+
|
|
121
|
+
// Bible endpoints
|
|
122
|
+
http.get(`https://${apiHost}/v1/bibles/:id/books`, () => {
|
|
123
|
+
return HttpResponse.json({ data: mockBibleBooks });
|
|
124
|
+
}),
|
|
125
|
+
|
|
126
|
+
http.get(`https://${apiHost}/v1/bibles/:bible_id/books/:book_id`, () => {
|
|
127
|
+
return HttpResponse.json(mockBibleGenesis);
|
|
128
|
+
}),
|
|
129
|
+
|
|
130
|
+
// Chaper endpoints
|
|
131
|
+
http.get(`https://${apiHost}/v1/bibles/:bible_id/books/:book_id/chapters`, () => {
|
|
132
|
+
return HttpResponse.json({ data: mockGenesisChapters });
|
|
133
|
+
}),
|
|
134
|
+
http.get(`https://${apiHost}/v1/bibles/:bible_id/books/:book_id/chapters/:chapter_id`, () => {
|
|
135
|
+
return HttpResponse.json(mockChapterGenesis1);
|
|
136
|
+
}),
|
|
137
|
+
|
|
138
|
+
// Verse endpoints
|
|
139
|
+
http.get(
|
|
140
|
+
`https://${apiHost}/v1/bibles/:bible_id/books/:book_id/chapters/:chapter_id/verses`,
|
|
141
|
+
() => {
|
|
142
|
+
return HttpResponse.json({ data: mockGen1Verses });
|
|
143
|
+
},
|
|
144
|
+
),
|
|
145
|
+
http.get(
|
|
146
|
+
`https://${apiHost}/v1/bibles/:bible_id/books/:book_id/chapters/:chapter_id/verses/:verse_id`,
|
|
147
|
+
() => {
|
|
148
|
+
return HttpResponse.json(mockGen1Verse1);
|
|
149
|
+
},
|
|
150
|
+
),
|
|
151
|
+
|
|
152
|
+
// Passage endpoints
|
|
153
|
+
http.get(`https://${apiHost}/v1/bibles/:bible_id/passages/GEN.1`, ({ request }) => {
|
|
154
|
+
const url = new URL(request.url);
|
|
155
|
+
const format = url.searchParams.get('format');
|
|
156
|
+
if (format === 'html') {
|
|
157
|
+
return HttpResponse.json(mockNIVGen1PassageHTML);
|
|
158
|
+
}
|
|
159
|
+
return HttpResponse.json(mockNIVGen1PassageText);
|
|
160
|
+
}),
|
|
161
|
+
http.get(`https://${apiHost}/v1/bibles/:bible_id/passages/GEN.1.1`, ({ request }) => {
|
|
162
|
+
const url = new URL(request.url);
|
|
163
|
+
const format = url.searchParams.get('format');
|
|
164
|
+
if (format === 'html') {
|
|
165
|
+
return HttpResponse.json(mockNIVGen1Verse1PassageHTML);
|
|
166
|
+
}
|
|
167
|
+
return HttpResponse.json(mockNIVGen1Verse1PassageText);
|
|
168
|
+
}),
|
|
169
|
+
http.get(`https://${apiHost}/v1/bibles/:bible_id/passages/ROM.1`, ({ request }) => {
|
|
170
|
+
const url = new URL(request.url);
|
|
171
|
+
const includeHeadings = url.searchParams.get('include_headings') === 'true';
|
|
172
|
+
const includeNotes = url.searchParams.get('include_notes') === 'true';
|
|
173
|
+
if (includeHeadings && !includeNotes) {
|
|
174
|
+
return HttpResponse.json(mockNIVRom1PassageHTMLHeadings);
|
|
175
|
+
} else if (!includeHeadings && includeNotes) {
|
|
176
|
+
return HttpResponse.json(mockNIVRom1PassageHTMLNotes);
|
|
177
|
+
} else if (includeNotes && includeHeadings) {
|
|
178
|
+
return HttpResponse.json(mockNIVRom1PassageHTMLHeadingsNotes);
|
|
179
|
+
}
|
|
180
|
+
}),
|
|
181
|
+
|
|
182
|
+
// Verse Of The Day endpoints
|
|
183
|
+
http.get(`https://${apiHost}/v1/verse_of_the_days/:day`, ({ params }) => {
|
|
184
|
+
const { day } = params;
|
|
185
|
+
const votd = mockAllVOTDs.find((v) => v.day === Number(day));
|
|
186
|
+
return HttpResponse.json(votd || mockAllVOTDs[0]);
|
|
187
|
+
}),
|
|
188
|
+
http.get(`https://${apiHost}/v1/verse_of_the_days`, () => {
|
|
189
|
+
return HttpResponse.json({ data: mockAllVOTDs });
|
|
190
|
+
}),
|
|
93
191
|
];
|
package/src/schemas/version.ts
CHANGED
|
@@ -7,9 +7,9 @@ export const BibleVersionSchema = z.object({
|
|
|
7
7
|
/** Bible version abbreviation */
|
|
8
8
|
abbreviation: z.string(),
|
|
9
9
|
/** Long copyright text */
|
|
10
|
-
copyright_long: z.string(),
|
|
10
|
+
copyright_long: z.string().nullable().optional(),
|
|
11
11
|
/** Short copyright text */
|
|
12
|
-
copyright_short: z.string(),
|
|
12
|
+
copyright_short: z.string().nullable().optional(),
|
|
13
13
|
/** Bible information text */
|
|
14
14
|
info: z.string().nullable().optional(),
|
|
15
15
|
/** Publisher URL */
|
|
@@ -20,6 +20,8 @@ export const BibleVersionSchema = z.object({
|
|
|
20
20
|
local_abbreviation: z.string(),
|
|
21
21
|
/** Localized title */
|
|
22
22
|
local_title: z.string(),
|
|
23
|
+
/** Organization ID of publisher */
|
|
24
|
+
organization_id: z.string().nullable().optional(),
|
|
23
25
|
/** Full title */
|
|
24
26
|
title: z.string(),
|
|
25
27
|
/** Array of book identifiers (e.g., ["GEN", "EXO", "LEV"]) */
|