@authing/guard-shim-react18 5.0.8-alpha.1 → 5.0.8-alpha.10

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/package.json CHANGED
@@ -1,33 +1,34 @@
1
1
  {
2
2
  "name": "@authing/guard-shim-react18",
3
- "version": "5.0.8-alpha.1",
3
+ "version": "5.0.8-alpha.10",
4
4
  "description": "Guard shim for react18",
5
- "main": "src/index.tsx",
5
+ "module": "dist/esm/guard.min.js",
6
+ "types": "dist/typings/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
6
10
  "scripts": {
7
11
  "autoinstall": "npm ci",
8
- "build": "echo 'No need to build for @authing/guard-shim-react18'",
12
+ "build": "node scripts/build.js",
9
13
  "lint": "eslint --ext .ts,.tsx src/**",
10
14
  "lint:fix": "eslint --fix --ext .ts,.tsx src/**",
11
15
  "release:official": "npm publish --verbose --access public",
12
16
  "release:alpha": "npm publish --verbose --tag=alpha --access public"
13
17
  },
14
18
  "devDependencies": {
15
- "@types/react": "^17.0.43",
16
- "@types/react-dom": "^17.0.14",
19
+ "@types/react": "^18.0.24",
20
+ "@types/react-dom": "^18.0.8",
17
21
  "css-loader": "^6.7.1",
18
22
  "mini-css-extract-plugin": "^2.6.1",
19
23
  "rimraf": "^2.6.2",
20
24
  "ts-loader": "^9.3.1",
21
25
  "webpack": "^5.72.0"
22
26
  },
23
- "peerDependencies": {
24
- "axios": "^0.27.2",
27
+ "dependencies": {
28
+ "@authing/react18-ui-components": "^4.1.0-alpha.2",
25
29
  "react": "^18.0.0",
26
30
  "react-dom": "^18.0.0"
27
31
  },
28
- "dependencies": {
29
- "@authing/react18-components": "^4.1.0-alpha.0"
30
- },
31
32
  "author": "https://github.com/authing",
32
33
  "license": "MIT",
33
34
  "publishConfig": {
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2019 Authing
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # @authing/guard-shim-react18
2
-
3
- Be only used for internal
package/scripts/build.js DELETED
@@ -1,22 +0,0 @@
1
- const path = require('path')
2
- const rm = require('rimraf')
3
- const webpack = require('webpack')
4
- const webpackEsmBundlerConfig = require('./webpack.esm.config')
5
-
6
- try {
7
- rm.sync(path.resolve(__dirname, '../', 'dist'))
8
- } catch (e) {
9
- console.error('\n\n build guard, failed to delete dist directory, please operate manually \n\n')
10
- }
11
-
12
- readyGo()
13
-
14
- function readyGo () {
15
- webpack(webpackEsmBundlerConfig, (error, stats) => {
16
- if (error) {
17
- console.error('build guard-shim-react18 esm bundler error: ', error)
18
- } else {
19
- console.log(stats)
20
- }
21
- })
22
- }
@@ -1,42 +0,0 @@
1
- const path = require('path')
2
- const MiniCssExtractPlugin = require('mini-css-extract-plugin')
3
-
4
- function resolve (dir, file = '') {
5
- return path.resolve(__dirname, '../', dir, file)
6
- }
7
-
8
- module.exports = {
9
- mode: 'production',
10
- entry: resolve('src/index.tsx'),
11
- output: {
12
- filename: 'guard.min.js',
13
- path: resolve('dist/esm'),
14
- library: {
15
- type: 'module'
16
- }
17
- },
18
- experiments: {
19
- outputModule: true
20
- },
21
- resolve: {
22
- extensions: ['.ts', '.tsx', '.js']
23
- },
24
- module: {
25
- rules: [
26
- {
27
- test: /\.css$/,
28
- use: [MiniCssExtractPlugin.loader, 'css-loader']
29
- },
30
- {
31
- test: /\.tsx?$/,
32
- use: 'ts-loader',
33
- exclude: /node_modules/
34
- }
35
- ]
36
- },
37
- plugins: [
38
- new MiniCssExtractPlugin({
39
- filename: 'guard.min.css'
40
- })
41
- ]
42
- }
package/src/index.tsx DELETED
@@ -1,515 +0,0 @@
1
- import React from 'react'
2
-
3
- import { createRoot, Root } from 'react-dom/client'
4
-
5
- import {
6
- GuardOptions,
7
- GuardMode,
8
- GuardEventsCamelToKebabMapping,
9
- GuardLocalConfig,
10
- GuardEventListeners,
11
- GuardEvents,
12
- Guard as ReactAuthingGuard,
13
- GuardEventsKebabToCamelType,
14
- StartWithRedirectOptions,
15
- AuthenticationClient,
16
- JwtTokenStatus,
17
- User,
18
- GuardModuleType,
19
- Lang,
20
- IGuardConfig
21
- } from './types'
22
-
23
- import '@authing/react18-components/lib/index.min.css'
24
-
25
- export * from './types'
26
-
27
- const isDef = (value: unknown) => value !== undefined
28
-
29
- export class Guard {
30
- public options: GuardOptions
31
-
32
- private visible = false
33
-
34
- private then: () => Promise<any | never>
35
-
36
- private publicConfig?: Record<string, unknown>
37
-
38
- private root?: Root
39
-
40
- constructor(options: GuardOptions) {
41
- if (!options.appId) {
42
- throw new Error('appId is required')
43
- }
44
-
45
- const config = {
46
- ...options.config
47
- }
48
-
49
- this.options = this.adaptOptions(options, config)
50
-
51
- const init = (async () => {
52
- if (this.publicConfig) {
53
- return this.publicConfig
54
- }
55
-
56
- const publicConfigRes = await this.getPublicConfig()
57
-
58
- return (this.publicConfig = publicConfigRes.data)
59
- })()
60
-
61
- this.then = init.then.bind(init)
62
-
63
- this.visible = !!(options.mode === GuardMode.Modal)
64
- }
65
-
66
- private adaptOptions(options: GuardOptions, config: Partial<IGuardConfig>) {
67
- options.host = options.host || ''
68
-
69
- if (isDef(options.isSSO)) {
70
- config.isSSO = options.isSSO
71
- }
72
-
73
- if (isDef(options.defaultScene)) {
74
- // @ts-ignore
75
- config.defaultScenes = options.defaultScene
76
- }
77
-
78
- if (isDef(options.lang)) {
79
- config.lang = options.lang
80
- }
81
-
82
- if (isDef(options.host)) {
83
- config.host = options.host
84
- }
85
-
86
- if (isDef(options.mode)) {
87
- // @ts-ignore
88
- config.mode = options.mode
89
- }
90
-
91
- options.config = config
92
-
93
- if (isDef(options.config.socialConnectionList)) {
94
- // @ts-ignore
95
- options.config.socialConnections = options.config.socialConnectionList
96
- }
97
-
98
- if (isDef(options.config.loginMethod)) {
99
- // @ts-ignore
100
- options.config.defaultLoginMethod = options.config.loginMethod
101
- }
102
-
103
- if (isDef(options.config.loginMethodList)) {
104
- // @ts-ignore
105
- options.config.loginMethods = options.config.loginMethodList
106
- }
107
-
108
- if (isDef(options.config.registerMethodList)) {
109
- // @ts-ignore
110
- options.config.registerMethods = options.config.registerMethodList
111
- }
112
-
113
- if (isDef(options.config.registerMethod)) {
114
- // @ts-ignore
115
- options.config.defaultRegisterMethod = options.config.registerMethod
116
- }
117
-
118
- if (isDef(options.config.contentCSS)) {
119
- options.config.contentCss = options.config.contentCSS
120
- }
121
-
122
- return options
123
- }
124
-
125
- private async getPublicConfig(): Promise<{
126
- [prop: string]: any
127
- }> {
128
- const host = `${this.options.host}` || 'https://core.authing.cn'
129
-
130
- const options: RequestInit = {
131
- method: 'GET',
132
- credentials: 'include'
133
- }
134
-
135
- const fetchRes = await fetch(
136
- `${host}/api/v2/applications/${this.options.appId}/public-config`,
137
- options
138
- )
139
-
140
- const publicConfig = await fetchRes.text()
141
-
142
- return JSON.parse(publicConfig)
143
- }
144
-
145
- async getAuthClient(): Promise<AuthenticationClient> {
146
- let publicConfig = {} as any
147
-
148
- try {
149
- publicConfig = await this.then()
150
- } catch (e) {
151
- throw new Error(JSON.stringify(e))
152
- }
153
-
154
- const _authClientOptions = Object.assign(
155
- {},
156
- {
157
- appId: this.options.appId,
158
- appHost: this.options.host || `https://${publicConfig.requestHostname}`,
159
- tenantId: this.options.tenantId,
160
- redirectUri:
161
- this.options.redirectUri || publicConfig.oidcConfig.redirect_uris[0],
162
- tokenEndPointAuthMethod:
163
- publicConfig.oidcConfig.token_endpoint_auth_method || 'none',
164
- introspectionEndPointAuthMethod:
165
- publicConfig.oidcConfig.introspection_endpoint_auth_method || 'none'
166
- }
167
- )
168
-
169
- return new AuthenticationClient(_authClientOptions)
170
- }
171
-
172
- static getGuardContainer(selector?: string | HTMLElement): Element | null {
173
- const defaultId = 'authing_guard_container'
174
-
175
- if (!selector) {
176
- let container = document.querySelector(`#${defaultId}`)
177
- if (!container) {
178
- container = document.createElement('div')
179
- container.id = defaultId
180
- document.body.appendChild(container)
181
- }
182
-
183
- return container
184
- }
185
-
186
- if (typeof selector === 'string') {
187
- const res = document.querySelector(selector)
188
- if (!res) {
189
- console.warn(
190
- `Failed to start guard: target selector "${selector}" returned null.`
191
- )
192
- }
193
- return res
194
- }
195
-
196
- return selector
197
- }
198
-
199
- private eventListeners = Object.values(GuardEventsCamelToKebabMapping).reduce(
200
- (acc, evtName) => {
201
- return Object.assign({}, acc, {
202
- [evtName as string]: []
203
- })
204
- },
205
- {} as GuardEventListeners
206
- )
207
-
208
- /**
209
- * 启动嵌入模式
210
- * @param el String
211
- * @returns Promise
212
- */
213
- async start(el?: string): Promise<User> {
214
- ;(this.options.config as Partial<GuardLocalConfig>).target = el
215
-
216
- this.render()
217
-
218
- const userInfo = await this.trackSession()
219
-
220
- if (userInfo) {
221
- return Promise.resolve(userInfo)
222
- }
223
-
224
- return new Promise(resolve => {
225
- this.on('login', userInfo => {
226
- resolve(userInfo)
227
- })
228
- })
229
- }
230
-
231
- startRegister() {
232
- this.options.defaultScene = GuardModuleType.REGISTER
233
-
234
- this.options.config = Object.assign({}, this.options.config, {
235
- defaultScenes: GuardModuleType.REGISTER
236
- })
237
-
238
- this.unmount()
239
- this.render()
240
- }
241
-
242
- async checkLoginStatus(): Promise<JwtTokenStatus | undefined> {
243
- const authClient = await this.getAuthClient()
244
- const user = await authClient.getCurrentUser()
245
-
246
- if (!user) {
247
- return
248
- }
249
-
250
- const token = user.token
251
-
252
- if (!token) {
253
- return
254
- }
255
-
256
- const loginStatus: JwtTokenStatus = await authClient.checkLoginStatus(token)
257
-
258
- if (loginStatus.status) {
259
- return loginStatus
260
- }
261
- }
262
-
263
- changeLang(lang: Lang) {
264
- this.options.lang = lang
265
-
266
- this.options.config = Object.assign({}, this.options.config, {
267
- lang
268
- })
269
-
270
- this.unmount()
271
- this.render()
272
- }
273
-
274
- changeContentCSS(contentCSS: string) {
275
- this.options.config = Object.assign({}, this.options.config, {
276
- contentCss: contentCSS
277
- })
278
-
279
- this.unmount()
280
- this.render()
281
- }
282
-
283
- /**
284
- * 启动跳转模式
285
- */
286
- async startWithRedirect(options: StartWithRedirectOptions = {}) {
287
- const getRandom = () => Math.random().toString().slice(2)
288
-
289
- const {
290
- codeChallengeMethod = 'S256',
291
- scope = 'openid profile email phone address',
292
- redirectUri,
293
- state = getRandom(),
294
- nonce = getRandom(),
295
- responseMode = 'query',
296
- responseType = 'code'
297
- } = options
298
-
299
- const authClient = await this.getAuthClient()
300
-
301
- // 生成一个 code_verifier
302
- const codeChallenge = authClient.generateCodeChallenge()
303
-
304
- localStorage.setItem('codeChallenge', codeChallenge)
305
-
306
- // 计算 code_verifier 的 SHA256 摘要
307
- const codeChallengeDigest = authClient.getCodeChallengeDigest({
308
- codeChallenge,
309
- method: codeChallengeMethod
310
- })
311
-
312
- // 构造 OIDC 授权码 + PKCE 模式登录 URL
313
- const url = authClient.buildAuthorizeUrl({
314
- codeChallenge: codeChallengeDigest,
315
- codeChallengeMethod,
316
- scope,
317
- redirectUri,
318
- state,
319
- nonce,
320
- responseMode,
321
- responseType
322
- })
323
-
324
- window.location.href = url
325
- }
326
-
327
- async handleRedirectCallback() {
328
- const { code, codeChallenge } = this.getCodeAndCodeChallenge()
329
-
330
- const { id_token, access_token } = await this.getAccessTokenByCode(
331
- code,
332
- codeChallenge
333
- )
334
-
335
- const authClient = await this.getAuthClient()
336
-
337
- const userInfo = await authClient.getUserInfoByAccessToken(access_token)
338
-
339
- this.setStorageCache(access_token, id_token, userInfo)
340
- }
341
-
342
- private async getAccessTokenByCode(code: string, codeChallenge: string) {
343
- const authClient = await this.getAuthClient()
344
-
345
- return await authClient.getAccessTokenByCode(code, {
346
- codeVerifier: codeChallenge
347
- })
348
- }
349
-
350
- private getCodeAndCodeChallenge() {
351
- const query = this.parseUrlQuery()
352
- const { code = '' } = query
353
- const codeChallenge = localStorage.getItem('codeChallenge') || ''
354
-
355
- return {
356
- code,
357
- codeChallenge
358
- }
359
- }
360
-
361
- private setStorageCache(
362
- accessToken: string,
363
- idToken: string,
364
- userInfo: string
365
- ) {
366
- localStorage.setItem('accessToken', accessToken)
367
- localStorage.setItem('idToken', idToken)
368
- localStorage.setItem('userInfo', JSON.stringify(userInfo))
369
- }
370
-
371
- private parseUrlQuery() {
372
- const query: Record<string, string> = {}
373
-
374
- let queryString = ''
375
-
376
- try {
377
- queryString = window.location.search.split('?')[1]
378
- } catch (e) {
379
- queryString = window.location.hash.split('#')[1]
380
- }
381
-
382
- if (!queryString) {
383
- return query
384
- }
385
-
386
- queryString.split('&').forEach(item => {
387
- const [key, value] = item.split('=')
388
- query[key] = value
389
- })
390
-
391
- return query
392
- }
393
-
394
- /**
395
- * 获取当前用户信息
396
- */
397
- async trackSession(): Promise<User | null> {
398
- const authClient = await this.getAuthClient()
399
-
400
- return authClient.getCurrentUser()
401
- }
402
-
403
- async logout() {
404
- const publicConfig = await this.then()
405
-
406
- let redirectUri = ''
407
-
408
- const origin = window.location.origin
409
-
410
- try {
411
- redirectUri = publicConfig.logoutRedirectUris[0]
412
- } catch (e) {
413
- redirectUri = origin
414
- } finally {
415
- if (!redirectUri) {
416
- redirectUri = origin
417
- }
418
- }
419
-
420
- const idToken = localStorage.getItem('idToken')
421
- let logoutUrl = ''
422
- const authClient = await this.getAuthClient()
423
-
424
- authClient.logout()
425
-
426
- if (idToken) {
427
- logoutUrl = authClient.buildLogoutUrl({
428
- expert: true,
429
- redirectUri,
430
- idToken
431
- })
432
- }
433
-
434
- localStorage.clear()
435
-
436
- window.location.href = logoutUrl || redirectUri
437
- }
438
-
439
- async render() {
440
- const evts: GuardEvents = Object.entries(
441
- GuardEventsCamelToKebabMapping
442
- ).reduce((acc, [reactEvt, nativeEvt]) => {
443
- return Object.assign({}, acc, {
444
- [reactEvt]: (...rest: any) => {
445
- if (nativeEvt === 'close') {
446
- this.hide()
447
- }
448
-
449
- // TODO 返回最后一个执行函数的值,实际应该只让监听一次
450
- return (
451
- (this.eventListeners as any)[nativeEvt as string]
452
- .map((item: any) => {
453
- return item(...rest)
454
- })
455
- .slice(-1)[0] ?? true
456
- )
457
- }
458
- })
459
- }, {} as GuardEvents)
460
-
461
- const publicConfig = await this.then()
462
- const authClient = await this.getAuthClient()
463
-
464
- if (this.options.config) {
465
- this.options.config.host =
466
- this.options.host || `https://${publicConfig.requestHostname}`
467
- }
468
-
469
- const target = Guard.getGuardContainer(this.options.config?.target)
470
-
471
- if (!target) {
472
- return
473
- }
474
-
475
- const root = (this.root = createRoot(target))
476
-
477
- return root.render(
478
- <ReactAuthingGuard
479
- {...(evts as GuardEvents)}
480
- appId={this.options.appId}
481
- tenantId={this.options.tenantId}
482
- config={this.options.config}
483
- facePlugin={this.options.facePlugin}
484
- appendConfig={this.options.appendConfig}
485
- visible={this.visible}
486
- authClient={authClient}
487
- />
488
- )
489
- }
490
-
491
- on<T extends keyof GuardEventsKebabToCamelType>(
492
- evt: T,
493
- handler: Exclude<GuardEventsKebabToCamelType[T], undefined>
494
- ) {
495
- ;(this.eventListeners as any)[evt].push(handler as any)
496
- }
497
-
498
- show() {
499
- this.visible = true
500
- this.render()
501
- }
502
-
503
- hide() {
504
- this.visible = false
505
- this.render()
506
- }
507
-
508
- unmount() {
509
- const node = Guard.getGuardContainer(this.options.config?.target)
510
-
511
- if (node && this.root) {
512
- this.root.unmount()
513
- }
514
- }
515
- }
package/src/types.ts DELETED
@@ -1,93 +0,0 @@
1
- import {
2
- GuardEventsKebabToCamelType,
3
- Lang,
4
- GuardProps,
5
- GuardLocalConfig,
6
- CodeAction,
7
- ApiCode,
8
- GuardModuleType,
9
- LoginMethods,
10
- OIDCConnectionMode,
11
- SocialConnectionProvider,
12
- Protocol,
13
- RegisterMethods,
14
- GuardMode,
15
- InputMethod,
16
- GuardPageSene,
17
- EmailScene,
18
- SceneType
19
- } from '@authing/react18-components'
20
-
21
- export type ICodeAction = `${CodeAction}`
22
- export type IApiCode = `${ApiCode}`
23
- export type IGuardModuleType = `${GuardModuleType}`
24
- export type ILoginMethod = `${LoginMethods}`
25
- export type IOIDCConnectionMode = `${OIDCConnectionMode}`
26
- export type ISocialConnectionProvider = `${SocialConnectionProvider}`
27
- export type IProtocol = `${Protocol}`
28
- export type IRegisterMethod = `${RegisterMethods}`
29
- export type IGuardMode = `${GuardMode}`
30
- export type IInputMethod = `${InputMethod}`
31
- export type IGuardPageSene = `${GuardPageSene}`
32
- export type IEmailScene = `${EmailScene}`
33
- export type ISceneType = `${SceneType}`
34
-
35
- export type GuardEventListeners = {
36
- [key in keyof GuardEventsKebabToCamelType]: Exclude<
37
- Required<GuardEventsKebabToCamelType>[key],
38
- undefined
39
- >[]
40
- }
41
-
42
- export type CodeChallengeMethod = 'S256' | 'plain'
43
-
44
- export interface IGuardConfig extends GuardLocalConfig {
45
- // replace socialConnections
46
- socialConnectionList?: ISocialConnectionProvider[]
47
-
48
- // replace defaultLoginMethod
49
- loginMethod?: ILoginMethod
50
-
51
- // replace loginMethods
52
- loginMethodList: ILoginMethod[]
53
-
54
- // replace defaultRegisterMethod
55
- registerMethod?: IRegisterMethod
56
-
57
- // replace registerMethods
58
- registerMethodList?: IRegisterMethod[]
59
-
60
- // replace contentCss
61
- contentCSS?: string
62
- }
63
-
64
- export interface GuardOptions extends GuardProps {
65
- appId: string
66
- host?: string
67
- redirectUri?: string
68
- mode?: IGuardMode
69
- defaultScene?: IGuardModuleType
70
- tenantId?: string
71
- lang?: Lang
72
- isSSO?: boolean
73
- config?: Partial<IGuardConfig> // 兼容 4.x 的 config
74
- }
75
-
76
- export interface StartWithRedirectOptions {
77
- codeChallengeMethod?: CodeChallengeMethod
78
- scope?: string
79
- redirectUri?: string
80
- state?: string
81
- responseType?:
82
- | 'code'
83
- | 'code id_token token'
84
- | 'code id_token'
85
- | 'code token'
86
- | 'id_token token'
87
- | 'id_token'
88
- | 'none'
89
- responseMode?: 'query' | 'fragment' | 'form_post'
90
- nonce?: string
91
- }
92
-
93
- export * from '@authing/react18-components'
package/tsconfig.json DELETED
@@ -1,31 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "baseUrl": ".",
4
- "outDir": "dist",
5
- "target": "es5",
6
- "lib": ["dom", "esnext"],
7
- "allowJs": false,
8
- "skipLibCheck": true,
9
- "esModuleInterop": true,
10
- "allowSyntheticDefaultImports": true,
11
- "strict": true,
12
- "forceConsistentCasingInFileNames": true,
13
- "noFallthroughCasesInSwitch": true,
14
- "module": "esnext",
15
- "moduleResolution": "node",
16
- "resolveJsonModule": true,
17
- "declaration": true,
18
- "declarationDir": "./dist/typings",
19
- "noEmit": false,
20
- "jsx": "react",
21
- "downlevelIteration": true
22
- },
23
- "include": [
24
- "src/**/*.tsx",
25
- "src/**/*.ts"
26
- ],
27
- "exclude": [
28
- "node_modules",
29
- "dist"
30
- ]
31
- }