@react-native-kakao/user 3.1.0-next.0 → 3.1.0-next.2
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/CHANGELOG.md +43 -0
- package/android/src/main/java/net/mjstudio/rnkakao/user/RNCKakaoUserModule.kt +325 -150
- package/ios/RNCKakaoUser.mm +59 -6
- package/ios/RNCKakaoUserManager.swift +244 -58
- package/lib/commonjs/index.js +91 -12
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +133 -18
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/spec/NativeKakaoUser.ts +25 -2
- package/lib/module/index.js +86 -13
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +126 -18
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/spec/NativeKakaoUser.ts +25 -2
- package/lib/typescript/src/index.d.ts +90 -25
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/spec/NativeKakaoUser.d.ts +9 -3
- package/lib/typescript/src/spec/NativeKakaoUser.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +213 -35
- package/src/index.web.ts +164 -24
- package/src/spec/NativeKakaoUser.ts +25 -2
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { is } from '@mj-studio/js-util';
|
|
2
|
-
import { kAssert } from '@react-native-kakao/core';
|
|
2
|
+
import { kAssert, kCreateWebError } from '@react-native-kakao/core';
|
|
3
3
|
|
|
4
4
|
import Native from './spec/NativeKakaoUser';
|
|
5
5
|
import { validateShippingAddressOptions } from './validateShippingAddressOptions';
|
|
@@ -15,13 +15,28 @@ export interface KakaoLoginToken {
|
|
|
15
15
|
refreshTokenExpiresIn: number;
|
|
16
16
|
scopes: string[];
|
|
17
17
|
}
|
|
18
|
+
export type KakaoCodeTokenOptions = {
|
|
19
|
+
code: string;
|
|
20
|
+
codeVerifier?: string;
|
|
21
|
+
redirectUri?: string;
|
|
22
|
+
web?: { clientSecret?: string };
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const minActivityRequestCode = -2147483648;
|
|
26
|
+
const maxActivityRequestCode = 2147483647;
|
|
27
|
+
|
|
28
|
+
export type KakaoTalkLaunchMethod = 'UniversalLink' | 'CustomScheme';
|
|
29
|
+
|
|
30
|
+
const defaultTalkLaunchMethod: KakaoTalkLaunchMethod = 'UniversalLink';
|
|
31
|
+
const webOnlyErrorCode = 'Package-UnsupportedPlatform';
|
|
32
|
+
|
|
18
33
|
export interface KakaoScopeInfo {
|
|
19
34
|
id: string;
|
|
20
35
|
agreed: boolean;
|
|
21
36
|
displayName: string;
|
|
22
|
-
revocable?: boolean;
|
|
37
|
+
revocable?: boolean | null;
|
|
23
38
|
using: boolean;
|
|
24
|
-
delegated?: boolean;
|
|
39
|
+
delegated?: boolean | null;
|
|
25
40
|
type: string;
|
|
26
41
|
}
|
|
27
42
|
export interface KakaoServiceTerms {
|
|
@@ -30,6 +45,7 @@ export interface KakaoServiceTerms {
|
|
|
30
45
|
agreed: boolean;
|
|
31
46
|
required: boolean;
|
|
32
47
|
revocable: boolean;
|
|
48
|
+
agreedBy?: 'KAUTH' | 'KAPI' | 'unknown';
|
|
33
49
|
}
|
|
34
50
|
export type KakaoRevokedServiceTerms = {
|
|
35
51
|
tag: string;
|
|
@@ -61,34 +77,45 @@ export interface KakaoShippingAddress {
|
|
|
61
77
|
}
|
|
62
78
|
export interface KakaoUser {
|
|
63
79
|
id: number;
|
|
64
|
-
|
|
80
|
+
properties: Record<string, string>;
|
|
81
|
+
hasSignedUp?: boolean | null;
|
|
82
|
+
uuid?: string | null;
|
|
83
|
+
groupUserToken?: string | null;
|
|
84
|
+
email?: string | null;
|
|
65
85
|
name?: string | null;
|
|
66
|
-
nickname
|
|
67
|
-
profileImageUrl
|
|
68
|
-
thumbnailImageUrl
|
|
86
|
+
nickname?: string | null;
|
|
87
|
+
profileImageUrl?: string | null;
|
|
88
|
+
thumbnailImageUrl?: string | null;
|
|
89
|
+
isDefaultImage?: boolean | null;
|
|
69
90
|
phoneNumber?: string | null;
|
|
70
91
|
ageRange?: string | null;
|
|
71
92
|
birthday?: string | null;
|
|
72
93
|
birthdayType?: string | null;
|
|
94
|
+
isLeapMonth?: boolean | null;
|
|
73
95
|
birthyear?: string | null;
|
|
74
96
|
gender?: string | null;
|
|
75
|
-
isEmailValid
|
|
76
|
-
isEmailVerified
|
|
77
|
-
isKorean?: boolean;
|
|
78
|
-
ageRangeNeedsAgreement?: boolean;
|
|
79
|
-
birthdayNeedsAgreement?: boolean;
|
|
80
|
-
birthyearNeedsAgreement?: boolean;
|
|
81
|
-
emailNeedsAgreement?: boolean;
|
|
82
|
-
genderNeedsAgreement?: boolean;
|
|
83
|
-
isKoreanNeedsAgreement?: boolean;
|
|
84
|
-
phoneNumberNeedsAgreement?: boolean;
|
|
85
|
-
profileNeedsAgreement?: boolean;
|
|
86
|
-
nameNeedsAgreement?: boolean;
|
|
87
|
-
profileImageNeedsAgreement?: boolean;
|
|
88
|
-
profileNicknameNeedsAgreement?: boolean;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
97
|
+
isEmailValid?: boolean | null;
|
|
98
|
+
isEmailVerified?: boolean | null;
|
|
99
|
+
isKorean?: boolean | null;
|
|
100
|
+
ageRangeNeedsAgreement?: boolean | null;
|
|
101
|
+
birthdayNeedsAgreement?: boolean | null;
|
|
102
|
+
birthyearNeedsAgreement?: boolean | null;
|
|
103
|
+
emailNeedsAgreement?: boolean | null;
|
|
104
|
+
genderNeedsAgreement?: boolean | null;
|
|
105
|
+
isKoreanNeedsAgreement?: boolean | null;
|
|
106
|
+
phoneNumberNeedsAgreement?: boolean | null;
|
|
107
|
+
profileNeedsAgreement?: boolean | null;
|
|
108
|
+
nameNeedsAgreement?: boolean | null;
|
|
109
|
+
profileImageNeedsAgreement?: boolean | null;
|
|
110
|
+
profileNicknameNeedsAgreement?: boolean | null;
|
|
111
|
+
legalName?: string | null;
|
|
112
|
+
legalNameNeedsAgreement?: boolean | null;
|
|
113
|
+
legalBirthDate?: string | null;
|
|
114
|
+
legalBirthDateNeedsAgreement?: boolean | null;
|
|
115
|
+
legalGender?: 'female' | 'male' | null;
|
|
116
|
+
legalGenderNeedsAgreement?: boolean | null;
|
|
117
|
+
connectedAt?: number | null;
|
|
118
|
+
synchedAt?: number | null;
|
|
92
119
|
}
|
|
93
120
|
export interface KakaoAccessTokenInfo {
|
|
94
121
|
id?: number;
|
|
@@ -101,12 +128,20 @@ export function login({
|
|
|
101
128
|
useKakaoAccountLogin,
|
|
102
129
|
scopes,
|
|
103
130
|
nonce,
|
|
131
|
+
loginHint,
|
|
132
|
+
channelPublicIds,
|
|
133
|
+
android,
|
|
134
|
+
ios,
|
|
104
135
|
}: {
|
|
105
136
|
serviceTerms?: string[];
|
|
106
137
|
prompts?: ('Login' | 'Create' | 'Cert' | 'SelectAccount')[];
|
|
107
138
|
scopes?: string[];
|
|
108
139
|
useKakaoAccountLogin?: boolean;
|
|
109
140
|
nonce?: string;
|
|
141
|
+
loginHint?: string;
|
|
142
|
+
channelPublicIds?: string[];
|
|
143
|
+
android?: { requestCode?: number };
|
|
144
|
+
ios?: { launchMethod?: KakaoTalkLaunchMethod };
|
|
110
145
|
web?: {
|
|
111
146
|
redirectUri: string;
|
|
112
147
|
scope?: string[];
|
|
@@ -118,31 +153,133 @@ export function login({
|
|
|
118
153
|
nonce?: string;
|
|
119
154
|
};
|
|
120
155
|
} = {}): Promise<KakaoLoginToken> {
|
|
156
|
+
const requestCode = android?.requestCode;
|
|
157
|
+
kAssert(
|
|
158
|
+
requestCode == null ||
|
|
159
|
+
(Number.isInteger(requestCode) &&
|
|
160
|
+
requestCode >= minActivityRequestCode &&
|
|
161
|
+
requestCode <= maxActivityRequestCode),
|
|
162
|
+
`[login] android.requestCode must be an integer from ${minActivityRequestCode} to ${maxActivityRequestCode}`,
|
|
163
|
+
);
|
|
164
|
+
|
|
121
165
|
kAssert(
|
|
122
166
|
!useKakaoAccountLogin ? !is.notEmptyArray(prompts) && !is.notEmptyArray(scopes) : true,
|
|
123
167
|
'[login] `prompts` and `scopes` cannot be passed if useKakaoAccountLogin is false.',
|
|
124
168
|
);
|
|
125
169
|
|
|
126
170
|
kAssert(
|
|
127
|
-
is.notEmptyArray(scopes)
|
|
128
|
-
|
|
171
|
+
is.notEmptyArray(scopes)
|
|
172
|
+
? !is.notEmptyArray(prompts) &&
|
|
173
|
+
!is.notEmptyArray(serviceTerms) &&
|
|
174
|
+
!is.notEmptyArray(channelPublicIds)
|
|
175
|
+
: true,
|
|
176
|
+
'[login] `scopes` cannot be passed with `prompts`, `serviceTerms`, or `channelPublicIds`',
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
kAssert(
|
|
180
|
+
loginHint == null ||
|
|
181
|
+
(!is.notEmptyArray(scopes) &&
|
|
182
|
+
!is.notEmptyArray(serviceTerms) &&
|
|
183
|
+
!is.notEmptyArray(channelPublicIds)),
|
|
184
|
+
'[login] `loginHint` cannot be passed with `scopes`, `serviceTerms`, or `channelPublicIds` on native platforms.',
|
|
129
185
|
);
|
|
130
186
|
|
|
131
187
|
return Native.login(
|
|
132
188
|
serviceTerms ?? [],
|
|
133
189
|
prompts ?? [],
|
|
134
190
|
useKakaoAccountLogin ?? false,
|
|
191
|
+
ios?.launchMethod ?? defaultTalkLaunchMethod,
|
|
135
192
|
scopes ?? [],
|
|
136
193
|
nonce,
|
|
194
|
+
loginHint,
|
|
195
|
+
channelPublicIds ?? [],
|
|
196
|
+
requestCode,
|
|
137
197
|
);
|
|
138
198
|
}
|
|
139
199
|
|
|
140
|
-
export function
|
|
141
|
-
|
|
200
|
+
export async function signup({ properties }: { properties?: Record<string, string> } = {}) {
|
|
201
|
+
await Native.signup(properties);
|
|
142
202
|
}
|
|
143
203
|
|
|
144
|
-
export function
|
|
145
|
-
|
|
204
|
+
export function loginWithKakao({
|
|
205
|
+
uiMode = 'auto',
|
|
206
|
+
prompts,
|
|
207
|
+
loginHint,
|
|
208
|
+
nonce,
|
|
209
|
+
channelPublicIds,
|
|
210
|
+
serviceTerms,
|
|
211
|
+
ios,
|
|
212
|
+
}: {
|
|
213
|
+
uiMode?: 'auto' | 'light' | 'dark';
|
|
214
|
+
prompts?: ('Login' | 'Create' | 'Cert' | 'SelectAccount')[];
|
|
215
|
+
loginHint?: string;
|
|
216
|
+
nonce?: string;
|
|
217
|
+
channelPublicIds?: string[];
|
|
218
|
+
serviceTerms?: string[];
|
|
219
|
+
ios?: {
|
|
220
|
+
orientation?: 'auto' | 'portrait' | 'landscape';
|
|
221
|
+
launchMethod?: KakaoTalkLaunchMethod;
|
|
222
|
+
};
|
|
223
|
+
} = {}): Promise<KakaoLoginToken> {
|
|
224
|
+
return Native.loginWithKakao(
|
|
225
|
+
uiMode,
|
|
226
|
+
ios?.orientation ?? 'auto',
|
|
227
|
+
ios?.launchMethod ?? defaultTalkLaunchMethod,
|
|
228
|
+
prompts ?? [],
|
|
229
|
+
loginHint,
|
|
230
|
+
nonce,
|
|
231
|
+
channelPublicIds ?? [],
|
|
232
|
+
serviceTerms ?? [],
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export function refreshToken({
|
|
237
|
+
token,
|
|
238
|
+
ios,
|
|
239
|
+
}: {
|
|
240
|
+
token?: KakaoLoginToken;
|
|
241
|
+
ios?: { loggingEnabled?: boolean };
|
|
242
|
+
} = {}): Promise<KakaoLoginToken> {
|
|
243
|
+
kAssert(
|
|
244
|
+
ios?.loggingEnabled == null || typeof ios.loggingEnabled === 'boolean',
|
|
245
|
+
'[refreshToken] ios.loggingEnabled must be a boolean',
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
if (token !== undefined) {
|
|
249
|
+
kAssert(
|
|
250
|
+
token != null &&
|
|
251
|
+
is.string(token.accessToken) &&
|
|
252
|
+
token.accessToken.length > 0 &&
|
|
253
|
+
is.string(token.refreshToken) &&
|
|
254
|
+
token.refreshToken.length > 0,
|
|
255
|
+
'[refreshToken] token must contain non-empty accessToken and refreshToken strings',
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
kAssert(
|
|
259
|
+
[token.accessTokenExpiresAt, token.refreshTokenExpiresAt].every(
|
|
260
|
+
(value) => Number.isFinite(value) && !Number.isNaN(new Date(value * 1000).getTime()),
|
|
261
|
+
) && [token.accessTokenExpiresIn, token.refreshTokenExpiresIn].every(Number.isFinite),
|
|
262
|
+
'[refreshToken] token expiry timestamps must be valid Unix seconds and lifetimes must be finite',
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
kAssert(
|
|
266
|
+
(token.tokenType == null || is.string(token.tokenType)) &&
|
|
267
|
+
(token.idToken == null || is.string(token.idToken)) &&
|
|
268
|
+
Array.isArray(token.scopes) &&
|
|
269
|
+
token.scopes.every((scope) => is.string(scope)),
|
|
270
|
+
'[refreshToken] tokenType and idToken must be strings when present, and scopes must be strings',
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return Native.refreshToken(token, ios?.loggingEnabled ?? true);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export async function logout() {
|
|
278
|
+
await Native.logout();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export async function unlink() {
|
|
282
|
+
await Native.unlink();
|
|
146
283
|
}
|
|
147
284
|
|
|
148
285
|
export function isLogined() {
|
|
@@ -159,7 +296,11 @@ export function scopes(scopes?: string[]): Promise<KakaoScopeInfo[]> {
|
|
|
159
296
|
return Native.scopes(scopes);
|
|
160
297
|
}
|
|
161
298
|
|
|
162
|
-
export function revokeScopes(scopes: string[]): Promise<void> {
|
|
299
|
+
export async function revokeScopes(scopes: string[]): Promise<void> {
|
|
300
|
+
await Native.revokeScopes(scopes);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export function revokeScopesWithResult(scopes: string[]): Promise<KakaoScopeInfo[]> {
|
|
163
304
|
return Native.revokeScopes(scopes);
|
|
164
305
|
}
|
|
165
306
|
|
|
@@ -195,21 +336,49 @@ export function selectShippingAddress(): Promise<number> {
|
|
|
195
336
|
return Native.selectShippingAddress();
|
|
196
337
|
}
|
|
197
338
|
|
|
198
|
-
export function me(
|
|
199
|
-
|
|
339
|
+
export function me({
|
|
340
|
+
propertyKeys,
|
|
341
|
+
secureResource = true,
|
|
342
|
+
}: { propertyKeys?: string[]; secureResource?: boolean } = {}): Promise<KakaoUser> {
|
|
343
|
+
return Native.me(propertyKeys, secureResource);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export async function issueAccessTokenWithCode({
|
|
347
|
+
code,
|
|
348
|
+
codeVerifier,
|
|
349
|
+
redirectUri,
|
|
350
|
+
}: KakaoCodeTokenOptions): Promise<KakaoLoginToken> {
|
|
351
|
+
kAssert(is.string(code) && code.length > 0, '[issueAccessTokenWithCode] code is required');
|
|
352
|
+
|
|
353
|
+
return Native.issueAccessTokenWithCode(code, codeVerifier, redirectUri);
|
|
200
354
|
}
|
|
201
355
|
|
|
202
356
|
export function getAccessToken(): Promise<KakaoAccessTokenInfo> {
|
|
203
357
|
return Native.getAccessToken();
|
|
204
358
|
}
|
|
205
359
|
|
|
360
|
+
export async function updateProfile({
|
|
361
|
+
properties,
|
|
362
|
+
}: {
|
|
363
|
+
properties: Record<string, string>;
|
|
364
|
+
}): Promise<void> {
|
|
365
|
+
await Native.updateProfile(properties);
|
|
366
|
+
}
|
|
367
|
+
|
|
206
368
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
207
|
-
export function setAccessTokenWeb(token: string) {
|
|
369
|
+
export function setAccessTokenWeb(token: string): void {
|
|
370
|
+
kCreateWebError({
|
|
371
|
+
code: webOnlyErrorCode,
|
|
372
|
+
message: '[setAccessTokenWeb] This API is only supported on web.',
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
|
|
208
376
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
209
377
|
export async function issueAccessTokenWithCodeWeb(params: {
|
|
210
378
|
redirectUri: string;
|
|
211
379
|
clientSecret?: string;
|
|
212
380
|
code: string;
|
|
381
|
+
codeVerifier?: string;
|
|
213
382
|
}): Promise<{
|
|
214
383
|
tokenType: string;
|
|
215
384
|
accessToken: string;
|
|
@@ -219,11 +388,18 @@ export async function issueAccessTokenWithCodeWeb(params: {
|
|
|
219
388
|
refreshTokenExpiresIn: number;
|
|
220
389
|
scope?: string;
|
|
221
390
|
}> {
|
|
222
|
-
|
|
391
|
+
kCreateWebError({
|
|
392
|
+
code: webOnlyErrorCode,
|
|
393
|
+
message: '[issueAccessTokenWithCodeWeb] This API is only supported on web.',
|
|
394
|
+
});
|
|
223
395
|
}
|
|
224
396
|
|
|
225
397
|
const KakaoUser = {
|
|
226
398
|
login,
|
|
399
|
+
loginWithKakao,
|
|
400
|
+
refreshToken,
|
|
401
|
+
issueAccessTokenWithCode,
|
|
402
|
+
signup,
|
|
227
403
|
logout,
|
|
228
404
|
unlink,
|
|
229
405
|
isLogined,
|
|
@@ -231,11 +407,13 @@ const KakaoUser = {
|
|
|
231
407
|
isKakaoTalkLoginAvailable,
|
|
232
408
|
scopes,
|
|
233
409
|
revokeScopes,
|
|
410
|
+
revokeScopesWithResult,
|
|
234
411
|
serviceTerms,
|
|
235
412
|
revokeServiceTerms,
|
|
236
413
|
shippingAddresses,
|
|
237
414
|
selectShippingAddress,
|
|
238
415
|
me,
|
|
416
|
+
updateProfile,
|
|
239
417
|
getAccessToken,
|
|
240
418
|
setAccessTokenWeb,
|
|
241
419
|
issueAccessTokenWithCodeWeb,
|
package/src/index.web.ts
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { camelCaseObject, filterNonNullishKeys, is } from '@mj-studio/js-util';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
kAssert,
|
|
4
|
+
kCreateWebError,
|
|
5
|
+
kFetch,
|
|
6
|
+
kFetchFormUrlEncoded,
|
|
7
|
+
kGlobalStorage,
|
|
8
|
+
kRunWebAPI,
|
|
9
|
+
} from '@react-native-kakao/core';
|
|
3
10
|
|
|
4
11
|
import {
|
|
5
12
|
type KakaoLoginToken,
|
|
6
13
|
type KakaoScopeInfo,
|
|
14
|
+
type KakaoServiceTerms,
|
|
7
15
|
type KakaoShippingAddressResult,
|
|
8
16
|
type KakaoUser as KakaoUserProfile,
|
|
9
17
|
type KakaoUserAPI,
|
|
@@ -11,6 +19,7 @@ import {
|
|
|
11
19
|
import { validateShippingAddressOptions } from './validateShippingAddressOptions';
|
|
12
20
|
|
|
13
21
|
declare const Kakao: {
|
|
22
|
+
isInitialized: () => boolean;
|
|
14
23
|
Auth: {
|
|
15
24
|
authorize: Function;
|
|
16
25
|
logout: Function;
|
|
@@ -30,6 +39,21 @@ function isoToUnix(value?: string | number) {
|
|
|
30
39
|
}
|
|
31
40
|
|
|
32
41
|
const KakaoUser: KakaoUserAPI = {
|
|
42
|
+
loginWithKakao: () =>
|
|
43
|
+
kRunWebAPI(() => {
|
|
44
|
+
throw {
|
|
45
|
+
code: 'Package-UnsupportedPlatform',
|
|
46
|
+
message:
|
|
47
|
+
'loginWithKakao is supported on Android and iOS. Use login with web.redirectUri on web.',
|
|
48
|
+
};
|
|
49
|
+
}),
|
|
50
|
+
refreshToken: () =>
|
|
51
|
+
kRunWebAPI(() => {
|
|
52
|
+
throw {
|
|
53
|
+
code: 'Package-UnsupportedPlatform',
|
|
54
|
+
message: 'The Kakao JavaScript SDK does not support refreshToken.',
|
|
55
|
+
};
|
|
56
|
+
}),
|
|
33
57
|
hasToken: () => kRunWebAPI(() => Kakao.Auth.getAccessToken() != null),
|
|
34
58
|
getAccessToken: () =>
|
|
35
59
|
kRunWebAPI(async () => {
|
|
@@ -42,7 +66,62 @@ const KakaoUser: KakaoUserAPI = {
|
|
|
42
66
|
appId: app_id,
|
|
43
67
|
};
|
|
44
68
|
}),
|
|
45
|
-
|
|
69
|
+
issueAccessTokenWithCode: ({ code, codeVerifier, redirectUri, web }) =>
|
|
70
|
+
kRunWebAPI(async () => {
|
|
71
|
+
kAssert(
|
|
72
|
+
is.string(code) && code.length > 0 && is.string(redirectUri) && redirectUri.length > 0,
|
|
73
|
+
'[issueAccessTokenWithCode] code and redirectUri are required on web',
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
if (typeof Kakao === 'undefined' || !Kakao.isInitialized()) {
|
|
77
|
+
kCreateWebError({
|
|
78
|
+
code: 'Package-SDKNotInitialized',
|
|
79
|
+
message: 'Initialize the Kakao SDK before exchanging an authorization code.',
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const token = await KakaoUser.issueAccessTokenWithCodeWeb({
|
|
84
|
+
code,
|
|
85
|
+
codeVerifier,
|
|
86
|
+
redirectUri: redirectUri!,
|
|
87
|
+
clientSecret: web?.clientSecret,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
if (
|
|
91
|
+
!is.string(token.accessToken) ||
|
|
92
|
+
!token.accessToken ||
|
|
93
|
+
!is.string(token.refreshToken) ||
|
|
94
|
+
!token.refreshToken ||
|
|
95
|
+
!is.string(token.tokenType) ||
|
|
96
|
+
(token.idToken != null && !is.string(token.idToken)) ||
|
|
97
|
+
!Number.isFinite(token.expiresIn) ||
|
|
98
|
+
token.expiresIn < 0 ||
|
|
99
|
+
!Number.isFinite(token.refreshTokenExpiresIn) ||
|
|
100
|
+
token.refreshTokenExpiresIn < 0 ||
|
|
101
|
+
(token.scope != null && !is.string(token.scope))
|
|
102
|
+
) {
|
|
103
|
+
kCreateWebError({
|
|
104
|
+
code: 'Package-APIResponseNotFound',
|
|
105
|
+
message: 'issueAccessTokenWithCode returned invalid token data.',
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const issuedAt = Math.floor(Date.now() / 1000);
|
|
110
|
+
KakaoUser.setAccessTokenWeb(token.accessToken);
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
accessToken: token.accessToken,
|
|
114
|
+
refreshToken: token.refreshToken,
|
|
115
|
+
tokenType: token.tokenType,
|
|
116
|
+
idToken: token.idToken,
|
|
117
|
+
accessTokenExpiresIn: token.expiresIn,
|
|
118
|
+
refreshTokenExpiresIn: token.refreshTokenExpiresIn,
|
|
119
|
+
accessTokenExpiresAt: issuedAt + token.expiresIn,
|
|
120
|
+
refreshTokenExpiresAt: issuedAt + token.refreshTokenExpiresIn,
|
|
121
|
+
scopes: token.scope?.split(' ').filter(Boolean) ?? [],
|
|
122
|
+
};
|
|
123
|
+
}),
|
|
124
|
+
issueAccessTokenWithCodeWeb: ({ clientSecret, code, codeVerifier, redirectUri }) =>
|
|
46
125
|
kRunWebAPI(async () => {
|
|
47
126
|
const res = await kFetchFormUrlEncoded<{
|
|
48
127
|
token_type: string;
|
|
@@ -59,6 +138,7 @@ const KakaoUser: KakaoUserAPI = {
|
|
|
59
138
|
client_id: kGlobalStorage.restApiKey,
|
|
60
139
|
redirect_uri: redirectUri,
|
|
61
140
|
code,
|
|
141
|
+
code_verifier: codeVerifier,
|
|
62
142
|
client_secret: clientSecret,
|
|
63
143
|
}),
|
|
64
144
|
}).then((r) => r.body);
|
|
@@ -73,10 +153,12 @@ const KakaoUser: KakaoUserAPI = {
|
|
|
73
153
|
kRunWebAPI(() => {
|
|
74
154
|
const { loginHint, nonce, prompt, redirectUri, scope, state, throughTalk, serviceTerms } =
|
|
75
155
|
params?.web ?? {};
|
|
156
|
+
const channelPublicIds = params?.channelPublicIds;
|
|
76
157
|
|
|
77
158
|
return Kakao.Auth.authorize(
|
|
78
159
|
filterNonNullishKeys({
|
|
79
|
-
loginHint,
|
|
160
|
+
loginHint: params?.loginHint ?? loginHint,
|
|
161
|
+
channelPublicId: channelPublicIds?.length ? channelPublicIds.join(',') : undefined,
|
|
80
162
|
nonce: params?.nonce ?? nonce,
|
|
81
163
|
prompt: (
|
|
82
164
|
prompt ??
|
|
@@ -92,6 +174,13 @@ const KakaoUser: KakaoUserAPI = {
|
|
|
92
174
|
}),
|
|
93
175
|
);
|
|
94
176
|
}),
|
|
177
|
+
signup: ({ properties } = {}) =>
|
|
178
|
+
kRunWebAPI(async () => {
|
|
179
|
+
await Kakao.API.request({
|
|
180
|
+
url: '/v1/user/signup',
|
|
181
|
+
data: filterNonNullishKeys({ properties }),
|
|
182
|
+
});
|
|
183
|
+
}),
|
|
95
184
|
logout: () =>
|
|
96
185
|
kRunWebAPI(async () => {
|
|
97
186
|
try {
|
|
@@ -123,17 +212,12 @@ const KakaoUser: KakaoUserAPI = {
|
|
|
123
212
|
data: scopes?.length ? { scopes } : undefined,
|
|
124
213
|
});
|
|
125
214
|
|
|
126
|
-
return camelCaseObject(response.scopes) as KakaoScopeInfo[];
|
|
127
|
-
}),
|
|
128
|
-
revokeScopes: (scopes: string[]) =>
|
|
129
|
-
kRunWebAPI(async () => {
|
|
130
|
-
await Kakao.API.request({
|
|
131
|
-
url: '/v2/user/revoke/scopes',
|
|
132
|
-
data: {
|
|
133
|
-
scopes,
|
|
134
|
-
},
|
|
135
|
-
});
|
|
215
|
+
return camelCaseObject(response.scopes ?? []) as KakaoScopeInfo[];
|
|
136
216
|
}),
|
|
217
|
+
revokeScopes: async (scopes: string[]) => {
|
|
218
|
+
await revokeScopesWithResult(scopes);
|
|
219
|
+
},
|
|
220
|
+
revokeScopesWithResult,
|
|
137
221
|
serviceTerms: ({ result, tags } = {}) =>
|
|
138
222
|
kRunWebAPI(async () => {
|
|
139
223
|
const response: {
|
|
@@ -144,6 +228,7 @@ const KakaoUser: KakaoUserAPI = {
|
|
|
144
228
|
agreed: boolean;
|
|
145
229
|
required: boolean;
|
|
146
230
|
revocable: boolean;
|
|
231
|
+
agreed_by?: string | null;
|
|
147
232
|
}[]
|
|
148
233
|
| null;
|
|
149
234
|
} = await Kakao.API.request({
|
|
@@ -151,13 +236,22 @@ const KakaoUser: KakaoUserAPI = {
|
|
|
151
236
|
data: filterNonNullishKeys({ result, tags: tags?.join(',') }),
|
|
152
237
|
});
|
|
153
238
|
|
|
154
|
-
return (response.service_terms ?? []).map(
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
239
|
+
return (response.service_terms ?? []).map(
|
|
240
|
+
(term): KakaoServiceTerms =>
|
|
241
|
+
filterNonNullishKeys({
|
|
242
|
+
tag: term.tag,
|
|
243
|
+
agreedAt: term.agreed_at ? isoToUnix(term.agreed_at) : undefined,
|
|
244
|
+
agreed: term.agreed,
|
|
245
|
+
required: term.required,
|
|
246
|
+
revocable: term.revocable,
|
|
247
|
+
agreedBy:
|
|
248
|
+
term.agreed_by == null
|
|
249
|
+
? undefined
|
|
250
|
+
: term.agreed_by === 'KAUTH' || term.agreed_by === 'KAPI'
|
|
251
|
+
? term.agreed_by
|
|
252
|
+
: 'unknown',
|
|
253
|
+
}),
|
|
254
|
+
);
|
|
161
255
|
}),
|
|
162
256
|
revokeServiceTerms: (tags) =>
|
|
163
257
|
kRunWebAPI(async () => {
|
|
@@ -226,15 +320,33 @@ const KakaoUser: KakaoUserAPI = {
|
|
|
226
320
|
throw error;
|
|
227
321
|
}
|
|
228
322
|
}),
|
|
229
|
-
|
|
323
|
+
updateProfile: ({ properties }) =>
|
|
230
324
|
kRunWebAPI(async () => {
|
|
231
|
-
|
|
325
|
+
await Kakao.API.request({ url: '/v1/user/update_profile', data: { properties } });
|
|
326
|
+
}),
|
|
327
|
+
me: ({ propertyKeys, secureResource = true } = {}) =>
|
|
328
|
+
kRunWebAPI(async () => {
|
|
329
|
+
const response: { properties?: Record<string, string> } = await Kakao.API.request({
|
|
330
|
+
url: '/v2/user/me',
|
|
331
|
+
data: filterNonNullishKeys({
|
|
332
|
+
property_keys: propertyKeys,
|
|
333
|
+
secure_resource: secureResource,
|
|
334
|
+
}),
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
const ret = camelCaseObject(response) as {
|
|
232
338
|
id: number;
|
|
339
|
+
hasSignedUp?: boolean | null;
|
|
340
|
+
forPartner?: { uuid?: string };
|
|
341
|
+
groupUserToken?: string;
|
|
233
342
|
connectedAt?: string;
|
|
234
343
|
synchedAt?: string;
|
|
235
344
|
kakaoAccount?: Partial<KakaoUserProfile> & {
|
|
236
345
|
profile?: Partial<
|
|
237
|
-
Pick<
|
|
346
|
+
Pick<
|
|
347
|
+
KakaoUserProfile,
|
|
348
|
+
'nickname' | 'profileImageUrl' | 'thumbnailImageUrl' | 'isDefaultImage'
|
|
349
|
+
>
|
|
238
350
|
>;
|
|
239
351
|
};
|
|
240
352
|
properties?: { nickname?: string; profileImage?: string; thumbnailImage?: string };
|
|
@@ -242,9 +354,22 @@ const KakaoUser: KakaoUserAPI = {
|
|
|
242
354
|
const kakaoAccount = ret.kakaoAccount ?? {};
|
|
243
355
|
const properties = ret.properties ?? {};
|
|
244
356
|
const profile = kakaoAccount.profile ?? {};
|
|
357
|
+
const legalGender = kakaoAccount.legalGender;
|
|
245
358
|
|
|
246
359
|
return {
|
|
247
360
|
id: ret.id,
|
|
361
|
+
properties: response.properties ?? {},
|
|
362
|
+
hasSignedUp: ret.hasSignedUp ?? null,
|
|
363
|
+
uuid: ret.forPartner?.uuid ?? null,
|
|
364
|
+
groupUserToken: ret.groupUserToken ?? null,
|
|
365
|
+
isDefaultImage: profile.isDefaultImage ?? null,
|
|
366
|
+
isLeapMonth: kakaoAccount.isLeapMonth ?? null,
|
|
367
|
+
legalName: kakaoAccount.legalName ?? null,
|
|
368
|
+
legalNameNeedsAgreement: kakaoAccount.legalNameNeedsAgreement ?? null,
|
|
369
|
+
legalBirthDate: kakaoAccount.legalBirthDate ?? null,
|
|
370
|
+
legalBirthDateNeedsAgreement: kakaoAccount.legalBirthDateNeedsAgreement,
|
|
371
|
+
legalGender: legalGender === 'female' || legalGender === 'male' ? legalGender : null,
|
|
372
|
+
legalGenderNeedsAgreement: kakaoAccount.legalGenderNeedsAgreement ?? null,
|
|
248
373
|
email: kakaoAccount.email,
|
|
249
374
|
name: kakaoAccount.name,
|
|
250
375
|
nickname: profile.nickname ?? properties.nickname,
|
|
@@ -270,20 +395,35 @@ const KakaoUser: KakaoUserAPI = {
|
|
|
270
395
|
nameNeedsAgreement: kakaoAccount.nameNeedsAgreement,
|
|
271
396
|
profileImageNeedsAgreement: kakaoAccount.profileImageNeedsAgreement,
|
|
272
397
|
profileNicknameNeedsAgreement: kakaoAccount.profileNicknameNeedsAgreement,
|
|
273
|
-
legalBirthDateNeedsAgreement: kakaoAccount.legalBirthDateNeedsAgreement,
|
|
274
398
|
connectedAt: isoToUnix(ret.connectedAt),
|
|
275
399
|
synchedAt: isoToUnix(ret.synchedAt),
|
|
276
400
|
} as KakaoUserProfile;
|
|
277
401
|
}),
|
|
278
402
|
};
|
|
279
403
|
|
|
404
|
+
export function revokeScopesWithResult(scopes: string[]): Promise<KakaoScopeInfo[]> {
|
|
405
|
+
return kRunWebAPI(async () => {
|
|
406
|
+
const response = await Kakao.API.request({
|
|
407
|
+
url: '/v2/user/revoke/scopes',
|
|
408
|
+
data: { scopes },
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
return camelCaseObject(response.scopes ?? []) as KakaoScopeInfo[];
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
|
|
280
415
|
export const {
|
|
416
|
+
loginWithKakao,
|
|
417
|
+
refreshToken,
|
|
418
|
+
issueAccessTokenWithCode,
|
|
281
419
|
isKakaoTalkLoginAvailable,
|
|
282
420
|
isLogined,
|
|
283
421
|
hasToken,
|
|
284
422
|
login,
|
|
423
|
+
signup,
|
|
285
424
|
logout,
|
|
286
425
|
me,
|
|
426
|
+
updateProfile,
|
|
287
427
|
revokeScopes,
|
|
288
428
|
scopes,
|
|
289
429
|
serviceTerms,
|