@react-native-kakao/user 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -1,7 +1,8 @@
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
+ import { validateShippingAddressOptions } from './validateShippingAddressOptions';
5
6
 
6
7
  export interface KakaoLoginToken {
7
8
  accessToken: string;
@@ -14,13 +15,28 @@ export interface KakaoLoginToken {
14
15
  refreshTokenExpiresIn: number;
15
16
  scopes: string[];
16
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
+
17
33
  export interface KakaoScopeInfo {
18
34
  id: string;
19
35
  agreed: boolean;
20
36
  displayName: string;
21
- revocable?: boolean;
37
+ revocable?: boolean | null;
22
38
  using: boolean;
23
- delegated?: boolean;
39
+ delegated?: boolean | null;
24
40
  type: string;
25
41
  }
26
42
  export interface KakaoServiceTerms {
@@ -29,7 +45,12 @@ export interface KakaoServiceTerms {
29
45
  agreed: boolean;
30
46
  required: boolean;
31
47
  revocable: boolean;
48
+ agreedBy?: 'KAUTH' | 'KAPI' | 'unknown';
32
49
  }
50
+ export type KakaoRevokedServiceTerms = {
51
+ tag: string;
52
+ agreed: boolean;
53
+ };
33
54
  export interface KakaoAppServiceTerms {
34
55
  tag: string;
35
56
  createdAt: number;
@@ -56,34 +77,45 @@ export interface KakaoShippingAddress {
56
77
  }
57
78
  export interface KakaoUser {
58
79
  id: number;
59
- email: string;
80
+ properties: Record<string, string>;
81
+ hasSignedUp?: boolean | null;
82
+ uuid?: string | null;
83
+ groupUserToken?: string | null;
84
+ email?: string | null;
60
85
  name?: string | null;
61
- nickname: string;
62
- profileImageUrl: string;
63
- thumbnailImageUrl: string;
86
+ nickname?: string | null;
87
+ profileImageUrl?: string | null;
88
+ thumbnailImageUrl?: string | null;
89
+ isDefaultImage?: boolean | null;
64
90
  phoneNumber?: string | null;
65
91
  ageRange?: string | null;
66
92
  birthday?: string | null;
67
93
  birthdayType?: string | null;
94
+ isLeapMonth?: boolean | null;
68
95
  birthyear?: string | null;
69
96
  gender?: string | null;
70
- isEmailValid: boolean;
71
- isEmailVerified: boolean;
72
- isKorean?: boolean;
73
- ageRangeNeedsAgreement?: boolean;
74
- birthdayNeedsAgreement?: boolean;
75
- birthyearNeedsAgreement?: boolean;
76
- emailNeedsAgreement?: boolean;
77
- genderNeedsAgreement?: boolean;
78
- isKoreanNeedsAgreement?: boolean;
79
- phoneNumberNeedsAgreement?: boolean;
80
- profileNeedsAgreement?: boolean;
81
- nameNeedsAgreement?: boolean;
82
- profileImageNeedsAgreement?: boolean;
83
- profileNicknameNeedsAgreement?: boolean;
84
- legalBirthDateNeedsAgreement?: boolean;
85
- connectedAt?: number;
86
- synchedAt?: number;
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;
87
119
  }
88
120
  export interface KakaoAccessTokenInfo {
89
121
  id?: number;
@@ -96,12 +128,20 @@ export function login({
96
128
  useKakaoAccountLogin,
97
129
  scopes,
98
130
  nonce,
131
+ loginHint,
132
+ channelPublicIds,
133
+ android,
134
+ ios,
99
135
  }: {
100
136
  serviceTerms?: string[];
101
137
  prompts?: ('Login' | 'Create' | 'Cert' | 'SelectAccount')[];
102
138
  scopes?: string[];
103
139
  useKakaoAccountLogin?: boolean;
104
140
  nonce?: string;
141
+ loginHint?: string;
142
+ channelPublicIds?: string[];
143
+ android?: { requestCode?: number };
144
+ ios?: { launchMethod?: KakaoTalkLaunchMethod };
105
145
  web?: {
106
146
  redirectUri: string;
107
147
  scope?: string[];
@@ -113,37 +153,141 @@ export function login({
113
153
  nonce?: string;
114
154
  };
115
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
+
116
165
  kAssert(
117
166
  !useKakaoAccountLogin ? !is.notEmptyArray(prompts) && !is.notEmptyArray(scopes) : true,
118
167
  '[login] `prompts` and `scopes` cannot be passed if useKakaoAccountLogin is false.',
119
168
  );
120
169
 
121
170
  kAssert(
122
- is.notEmptyArray(scopes) ? !is.notEmptyArray(prompts) && !is.notEmptyArray(serviceTerms) : true,
123
- '[login] `scopes` cannot be passed with `prompts` or `serviceTerms`',
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.',
124
185
  );
125
186
 
126
187
  return Native.login(
127
188
  serviceTerms ?? [],
128
189
  prompts ?? [],
129
190
  useKakaoAccountLogin ?? false,
191
+ ios?.launchMethod ?? defaultTalkLaunchMethod,
130
192
  scopes ?? [],
131
193
  nonce,
194
+ loginHint,
195
+ channelPublicIds ?? [],
196
+ requestCode,
197
+ );
198
+ }
199
+
200
+ export async function signup({ properties }: { properties?: Record<string, string> } = {}) {
201
+ await Native.signup(properties);
202
+ }
203
+
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 ?? [],
132
233
  );
133
234
  }
134
235
 
135
- export function logout() {
136
- return Native.logout();
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();
137
279
  }
138
280
 
139
- export function unlink() {
140
- return Native.unlink();
281
+ export async function unlink() {
282
+ await Native.unlink();
141
283
  }
142
284
 
143
285
  export function isLogined() {
144
286
  return Native.isLogined();
145
287
  }
146
288
 
289
+ export const hasToken = Native.hasToken;
290
+
147
291
  export function isKakaoTalkLoginAvailable(): Promise<boolean> {
148
292
  return Native.isKakaoTalkLoginAvailable();
149
293
  }
@@ -152,33 +296,89 @@ export function scopes(scopes?: string[]): Promise<KakaoScopeInfo[]> {
152
296
  return Native.scopes(scopes);
153
297
  }
154
298
 
155
- 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[]> {
156
304
  return Native.revokeScopes(scopes);
157
305
  }
158
306
 
159
- export function serviceTerms(): Promise<KakaoServiceTerms[]> {
160
- return Native.serviceTerms();
307
+ export function serviceTerms({
308
+ result,
309
+ tags,
310
+ }: {
311
+ result?: 'agreed_service_terms' | 'app_service_terms';
312
+ tags?: string[];
313
+ } = {}): Promise<KakaoServiceTerms[]> {
314
+ return Native.serviceTerms(result, tags);
315
+ }
316
+
317
+ export async function shippingAddresses({
318
+ addressId,
319
+ fromUpdatedAt,
320
+ pageSize,
321
+ }: {
322
+ addressId?: number;
323
+ fromUpdatedAt?: number;
324
+ pageSize?: number;
325
+ } = {}): Promise<KakaoShippingAddressResult> {
326
+ validateShippingAddressOptions({ addressId, fromUpdatedAt, pageSize });
327
+
328
+ return Native.shippingAddresses(addressId, fromUpdatedAt, pageSize);
329
+ }
330
+
331
+ export function revokeServiceTerms(tags: string[]): Promise<KakaoRevokedServiceTerms[]> {
332
+ return Native.revokeServiceTerms(tags);
161
333
  }
162
334
 
163
- export function shippingAddresses(): Promise<KakaoShippingAddressResult> {
164
- return Native.shippingAddresses();
335
+ export function selectShippingAddress(): Promise<number> {
336
+ return Native.selectShippingAddress();
165
337
  }
166
338
 
167
- export function me(): Promise<KakaoUser> {
168
- return Native.me();
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);
169
354
  }
170
355
 
171
356
  export function getAccessToken(): Promise<KakaoAccessTokenInfo> {
172
357
  return Native.getAccessToken();
173
358
  }
174
359
 
360
+ export async function updateProfile({
361
+ properties,
362
+ }: {
363
+ properties: Record<string, string>;
364
+ }): Promise<void> {
365
+ await Native.updateProfile(properties);
366
+ }
367
+
175
368
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
176
- 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
+
177
376
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
178
377
  export async function issueAccessTokenWithCodeWeb(params: {
179
378
  redirectUri: string;
180
379
  clientSecret?: string;
181
380
  code: string;
381
+ codeVerifier?: string;
182
382
  }): Promise<{
183
383
  tokenType: string;
184
384
  accessToken: string;
@@ -188,20 +388,32 @@ export async function issueAccessTokenWithCodeWeb(params: {
188
388
  refreshTokenExpiresIn: number;
189
389
  scope?: string;
190
390
  }> {
191
- return {} as any;
391
+ kCreateWebError({
392
+ code: webOnlyErrorCode,
393
+ message: '[issueAccessTokenWithCodeWeb] This API is only supported on web.',
394
+ });
192
395
  }
193
396
 
194
397
  const KakaoUser = {
195
398
  login,
399
+ loginWithKakao,
400
+ refreshToken,
401
+ issueAccessTokenWithCode,
402
+ signup,
196
403
  logout,
197
404
  unlink,
198
405
  isLogined,
406
+ hasToken,
199
407
  isKakaoTalkLoginAvailable,
200
408
  scopes,
201
409
  revokeScopes,
410
+ revokeScopesWithResult,
202
411
  serviceTerms,
412
+ revokeServiceTerms,
203
413
  shippingAddresses,
414
+ selectShippingAddress,
204
415
  me,
416
+ updateProfile,
205
417
  getAccessToken,
206
418
  setAccessTokenWeb,
207
419
  issueAccessTokenWithCodeWeb,