jazz-react-native 0.8.14 → 0.8.16
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 +471 -455
- package/dist/auth/DemoAuthMethod.js +1 -2
- package/dist/auth/DemoAuthMethod.js.map +1 -1
- package/dist/auth/DemoAuthUI.d.ts +1 -1
- package/dist/auth/DemoAuthUI.js +25 -31
- package/dist/auth/DemoAuthUI.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -5
- package/dist/index.js.map +1 -1
- package/dist/media.d.ts +1 -1
- package/dist/media.js.map +1 -1
- package/dist/provider.js +2 -4
- package/dist/provider.js.map +1 -1
- package/dist/storage/expo-secure-store-adapter.js.map +1 -1
- package/dist/storage/kv-store-context.js.map +1 -1
- package/package.json +7 -11
- package/src/auth/DemoAuthMethod.ts +168 -187
- package/src/auth/DemoAuthUI.tsx +239 -253
- package/src/index.ts +198 -202
- package/src/media.tsx +50 -51
- package/src/provider.tsx +265 -274
- package/src/storage/expo-secure-store-adapter.ts +21 -21
- package/src/storage/kv-store-context.ts +21 -21
- package/tsconfig.json +4 -8
- package/.eslintrc.cjs +0 -24
- package/.prettierrc.js +0 -9
package/src/provider.tsx
CHANGED
@@ -1,307 +1,298 @@
|
|
1
1
|
import React, { useEffect, useState } from "react";
|
2
2
|
|
3
3
|
import {
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
Account,
|
5
|
+
AccountClass,
|
6
|
+
AnonymousJazzAgent,
|
7
|
+
AuthMethod,
|
8
|
+
CoValue,
|
9
|
+
CoValueClass,
|
10
|
+
DeeplyLoaded,
|
11
|
+
DepthsIn,
|
12
|
+
ID,
|
13
|
+
subscribeToCoValue,
|
14
14
|
} from "jazz-tools";
|
15
|
+
import { Linking } from "react-native";
|
15
16
|
import {
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
BrowserContext,
|
18
|
+
BrowserGuestContext,
|
19
|
+
KvStoreContext,
|
20
|
+
createJazzRNContext,
|
21
|
+
parseInviteLink,
|
21
22
|
} from "./index.js";
|
22
|
-
import { Linking } from "react-native";
|
23
23
|
import { ExpoSecureStoreAdapter } from "./storage/expo-secure-store-adapter.js";
|
24
24
|
|
25
25
|
/** @category Context & Hooks */
|
26
26
|
export function createJazzRNApp<Acc extends Account>({
|
27
|
-
|
28
|
-
|
27
|
+
kvStore = new ExpoSecureStoreAdapter(),
|
28
|
+
AccountSchema = Account as unknown as AccountClass<Acc>,
|
29
29
|
} = {}): JazzReactApp<Acc> {
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
30
|
+
const JazzContext = React.createContext<
|
31
|
+
BrowserContext<Acc> | BrowserGuestContext | undefined
|
32
|
+
>(undefined);
|
33
|
+
|
34
|
+
if (!kvStore) {
|
35
|
+
throw new Error("kvStore is required");
|
36
|
+
}
|
37
|
+
|
38
|
+
KvStoreContext.getInstance().initialize(kvStore);
|
39
|
+
|
40
|
+
function Provider({
|
41
|
+
children,
|
42
|
+
auth,
|
43
|
+
peer,
|
44
|
+
storage,
|
45
|
+
}: {
|
46
|
+
children: React.ReactNode;
|
47
|
+
auth: AuthMethod | "guest";
|
48
|
+
peer: `wss://${string}` | `ws://${string}`;
|
49
|
+
storage?: "indexedDB" | "singleTabOPFS";
|
50
|
+
}) {
|
51
|
+
const [ctx, setCtx] = useState<
|
52
|
+
BrowserContext<Acc> | BrowserGuestContext | undefined
|
53
|
+
>();
|
54
|
+
|
55
|
+
const [sessionCount, setSessionCount] = useState(0);
|
56
|
+
|
57
|
+
useEffect(() => {
|
58
|
+
const promiseWithDoneCallback = createJazzRNContext<Acc>(
|
59
|
+
auth === "guest"
|
60
|
+
? {
|
61
|
+
peer,
|
62
|
+
storage,
|
63
|
+
}
|
64
|
+
: {
|
65
|
+
AccountSchema,
|
66
|
+
auth: auth,
|
67
|
+
peer,
|
68
|
+
storage,
|
69
|
+
},
|
70
|
+
).then((context) => {
|
71
|
+
setCtx({
|
72
|
+
...context,
|
73
|
+
logOut: () => {
|
74
|
+
context.logOut();
|
75
|
+
setCtx(undefined);
|
76
|
+
setSessionCount(sessionCount + 1);
|
77
|
+
},
|
78
|
+
});
|
79
|
+
return context.done;
|
80
|
+
});
|
81
|
+
|
82
|
+
return () => {
|
83
|
+
void promiseWithDoneCallback.then((done) => done());
|
84
|
+
};
|
85
|
+
}, [AccountSchema, auth, peer, storage, sessionCount]);
|
86
|
+
|
87
|
+
return (
|
88
|
+
<JazzContext.Provider value={ctx}>{ctx && children}</JazzContext.Provider>
|
89
|
+
);
|
90
|
+
}
|
91
|
+
|
92
|
+
function useAccount(): { me: Acc; logOut: () => void };
|
93
|
+
function useAccount<D extends DepthsIn<Acc>>(
|
94
|
+
depth: D,
|
95
|
+
): { me: DeeplyLoaded<Acc, D> | undefined; logOut: () => void };
|
96
|
+
function useAccount<D extends DepthsIn<Acc>>(
|
97
|
+
depth?: D,
|
98
|
+
): { me: Acc | DeeplyLoaded<Acc, D> | undefined; logOut: () => void } {
|
99
|
+
const context = React.useContext(JazzContext);
|
100
|
+
|
101
|
+
if (!context) {
|
102
|
+
throw new Error("useAccount must be used within a JazzProvider");
|
36
103
|
}
|
37
104
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
auth,
|
43
|
-
peer,
|
44
|
-
storage,
|
45
|
-
}: {
|
46
|
-
children: React.ReactNode;
|
47
|
-
auth: AuthMethod | "guest";
|
48
|
-
peer: `wss://${string}` | `ws://${string}`;
|
49
|
-
storage?: "indexedDB" | "singleTabOPFS";
|
50
|
-
}) {
|
51
|
-
const [ctx, setCtx] = useState<
|
52
|
-
BrowserContext<Acc> | BrowserGuestContext | undefined
|
53
|
-
>();
|
54
|
-
|
55
|
-
const [sessionCount, setSessionCount] = useState(0);
|
56
|
-
|
57
|
-
useEffect(() => {
|
58
|
-
const promiseWithDoneCallback = createJazzRNContext<Acc>(
|
59
|
-
auth === "guest"
|
60
|
-
? {
|
61
|
-
peer,
|
62
|
-
storage,
|
63
|
-
}
|
64
|
-
: {
|
65
|
-
AccountSchema,
|
66
|
-
auth: auth,
|
67
|
-
peer,
|
68
|
-
storage,
|
69
|
-
},
|
70
|
-
).then((context) => {
|
71
|
-
setCtx({
|
72
|
-
...context,
|
73
|
-
logOut: () => {
|
74
|
-
context.logOut();
|
75
|
-
setCtx(undefined);
|
76
|
-
setSessionCount(sessionCount + 1);
|
77
|
-
},
|
78
|
-
});
|
79
|
-
return context.done;
|
80
|
-
});
|
81
|
-
|
82
|
-
return () => {
|
83
|
-
void promiseWithDoneCallback.then((done) => done());
|
84
|
-
};
|
85
|
-
}, [AccountSchema, auth, peer, storage, sessionCount]);
|
86
|
-
|
87
|
-
return (
|
88
|
-
<JazzContext.Provider value={ctx}>
|
89
|
-
{ctx && children}
|
90
|
-
</JazzContext.Provider>
|
91
|
-
);
|
105
|
+
if (!("me" in context)) {
|
106
|
+
throw new Error(
|
107
|
+
"useAccount can't be used in a JazzProvider with auth === 'guest' - consider using useAccountOrGuest()",
|
108
|
+
);
|
92
109
|
}
|
93
110
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
depth?: D,
|
100
|
-
): { me: Acc | DeeplyLoaded<Acc, D> | undefined; logOut: () => void } {
|
101
|
-
const context = React.useContext(JazzContext);
|
102
|
-
|
103
|
-
if (!context) {
|
104
|
-
throw new Error("useAccount must be used within a JazzProvider");
|
105
|
-
}
|
106
|
-
|
107
|
-
if (!("me" in context)) {
|
108
|
-
throw new Error(
|
109
|
-
"useAccount can't be used in a JazzProvider with auth === 'guest' - consider using useAccountOrGuest()",
|
110
|
-
);
|
111
|
-
}
|
111
|
+
const me = useCoState<Acc, D>(
|
112
|
+
context?.me.constructor as CoValueClass<Acc>,
|
113
|
+
context?.me.id,
|
114
|
+
depth,
|
115
|
+
);
|
112
116
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
117
|
+
return {
|
118
|
+
me: depth === undefined ? me || context.me : me,
|
119
|
+
logOut: context.logOut,
|
120
|
+
};
|
121
|
+
}
|
122
|
+
|
123
|
+
function useAccountOrGuest(): { me: Acc | AnonymousJazzAgent };
|
124
|
+
function useAccountOrGuest<D extends DepthsIn<Acc>>(
|
125
|
+
depth: D,
|
126
|
+
): { me: DeeplyLoaded<Acc, D> | undefined | AnonymousJazzAgent };
|
127
|
+
function useAccountOrGuest<D extends DepthsIn<Acc>>(
|
128
|
+
depth?: D,
|
129
|
+
): { me: Acc | DeeplyLoaded<Acc, D> | undefined | AnonymousJazzAgent } {
|
130
|
+
const context = React.useContext(JazzContext);
|
131
|
+
|
132
|
+
if (!context) {
|
133
|
+
throw new Error("useAccountOrGuest must be used within a JazzProvider");
|
123
134
|
}
|
124
135
|
|
125
|
-
|
126
|
-
function useAccountOrGuest<D extends DepthsIn<Acc>>(
|
127
|
-
depth: D,
|
128
|
-
): { me: DeeplyLoaded<Acc, D> | undefined | AnonymousJazzAgent };
|
129
|
-
function useAccountOrGuest<D extends DepthsIn<Acc>>(
|
130
|
-
depth?: D,
|
131
|
-
): { me: Acc | DeeplyLoaded<Acc, D> | undefined | AnonymousJazzAgent } {
|
132
|
-
const context = React.useContext(JazzContext);
|
133
|
-
|
134
|
-
if (!context) {
|
135
|
-
throw new Error(
|
136
|
-
"useAccountOrGuest must be used within a JazzProvider",
|
137
|
-
);
|
138
|
-
}
|
139
|
-
|
140
|
-
const contextMe = "me" in context ? context.me : undefined;
|
136
|
+
const contextMe = "me" in context ? context.me : undefined;
|
141
137
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
138
|
+
const me = useCoState<Acc, D>(
|
139
|
+
contextMe?.constructor as CoValueClass<Acc>,
|
140
|
+
contextMe?.id,
|
141
|
+
depth,
|
142
|
+
);
|
147
143
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
}
|
144
|
+
if ("me" in context) {
|
145
|
+
return {
|
146
|
+
me: depth === undefined ? me || context.me : me,
|
147
|
+
};
|
148
|
+
} else {
|
149
|
+
return { me: context.guest };
|
155
150
|
}
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
useEffect(() => {
|
173
|
-
if (!id) return;
|
174
|
-
|
175
|
-
return subscribeToCoValue(
|
176
|
-
Schema,
|
177
|
-
id,
|
178
|
-
"me" in context ? context.me : context.guest,
|
179
|
-
depth,
|
180
|
-
(value) => {
|
181
|
-
setState({ value });
|
182
|
-
},
|
183
|
-
);
|
184
|
-
}, [Schema, id, context]);
|
185
|
-
|
186
|
-
return state.value;
|
151
|
+
}
|
152
|
+
|
153
|
+
function useCoState<V extends CoValue, D>(
|
154
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
155
|
+
Schema: CoValueClass<V>,
|
156
|
+
id: ID<V> | undefined,
|
157
|
+
depth: D & DepthsIn<V> = [] as D & DepthsIn<V>,
|
158
|
+
): DeeplyLoaded<V, D> | undefined {
|
159
|
+
const [state, setState] = useState<{
|
160
|
+
value: DeeplyLoaded<V, D> | undefined;
|
161
|
+
}>({ value: undefined });
|
162
|
+
const context = React.useContext(JazzContext);
|
163
|
+
|
164
|
+
if (!context) {
|
165
|
+
throw new Error("useCoState must be used within a JazzProvider");
|
187
166
|
}
|
188
167
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
invitedObjectSchema,
|
221
|
-
)
|
222
|
-
.then(() => {
|
223
|
-
onAccept(result.valueID);
|
224
|
-
})
|
225
|
-
.catch((e) => {
|
226
|
-
console.error("Failed to accept invite", e);
|
227
|
-
});
|
228
|
-
}
|
229
|
-
};
|
230
|
-
|
231
|
-
const linkingListener = Linking.addEventListener(
|
232
|
-
"url",
|
233
|
-
handleDeepLink,
|
234
|
-
);
|
235
|
-
|
236
|
-
void Linking.getInitialURL().then((url) => {
|
237
|
-
if (url) handleDeepLink({ url });
|
238
|
-
});
|
168
|
+
useEffect(() => {
|
169
|
+
if (!id) return;
|
170
|
+
|
171
|
+
return subscribeToCoValue(
|
172
|
+
Schema,
|
173
|
+
id,
|
174
|
+
"me" in context ? context.me : context.guest,
|
175
|
+
depth,
|
176
|
+
(value) => {
|
177
|
+
setState({ value });
|
178
|
+
},
|
179
|
+
);
|
180
|
+
}, [Schema, id, context]);
|
181
|
+
|
182
|
+
return state.value;
|
183
|
+
}
|
184
|
+
|
185
|
+
function useAcceptInvite<V extends CoValue>({
|
186
|
+
invitedObjectSchema,
|
187
|
+
onAccept,
|
188
|
+
forValueHint,
|
189
|
+
}: {
|
190
|
+
invitedObjectSchema: CoValueClass<V>;
|
191
|
+
onAccept: (projectID: ID<V>) => void;
|
192
|
+
forValueHint?: string;
|
193
|
+
}): void {
|
194
|
+
const context = React.useContext(JazzContext);
|
195
|
+
|
196
|
+
if (!context) {
|
197
|
+
throw new Error("useAcceptInvite must be used within a JazzProvider");
|
198
|
+
}
|
239
199
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
200
|
+
if (!("me" in context)) {
|
201
|
+
throw new Error(
|
202
|
+
"useAcceptInvite can't be used in a JazzProvider with auth === 'guest'.",
|
203
|
+
);
|
244
204
|
}
|
245
205
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
206
|
+
useEffect(() => {
|
207
|
+
const handleDeepLink = ({ url }: { url: string }) => {
|
208
|
+
const result = parseInviteLink<V>(url);
|
209
|
+
if (result && result.valueHint === forValueHint) {
|
210
|
+
context.me
|
211
|
+
.acceptInvite(
|
212
|
+
result.valueID,
|
213
|
+
result.inviteSecret,
|
214
|
+
invitedObjectSchema,
|
215
|
+
)
|
216
|
+
.then(() => {
|
217
|
+
onAccept(result.valueID);
|
218
|
+
})
|
219
|
+
.catch((e) => {
|
220
|
+
console.error("Failed to accept invite", e);
|
221
|
+
});
|
222
|
+
}
|
223
|
+
};
|
224
|
+
|
225
|
+
const linkingListener = Linking.addEventListener("url", handleDeepLink);
|
226
|
+
|
227
|
+
void Linking.getInitialURL().then((url) => {
|
228
|
+
if (url) handleDeepLink({ url });
|
229
|
+
});
|
230
|
+
|
231
|
+
return () => {
|
232
|
+
linkingListener.remove();
|
233
|
+
};
|
234
|
+
}, [context, onAccept, invitedObjectSchema, forValueHint]);
|
235
|
+
}
|
236
|
+
|
237
|
+
return {
|
238
|
+
Provider,
|
239
|
+
useAccount,
|
240
|
+
useAccountOrGuest,
|
241
|
+
useCoState,
|
242
|
+
useAcceptInvite,
|
243
|
+
};
|
253
244
|
}
|
254
245
|
|
255
246
|
/** @category Context & Hooks */
|
256
247
|
export interface JazzReactApp<Acc extends Account> {
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
248
|
+
/** @category Provider Component */
|
249
|
+
Provider: React.FC<{
|
250
|
+
children: React.ReactNode;
|
251
|
+
auth: AuthMethod | "guest";
|
252
|
+
peer: `wss://${string}` | `ws://${string}`;
|
253
|
+
storage?: "indexedDB" | "singleTabOPFS";
|
254
|
+
}>;
|
255
|
+
|
256
|
+
/** @category Hooks */
|
257
|
+
useAccount(): {
|
258
|
+
me: Acc;
|
259
|
+
logOut: () => void;
|
260
|
+
};
|
261
|
+
/** @category Hooks */
|
262
|
+
useAccount<D extends DepthsIn<Acc>>(
|
263
|
+
depth: D,
|
264
|
+
): {
|
265
|
+
me: DeeplyLoaded<Acc, D> | undefined;
|
266
|
+
logOut: () => void;
|
267
|
+
};
|
268
|
+
|
269
|
+
/** @category Hooks */
|
270
|
+
useAccountOrGuest(): {
|
271
|
+
me: Acc | AnonymousJazzAgent;
|
272
|
+
};
|
273
|
+
useAccountOrGuest<D extends DepthsIn<Acc>>(
|
274
|
+
depth: D,
|
275
|
+
): {
|
276
|
+
me: DeeplyLoaded<Acc, D> | undefined | AnonymousJazzAgent;
|
277
|
+
};
|
278
|
+
/** @category Hooks */
|
279
|
+
useCoState<V extends CoValue, D>(
|
280
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
281
|
+
Schema: { new (...args: any[]): V } & CoValueClass,
|
282
|
+
id: ID<V> | undefined,
|
283
|
+
depth?: D & DepthsIn<V>,
|
284
|
+
): DeeplyLoaded<V, D> | undefined;
|
285
|
+
|
286
|
+
/** @category Hooks */
|
287
|
+
useAcceptInvite<V extends CoValue>({
|
288
|
+
invitedObjectSchema,
|
289
|
+
onAccept,
|
290
|
+
forValueHint,
|
291
|
+
}: {
|
292
|
+
invitedObjectSchema: CoValueClass<V>;
|
293
|
+
onAccept: (projectID: ID<V>) => void;
|
294
|
+
forValueHint?: string;
|
295
|
+
}): void;
|
305
296
|
}
|
306
297
|
|
307
298
|
export * from "./media.js";
|
@@ -2,28 +2,28 @@ import * as SecureStore from "expo-secure-store";
|
|
2
2
|
import type { KvStore } from "./kv-store-context.js";
|
3
3
|
|
4
4
|
export class ExpoSecureStoreAdapter implements KvStore {
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
get(key: string): Promise<string | null> {
|
6
|
+
return SecureStore.getItemAsync(key, {
|
7
|
+
requireAuthentication: SecureStore.canUseBiometricAuthentication(),
|
8
|
+
keychainAccessible: SecureStore.AFTER_FIRST_UNLOCK,
|
9
|
+
});
|
10
|
+
}
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
async set(key: string, value: string): Promise<void> {
|
13
|
+
return SecureStore.setItemAsync(key, value, {
|
14
|
+
requireAuthentication: SecureStore.canUseBiometricAuthentication(),
|
15
|
+
keychainAccessible: SecureStore.AFTER_FIRST_UNLOCK,
|
16
|
+
});
|
17
|
+
}
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
async delete(key: string): Promise<void> {
|
20
|
+
return SecureStore.deleteItemAsync(key, {
|
21
|
+
requireAuthentication: SecureStore.canUseBiometricAuthentication(),
|
22
|
+
keychainAccessible: SecureStore.AFTER_FIRST_UNLOCK,
|
23
|
+
});
|
24
|
+
}
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
async clearAll(): Promise<void> {
|
27
|
+
throw new Error("Not implemented");
|
28
|
+
}
|
29
29
|
}
|
@@ -1,35 +1,35 @@
|
|
1
1
|
export interface KvStore {
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
get(key: string): Promise<string | null>;
|
3
|
+
set(key: string, value: string): Promise<void>;
|
4
|
+
delete(key: string): Promise<void>;
|
5
|
+
clearAll(): Promise<void>;
|
6
6
|
}
|
7
7
|
|
8
8
|
export class KvStoreContext {
|
9
|
-
|
10
|
-
|
9
|
+
private static instance: KvStoreContext;
|
10
|
+
private storageInstance: KvStore | null = null;
|
11
11
|
|
12
|
-
|
12
|
+
private constructor() {}
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
}
|
18
|
-
return KvStoreContext.instance;
|
14
|
+
public static getInstance(): KvStoreContext {
|
15
|
+
if (!KvStoreContext.instance) {
|
16
|
+
KvStoreContext.instance = new KvStoreContext();
|
19
17
|
}
|
18
|
+
return KvStoreContext.instance;
|
19
|
+
}
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
}
|
21
|
+
public initialize(store: KvStore): void {
|
22
|
+
if (!this.storageInstance) {
|
23
|
+
this.storageInstance = store;
|
25
24
|
}
|
25
|
+
}
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
}
|
31
|
-
return this.storageInstance;
|
27
|
+
public getStorage(): KvStore {
|
28
|
+
if (!this.storageInstance) {
|
29
|
+
throw new Error("Storage instance is not initialized.");
|
32
30
|
}
|
31
|
+
return this.storageInstance;
|
32
|
+
}
|
33
33
|
}
|
34
34
|
|
35
35
|
export default KvStoreContext;
|