@atproto/oauth-client-expo 0.1.3 → 0.1.4
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 +13 -0
- package/package.json +16 -8
- package/src/ExpoAtprotoOAuthClientModule.ts +0 -33
- package/src/ExpoAtprotoOAuthClientModule.types.ts +0 -2
- package/src/expo-oauth-client-interface.ts +0 -10
- package/src/expo-oauth-client-options.ts +0 -27
- package/src/expo-oauth-client.d.ts +0 -6
- package/src/expo-oauth-client.native.ts +0 -110
- package/src/expo-oauth-client.web.ts +0 -42
- package/src/index.ts +0 -8
- package/src/polyfill.d.ts +0 -1
- package/src/polyfill.native.ts +0 -2
- package/src/polyfill.web.ts +0 -1
- package/src/utils/expo-key.ts +0 -50
- package/src/utils/mmkv-simple-store-ttl.ts +0 -90
- package/src/utils/mmkv-simple-store.ts +0 -48
- package/src/utils/stores.ts +0 -115
- package/tsconfig.build.json +0 -8
- package/tsconfig.build.tsbuildinfo +0 -1
- package/tsconfig.json +0 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @atproto/oauth-client-expo
|
|
2
2
|
|
|
3
|
+
## 0.1.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#5099](https://github.com/bluesky-social/atproto/pull/5099) [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Update TypeScript build to rely on references to composite internal projects
|
|
8
|
+
|
|
9
|
+
- [#5099](https://github.com/bluesky-social/atproto/pull/5099) [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Bundle only necessary files in the NPM tarball, including the `CHANGELOG.md` and `README.md` files (if present).
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [[`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07), [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07), [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07)]:
|
|
12
|
+
- @atproto/oauth-client-browser@0.4.5
|
|
13
|
+
- @atproto-labs/simple-store@0.4.3
|
|
14
|
+
- @atproto/oauth-client@0.7.7
|
|
15
|
+
|
|
3
16
|
## 0.1.3
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/oauth-client-expo",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"engines": {
|
|
5
|
-
"node": ">=22"
|
|
6
|
-
},
|
|
3
|
+
"version": "0.1.4",
|
|
7
4
|
"license": "MIT",
|
|
8
5
|
"description": "ATPROTO OAuth client for Expo applications",
|
|
9
6
|
"authors": [
|
|
@@ -26,26 +23,37 @@
|
|
|
26
23
|
"url": "https://github.com/bluesky-social/atproto",
|
|
27
24
|
"directory": "packages/oauth/oauth-client-expo"
|
|
28
25
|
},
|
|
26
|
+
"files": [
|
|
27
|
+
"./expo-module.config.json",
|
|
28
|
+
"./android",
|
|
29
|
+
"./ios",
|
|
30
|
+
"./dist",
|
|
31
|
+
"./README.md",
|
|
32
|
+
"./CHANGELOG.md"
|
|
33
|
+
],
|
|
34
|
+
"type": "module",
|
|
29
35
|
"exports": {
|
|
30
36
|
".": {
|
|
31
37
|
"types": "./dist/index.d.ts",
|
|
32
38
|
"default": "./dist/index.js"
|
|
33
39
|
}
|
|
34
40
|
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=22"
|
|
43
|
+
},
|
|
35
44
|
"dependencies": {
|
|
36
45
|
"core-js": "^3",
|
|
37
46
|
"expo-web-browser": "^15.0.8",
|
|
38
47
|
"react-native-mmkv": "^3.3.3",
|
|
39
48
|
"react-native-url-polyfill": "^3.0.0",
|
|
40
|
-
"@atproto/
|
|
41
|
-
"@atproto
|
|
42
|
-
"@atproto/oauth-client-browser": "^0.4.
|
|
49
|
+
"@atproto-labs/simple-store": "^0.4.3",
|
|
50
|
+
"@atproto/oauth-client": "^0.7.7",
|
|
51
|
+
"@atproto/oauth-client-browser": "^0.4.5"
|
|
43
52
|
},
|
|
44
53
|
"peerDependencies": {
|
|
45
54
|
"expo": "*",
|
|
46
55
|
"react-native": "*"
|
|
47
56
|
},
|
|
48
|
-
"type": "module",
|
|
49
57
|
"scripts": {
|
|
50
58
|
"build": "tsgo --build tsconfig.build.json"
|
|
51
59
|
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { NativeModule, requireNativeModule } from 'expo'
|
|
2
|
-
import { SignedJwt, VerifyOptions, VerifyResult } from '@atproto/oauth-client'
|
|
3
|
-
import { ExpoAtprotoOAuthClientModuleEvents } from './ExpoAtprotoOAuthClientModule.types.js'
|
|
4
|
-
|
|
5
|
-
export type NativeJwk = {
|
|
6
|
-
kty: 'EC'
|
|
7
|
-
crv: 'P-256'
|
|
8
|
-
kid: string
|
|
9
|
-
x: string
|
|
10
|
-
y: string
|
|
11
|
-
d: string
|
|
12
|
-
alg: 'ES256'
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
declare class ExpoAtprotoOAuthClientModule extends NativeModule<ExpoAtprotoOAuthClientModuleEvents> {
|
|
16
|
-
digest(data: Uint8Array, algo: string): Promise<Uint8Array>
|
|
17
|
-
|
|
18
|
-
getRandomValues(byteLength: number): Promise<Uint8Array>
|
|
19
|
-
|
|
20
|
-
generatePrivateJwk(algorithm: string): Promise<NativeJwk>
|
|
21
|
-
|
|
22
|
-
createJwt(header: string, payload: string, jwk: NativeJwk): Promise<SignedJwt>
|
|
23
|
-
|
|
24
|
-
verifyJwt<C extends string = never>(
|
|
25
|
-
token: SignedJwt,
|
|
26
|
-
jwk: NativeJwk,
|
|
27
|
-
options: VerifyOptions<C>,
|
|
28
|
-
): Promise<VerifyResult<C>>
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export default requireNativeModule<ExpoAtprotoOAuthClientModule>(
|
|
32
|
-
'ExpoAtprotoOAuthClient',
|
|
33
|
-
)
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AuthorizeOptions,
|
|
3
|
-
OAuthClient,
|
|
4
|
-
OAuthSession,
|
|
5
|
-
} from '@atproto/oauth-client'
|
|
6
|
-
|
|
7
|
-
export interface ExpoOAuthClientInterface extends OAuthClient, AsyncDisposable {
|
|
8
|
-
signIn(input: string, options?: AuthorizeOptions): Promise<OAuthSession>
|
|
9
|
-
handleCallback(): Promise<null | OAuthSession>
|
|
10
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
OAuthClientMetadataInput,
|
|
3
|
-
OAuthClientOptions,
|
|
4
|
-
OAuthResponseMode,
|
|
5
|
-
} from '@atproto/oauth-client'
|
|
6
|
-
|
|
7
|
-
export type Simplify<T> = { [K in keyof T]: T[K] } & NonNullable<unknown>
|
|
8
|
-
|
|
9
|
-
export type ExpoOAuthClientOptions = Simplify<
|
|
10
|
-
{
|
|
11
|
-
clientMetadata: Readonly<OAuthClientMetadataInput>
|
|
12
|
-
responseMode?: Exclude<OAuthResponseMode, 'form_post'>
|
|
13
|
-
} & Omit<
|
|
14
|
-
OAuthClientOptions,
|
|
15
|
-
| 'clientMetadata'
|
|
16
|
-
| 'responseMode'
|
|
17
|
-
| 'keyset'
|
|
18
|
-
| 'runtimeImplementation'
|
|
19
|
-
| 'sessionStore'
|
|
20
|
-
| 'stateStore'
|
|
21
|
-
| 'didCache'
|
|
22
|
-
| 'handleCache'
|
|
23
|
-
| 'dpopNonceCache'
|
|
24
|
-
| 'authorizationServerMetadataCache'
|
|
25
|
-
| 'protectedResourceMetadataCache'
|
|
26
|
-
>
|
|
27
|
-
>
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { ExpoOAuthClientInterface } from './expo-oauth-client-interface.js'
|
|
2
|
-
import { ExpoOAuthClientOptions } from './expo-oauth-client-options.js'
|
|
3
|
-
|
|
4
|
-
export declare class ExpoOAuthClient implements ExpoOAuthClientInterface {
|
|
5
|
-
constructor(options: ExpoOAuthClientOptions)
|
|
6
|
-
}
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { openAuthSessionAsync } from 'expo-web-browser'
|
|
2
|
-
import {
|
|
3
|
-
AuthorizeOptions,
|
|
4
|
-
OAuthClient,
|
|
5
|
-
OAuthSession,
|
|
6
|
-
RuntimeImplementation,
|
|
7
|
-
} from '@atproto/oauth-client'
|
|
8
|
-
import { default as NativeModule } from './ExpoAtprotoOAuthClientModule.js'
|
|
9
|
-
import { ExpoOAuthClientInterface } from './expo-oauth-client-interface.js'
|
|
10
|
-
import { ExpoOAuthClientOptions } from './expo-oauth-client-options.js'
|
|
11
|
-
import { ExpoKey } from './utils/expo-key.js'
|
|
12
|
-
import {
|
|
13
|
-
AuthorizationServerMetadataCache,
|
|
14
|
-
DidCache,
|
|
15
|
-
DpopNonceCache,
|
|
16
|
-
HandleCache,
|
|
17
|
-
ProtectedResourceMetadataCache,
|
|
18
|
-
SessionStore,
|
|
19
|
-
StateStore,
|
|
20
|
-
} from './utils/stores.js'
|
|
21
|
-
|
|
22
|
-
export const CUSTOM_URI_SCHEME_REGEX = /^(?:[^.]+(?:\.[^.]+)+):\/(?:[^/].*)?$/
|
|
23
|
-
const isCustomUriScheme = (uri: string) => CUSTOM_URI_SCHEME_REGEX.test(uri)
|
|
24
|
-
|
|
25
|
-
const runtimeImplementation: RuntimeImplementation = {
|
|
26
|
-
createKey: async (algs) => ExpoKey.generate(algs),
|
|
27
|
-
digest: async (bytes, { name }) =>
|
|
28
|
-
NativeModule.digest(bytes, name) as Promise<Uint8Array<ArrayBuffer>>,
|
|
29
|
-
getRandomValues: async (length) => NativeModule.getRandomValues(length),
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export class ExpoOAuthClient
|
|
33
|
-
extends OAuthClient
|
|
34
|
-
implements ExpoOAuthClientInterface
|
|
35
|
-
{
|
|
36
|
-
readonly #disposables: DisposableStack
|
|
37
|
-
|
|
38
|
-
constructor(options: ExpoOAuthClientOptions) {
|
|
39
|
-
using stack = new DisposableStack()
|
|
40
|
-
|
|
41
|
-
super({
|
|
42
|
-
...options,
|
|
43
|
-
responseMode: options.responseMode ?? 'query',
|
|
44
|
-
keyset: undefined,
|
|
45
|
-
runtimeImplementation,
|
|
46
|
-
sessionStore: stack.use(new SessionStore()),
|
|
47
|
-
stateStore: stack.use(new StateStore()),
|
|
48
|
-
didCache: stack.use(new DidCache()),
|
|
49
|
-
handleCache: stack.use(new HandleCache()),
|
|
50
|
-
dpopNonceCache: stack.use(new DpopNonceCache()),
|
|
51
|
-
authorizationServerMetadataCache: stack.use(
|
|
52
|
-
new AuthorizationServerMetadataCache(),
|
|
53
|
-
),
|
|
54
|
-
protectedResourceMetadataCache: stack.use(
|
|
55
|
-
new ProtectedResourceMetadataCache(),
|
|
56
|
-
),
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
this.#disposables = stack.move()
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async handleCallback(): Promise<null | OAuthSession> {
|
|
63
|
-
return null
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async signIn(
|
|
67
|
-
input: string,
|
|
68
|
-
options?: AuthorizeOptions,
|
|
69
|
-
): Promise<OAuthSession> {
|
|
70
|
-
const redirectUri =
|
|
71
|
-
options?.redirect_uri ??
|
|
72
|
-
this.clientMetadata.redirect_uris.find(isCustomUriScheme)
|
|
73
|
-
|
|
74
|
-
if (!redirectUri) {
|
|
75
|
-
throw new TypeError(
|
|
76
|
-
'A redirect URI with a custom scheme is required for Expo OAuth.',
|
|
77
|
-
)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const url = await this.authorize(input, {
|
|
81
|
-
...options,
|
|
82
|
-
redirect_uri: redirectUri,
|
|
83
|
-
display: options?.display ?? 'touch',
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
const result = await openAuthSessionAsync(url.toString(), redirectUri, {
|
|
87
|
-
dismissButtonStyle: 'cancel', // iOS only
|
|
88
|
-
preferEphemeralSession: false, // iOS only
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
if (result.type === 'success') {
|
|
92
|
-
const callbackUrl = new URL(result.url)
|
|
93
|
-
const params =
|
|
94
|
-
this.responseMode === 'fragment'
|
|
95
|
-
? new URLSearchParams(callbackUrl.hash.slice(1))
|
|
96
|
-
: callbackUrl.searchParams
|
|
97
|
-
|
|
98
|
-
const { session } = await this.callback(params, {
|
|
99
|
-
redirect_uri: redirectUri,
|
|
100
|
-
})
|
|
101
|
-
return session
|
|
102
|
-
} else {
|
|
103
|
-
throw new Error(`Authentication cancelled: ${result.type}`)
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async [Symbol.asyncDispose]() {
|
|
108
|
-
this.#disposables.dispose()
|
|
109
|
-
}
|
|
110
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AuthorizeOptions,
|
|
3
|
-
BrowserOAuthClient,
|
|
4
|
-
OAuthSession,
|
|
5
|
-
} from '@atproto/oauth-client-browser'
|
|
6
|
-
import { ExpoOAuthClientInterface } from './expo-oauth-client-interface.js'
|
|
7
|
-
import { ExpoOAuthClientOptions } from './expo-oauth-client-options.js'
|
|
8
|
-
|
|
9
|
-
export class ExpoOAuthClient
|
|
10
|
-
extends BrowserOAuthClient
|
|
11
|
-
implements ExpoOAuthClientInterface
|
|
12
|
-
{
|
|
13
|
-
constructor({
|
|
14
|
-
clientMetadata,
|
|
15
|
-
responseMode = 'fragment',
|
|
16
|
-
...options
|
|
17
|
-
}: ExpoOAuthClientOptions) {
|
|
18
|
-
super({ ...options, clientMetadata, responseMode })
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
override async signIn(
|
|
22
|
-
input: string,
|
|
23
|
-
options?: AuthorizeOptions,
|
|
24
|
-
): Promise<OAuthSession> {
|
|
25
|
-
// Force popup mode
|
|
26
|
-
return this.signInPopup(input, {
|
|
27
|
-
...options,
|
|
28
|
-
display: options?.display ?? 'touch',
|
|
29
|
-
})
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async handleCallback(): Promise<null | OAuthSession> {
|
|
33
|
-
const params = this.readCallbackParams()
|
|
34
|
-
if (!params) return null
|
|
35
|
-
|
|
36
|
-
const url = this.findRedirectUrl()
|
|
37
|
-
if (!url) return null
|
|
38
|
-
|
|
39
|
-
const { session } = await this.initCallback(params, url)
|
|
40
|
-
return session
|
|
41
|
-
}
|
|
42
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import './polyfill'
|
|
2
|
-
|
|
3
|
-
export * from '@atproto/oauth-client'
|
|
4
|
-
|
|
5
|
-
export type { ExpoOAuthClientInterface } from './expo-oauth-client-interface.js'
|
|
6
|
-
export type { ExpoOAuthClientOptions } from './expo-oauth-client-options.js'
|
|
7
|
-
|
|
8
|
-
export { ExpoOAuthClient } from './expo-oauth-client.js'
|
package/src/polyfill.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {}
|
package/src/polyfill.native.ts
DELETED
package/src/polyfill.web.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import 'core-js/proposals/explicit-resource-management'
|
package/src/utils/expo-key.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type Jwk,
|
|
3
|
-
type JwtHeader,
|
|
4
|
-
type JwtPayload,
|
|
5
|
-
Key,
|
|
6
|
-
type SignedJwt,
|
|
7
|
-
type VerifyOptions,
|
|
8
|
-
type VerifyResult,
|
|
9
|
-
} from '@atproto/oauth-client'
|
|
10
|
-
import type { NativeJwk } from '../ExpoAtprotoOAuthClientModule.js'
|
|
11
|
-
import { default as NativeModule } from '../ExpoAtprotoOAuthClientModule.js'
|
|
12
|
-
|
|
13
|
-
export type ExpoJwk = Jwk & NativeJwk & { key_ops: ['sign'] }
|
|
14
|
-
export class ExpoKey extends Key<ExpoJwk> {
|
|
15
|
-
async createJwt(header: JwtHeader, payload: JwtPayload): Promise<SignedJwt> {
|
|
16
|
-
return NativeModule.createJwt(
|
|
17
|
-
JSON.stringify(header),
|
|
18
|
-
JSON.stringify(payload),
|
|
19
|
-
toNativeJwk(this.jwk),
|
|
20
|
-
)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async verifyJwt<C extends string = never>(
|
|
24
|
-
token: SignedJwt,
|
|
25
|
-
options: VerifyOptions<C> = {},
|
|
26
|
-
): Promise<VerifyResult<C>> {
|
|
27
|
-
return NativeModule.verifyJwt(token, toNativeJwk(this.jwk), options)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
static async generate(algs: string[]): Promise<ExpoKey> {
|
|
31
|
-
if (algs.includes('ES256')) {
|
|
32
|
-
const jwk = await NativeModule.generatePrivateJwk('ES256')
|
|
33
|
-
return new ExpoKey({ ...jwk, key_ops: ['sign'] })
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
throw TypeError(`No supported algorithm found in: ${algs.join(', ')}`)
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function toNativeJwk(jwk: ExpoJwk): NativeJwk {
|
|
41
|
-
return {
|
|
42
|
-
kty: jwk.kty,
|
|
43
|
-
crv: jwk.crv,
|
|
44
|
-
kid: jwk.kid,
|
|
45
|
-
x: jwk.x,
|
|
46
|
-
y: jwk.y,
|
|
47
|
-
d: jwk.d,
|
|
48
|
-
alg: jwk.alg,
|
|
49
|
-
}
|
|
50
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { Configuration, MMKV } from 'react-native-mmkv'
|
|
2
|
-
import type { SimpleStore, Value } from '@atproto-labs/simple-store'
|
|
3
|
-
import { MMKVSimpleStore, MMKVSimpleStoreOptions } from './mmkv-simple-store.js'
|
|
4
|
-
|
|
5
|
-
export type MMKVSimpleStoreTTLOptions<V extends Value> =
|
|
6
|
-
MMKVSimpleStoreOptions<V> & {
|
|
7
|
-
clearInterval?: null | false | number
|
|
8
|
-
expiresAt: (value: V) => null | number
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* A {@link SimpleStore} implementation based on {@link MMKVSimpleStore} that
|
|
13
|
-
* supports expiring entries after a certain time.
|
|
14
|
-
*/
|
|
15
|
-
export class MMKVSimpleStoreTTL<V extends Value>
|
|
16
|
-
extends MMKVSimpleStore<V>
|
|
17
|
-
implements Disposable, SimpleStore<string, V>
|
|
18
|
-
{
|
|
19
|
-
readonly #store: MMKV
|
|
20
|
-
readonly #expiresAt: (value: V) => null | number
|
|
21
|
-
readonly #clearTimer?: ReturnType<typeof setInterval>
|
|
22
|
-
|
|
23
|
-
constructor({
|
|
24
|
-
clearInterval = 60 * 1e3,
|
|
25
|
-
expiresAt,
|
|
26
|
-
encode,
|
|
27
|
-
decode,
|
|
28
|
-
|
|
29
|
-
...config
|
|
30
|
-
}: MMKVSimpleStoreTTLOptions<V> & Configuration) {
|
|
31
|
-
super({ ...config, encode, decode })
|
|
32
|
-
|
|
33
|
-
this.#store = new MMKV({ ...config, id: `${config.id}.exp` })
|
|
34
|
-
this.#expiresAt = expiresAt
|
|
35
|
-
if (clearInterval) {
|
|
36
|
-
this.#clearTimer = setInterval(() => this.clearExpired(), clearInterval)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
this.clearExpired()
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
[Symbol.dispose]() {
|
|
43
|
-
clearInterval(this.#clearTimer)
|
|
44
|
-
this.clearExpired()
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
override set(key: string, value: V): void {
|
|
48
|
-
super.set(key, value)
|
|
49
|
-
|
|
50
|
-
const expirationDate = this.#expiresAt.call(null, value)
|
|
51
|
-
if (expirationDate == null) this.#store.delete(key)
|
|
52
|
-
else this.#store.set(key, expirationDate)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
override get(key: string): V | undefined {
|
|
56
|
-
if (this.isExpired(key)) {
|
|
57
|
-
this.del(key)
|
|
58
|
-
return undefined
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return super.get(key)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
override del(key: string): void {
|
|
65
|
-
super.del(key)
|
|
66
|
-
this.#store.delete(key)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
override clear(): void {
|
|
70
|
-
super.clear()
|
|
71
|
-
this.#store.clearAll()
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
getExpirationTime(key: string): number | undefined {
|
|
75
|
-
return this.#store.getNumber(key) ?? undefined
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
isExpired(key: string): boolean {
|
|
79
|
-
const expirationTime = this.getExpirationTime(key)
|
|
80
|
-
return expirationTime != null && expirationTime < Date.now()
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
clearExpired() {
|
|
84
|
-
for (const key of this.#store.getAllKeys() ?? []) {
|
|
85
|
-
if (this.isExpired(key)) {
|
|
86
|
-
this.del(key)
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { Configuration, MMKV } from 'react-native-mmkv'
|
|
2
|
-
import type { SimpleStore, Value } from '@atproto-labs/simple-store'
|
|
3
|
-
|
|
4
|
-
export type MMKVSimpleStoreOptions<V extends Value> = {
|
|
5
|
-
decode: (value: string) => V
|
|
6
|
-
encode: (value: V) => string
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* A {@link SimpleStore} implementation using {@link MMKV} for storage.
|
|
11
|
-
*/
|
|
12
|
-
export class MMKVSimpleStore<V extends Value>
|
|
13
|
-
implements SimpleStore<string, V>
|
|
14
|
-
{
|
|
15
|
-
readonly #store: MMKV
|
|
16
|
-
readonly #encode: (value: V) => string
|
|
17
|
-
readonly #decode: (value: string) => V
|
|
18
|
-
|
|
19
|
-
constructor({
|
|
20
|
-
decode,
|
|
21
|
-
encode,
|
|
22
|
-
...config
|
|
23
|
-
}: MMKVSimpleStoreOptions<V> & Configuration) {
|
|
24
|
-
this.#store = new MMKV(config)
|
|
25
|
-
this.#decode = decode
|
|
26
|
-
this.#encode = encode
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
set(key: string, value: V): void {
|
|
30
|
-
const encoded = this.#encode.call(null, value)
|
|
31
|
-
this.#store.set(key, encoded)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
get(key: string): V | undefined {
|
|
35
|
-
const value = this.#store.getString(key)
|
|
36
|
-
if (value === undefined) return undefined
|
|
37
|
-
|
|
38
|
-
return this.#decode.call(null, value)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
del(key: string): void {
|
|
42
|
-
this.#store.delete(key)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
clear() {
|
|
46
|
-
this.#store.clearAll()
|
|
47
|
-
}
|
|
48
|
-
}
|
package/src/utils/stores.ts
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
DidDocument,
|
|
3
|
-
InternalStateData,
|
|
4
|
-
OAuthAuthorizationServerMetadata,
|
|
5
|
-
OAuthProtectedResourceMetadata,
|
|
6
|
-
ResolvedHandle,
|
|
7
|
-
Session,
|
|
8
|
-
} from '@atproto/oauth-client'
|
|
9
|
-
import { ExpoKey } from './expo-key.js'
|
|
10
|
-
import { MMKVSimpleStoreTTL } from './mmkv-simple-store-ttl.js'
|
|
11
|
-
|
|
12
|
-
const MMKV_ID = 'expo-atproto-oauth-client'
|
|
13
|
-
|
|
14
|
-
export class AuthorizationServerMetadataCache extends MMKVSimpleStoreTTL<OAuthAuthorizationServerMetadata> {
|
|
15
|
-
constructor() {
|
|
16
|
-
super({
|
|
17
|
-
id: `${MMKV_ID}.authorizationServerMetadata`,
|
|
18
|
-
expiresAt: oneMinuteFromNow,
|
|
19
|
-
decode: JSON.parse,
|
|
20
|
-
encode: JSON.stringify,
|
|
21
|
-
})
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export class ProtectedResourceMetadataCache extends MMKVSimpleStoreTTL<OAuthProtectedResourceMetadata | null> {
|
|
26
|
-
constructor() {
|
|
27
|
-
super({
|
|
28
|
-
id: `${MMKV_ID}.protectedResourceMetadata`,
|
|
29
|
-
expiresAt: oneMinuteFromNow,
|
|
30
|
-
decode: JSON.parse,
|
|
31
|
-
encode: JSON.stringify,
|
|
32
|
-
})
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export class DpopNonceCache extends MMKVSimpleStoreTTL<string> {
|
|
37
|
-
constructor() {
|
|
38
|
-
super({
|
|
39
|
-
id: `${MMKV_ID}.dpopNonce`,
|
|
40
|
-
expiresAt: tenMinutesFromNow,
|
|
41
|
-
decode: identity,
|
|
42
|
-
encode: identity,
|
|
43
|
-
})
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export class DidCache extends MMKVSimpleStoreTTL<DidDocument> {
|
|
48
|
-
constructor() {
|
|
49
|
-
super({
|
|
50
|
-
id: `${MMKV_ID}.did`,
|
|
51
|
-
expiresAt: oneMinuteFromNow,
|
|
52
|
-
decode: JSON.parse,
|
|
53
|
-
encode: JSON.stringify,
|
|
54
|
-
})
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export class HandleCache extends MMKVSimpleStoreTTL<ResolvedHandle> {
|
|
59
|
-
constructor() {
|
|
60
|
-
super({
|
|
61
|
-
id: `${MMKV_ID}.handle`,
|
|
62
|
-
expiresAt: oneMinuteFromNow,
|
|
63
|
-
decode: JSON.parse,
|
|
64
|
-
encode: JSON.stringify,
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export class StateStore extends MMKVSimpleStoreTTL<InternalStateData> {
|
|
70
|
-
constructor() {
|
|
71
|
-
super({
|
|
72
|
-
id: `${MMKV_ID}.state`,
|
|
73
|
-
expiresAt: tenMinutesFromNow,
|
|
74
|
-
decode: (value) => {
|
|
75
|
-
const parsed = JSON.parse(value)
|
|
76
|
-
return { ...parsed, dpopKey: new ExpoKey(parsed.dpopKey) }
|
|
77
|
-
},
|
|
78
|
-
encode: (value) => {
|
|
79
|
-
return JSON.stringify({ ...value, dpopKey: value.dpopKey.jwk })
|
|
80
|
-
},
|
|
81
|
-
})
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export class SessionStore extends MMKVSimpleStoreTTL<Session> {
|
|
86
|
-
constructor() {
|
|
87
|
-
super({
|
|
88
|
-
id: `${MMKV_ID}.session`,
|
|
89
|
-
expiresAt: ({ tokenSet }) => {
|
|
90
|
-
if (tokenSet.refresh_token) return null
|
|
91
|
-
if (tokenSet.expires_at) return new Date(tokenSet.expires_at).valueOf()
|
|
92
|
-
return null
|
|
93
|
-
},
|
|
94
|
-
decode: (value) => {
|
|
95
|
-
const parsed = JSON.parse(value)
|
|
96
|
-
return { ...parsed, dpopKey: new ExpoKey(parsed.dpopKey) }
|
|
97
|
-
},
|
|
98
|
-
encode: (value) => {
|
|
99
|
-
return JSON.stringify({ ...value, dpopKey: value.dpopKey.jwk })
|
|
100
|
-
},
|
|
101
|
-
})
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function identity<T>(x: T): T {
|
|
106
|
-
return x
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function tenMinutesFromNow() {
|
|
110
|
-
return Date.now() + 10 * 60e3
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function oneMinuteFromNow() {
|
|
114
|
-
return Date.now() + 60e3
|
|
115
|
-
}
|
package/tsconfig.build.json
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":"7.0.0-dev.20260614.1","root":["./src/ExpoAtprotoOAuthClientModule.ts","./src/ExpoAtprotoOAuthClientModule.types.ts","./src/expo-oauth-client-interface.ts","./src/expo-oauth-client-options.ts","./src/expo-oauth-client.d.ts","./src/expo-oauth-client.native.ts","./src/expo-oauth-client.web.ts","./src/index.ts","./src/polyfill.d.ts","./src/polyfill.native.ts","./src/polyfill.web.ts","./src/utils/expo-key.ts","./src/utils/mmkv-simple-store-ttl.ts","./src/utils/mmkv-simple-store.ts","./src/utils/stores.ts"]}
|
package/tsconfig.json
DELETED