-
Notifications
You must be signed in to change notification settings - Fork 132
/
Copy pathAsyncAuthStore.ts
133 lines (110 loc) · 3.45 KB
/
AsyncAuthStore.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import { BaseAuthStore, AuthRecord } from "@/stores/BaseAuthStore";
export type AsyncSaveFunc = (serializedPayload: string) => Promise<void>;
export type AsyncClearFunc = () => Promise<void>;
type queueFunc = () => Promise<void>;
/**
* AsyncAuthStore is a helper auth store implementation
* that could be used with any external async persistent layer
* (key-value db, local file, etc.).
*
* Here is an example with the React Native AsyncStorage package:
*
* ```
* import AsyncStorage from "@react-native-async-storage/async-storage";
* import PocketBase, { AsyncAuthStore } from "pocketbase";
*
* const store = new AsyncAuthStore({
* save: async (serialized) => AsyncStorage.setItem("pb_auth", serialized),
* initial: AsyncStorage.getItem("pb_auth"),
* });
*
* const pb = new PocketBase("https://example.com", store)
* ```
*/
export class AsyncAuthStore extends BaseAuthStore {
private saveFunc: AsyncSaveFunc;
private clearFunc?: AsyncClearFunc;
private queue: Array<queueFunc> = [];
constructor(config: {
// The async function that is called every time
// when the auth store state needs to be persisted.
save: AsyncSaveFunc;
/// An *optional* async function that is called every time
/// when the auth store needs to be cleared.
///
/// If not explicitly set, `saveFunc` with empty data will be used.
clear?: AsyncClearFunc;
// An *optional* initial data to load into the store.
initial?: string | Promise<any>;
}) {
super();
this.saveFunc = config.save;
this.clearFunc = config.clear;
this._enqueue(() => this._loadInitial(config.initial));
}
/**
* @inheritdoc
*/
save(token: string, record?: AuthRecord): void {
super.save(token, record);
let value = "";
try {
value = JSON.stringify({ token, record });
} catch (err) {
console.warn("AsyncAuthStore: failed to stringify the new state");
}
this._enqueue(() => this.saveFunc(value));
}
/**
* @inheritdoc
*/
clear(): void {
super.clear();
if (this.clearFunc) {
this._enqueue(() => this.clearFunc!());
} else {
this._enqueue(() => this.saveFunc(""));
}
}
/**
* Initializes the auth store state.
*/
private async _loadInitial(payload?: string | Promise<any>) {
try {
payload = await payload;
if (payload) {
let parsed;
if (typeof payload === "string") {
parsed = JSON.parse(payload) || {};
} else if (typeof payload === "object") {
parsed = payload;
}
this.save(parsed.token || "", parsed.record || parsed.model || null);
}
} catch (_) {}
}
/**
* Appends an async function to the queue.
*/
private _enqueue(asyncCallback: () => Promise<void>) {
this.queue.push(asyncCallback);
if (this.queue.length == 1) {
this._dequeue();
}
}
/**
* Starts the queue processing.
*/
private _dequeue() {
if (!this.queue.length) {
return;
}
this.queue[0]().finally(() => {
this.queue.shift();
if (!this.queue.length) {
return;
}
this._dequeue();
});
}
}