@flowerforce/flowerbase-client 0.3.0 → 0.3.1-beta.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/dist/app.d.ts CHANGED
@@ -48,6 +48,8 @@ export declare class App {
48
48
  get allUsers(): Readonly<Record<string, User>>;
49
49
  private persistSessionsByUser;
50
50
  private persistUsersOrder;
51
+ private restorePersistedUsers;
52
+ private restoreCurrentSession;
51
53
  private touchUser;
52
54
  private removeUserFromOrder;
53
55
  private setSessionForUser;
package/dist/app.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
package/dist/app.js CHANGED
@@ -19,29 +19,8 @@ class App {
19
19
  this.baseUrl = (config.baseUrl ?? '').replace(/\/$/, '');
20
20
  this.timeout = config.timeout ?? 10000;
21
21
  this.sessionManager = new session_1.SessionManager(this.id);
22
- const persistedSessionsByUser = this.sessionManager.getSessionsByUser();
23
- for (const [userId, session] of Object.entries(persistedSessionsByUser)) {
24
- this.sessionsByUserId.set(userId, session);
25
- }
26
- this.usersOrder = this.sessionManager.getUsersOrder();
27
- for (const userId of this.sessionsByUserId.keys()) {
28
- if (!this.usersOrder.includes(userId)) {
29
- this.usersOrder.push(userId);
30
- }
31
- }
32
- for (const userId of this.usersOrder) {
33
- this.getOrCreateUser(userId);
34
- }
35
- const currentSession = this.sessionManager.get();
36
- if (currentSession?.userId) {
37
- this.sessionsByUserId.set(currentSession.userId, currentSession);
38
- this.getOrCreateUser(currentSession.userId);
39
- this.touchUser(currentSession.userId);
40
- this.persistSessionsByUser();
41
- }
42
- else {
43
- this.setCurrentSessionFromOrder();
44
- }
22
+ this.restorePersistedUsers();
23
+ this.restoreCurrentSession();
45
24
  this.sessionBootstrapPromise = this.bootstrapSessionOnLoad();
46
25
  this.emailPasswordAuth = {
47
26
  registerUser: ({ email, password }) => this.postProvider('/local-userpass/register', { email, password }),
@@ -109,6 +88,39 @@ class App {
109
88
  persistUsersOrder() {
110
89
  this.sessionManager.setUsersOrder(this.usersOrder);
111
90
  }
91
+ restorePersistedUsers() {
92
+ const persistedSessionsByUser = this.sessionManager.getSessionsByUser();
93
+ for (const [userId, session] of Object.entries(persistedSessionsByUser)) {
94
+ this.sessionsByUserId.set(userId, session);
95
+ }
96
+ const persistedOrder = this.sessionManager.getUsersOrder();
97
+ const nextUsersOrder = [];
98
+ for (const userId of persistedOrder) {
99
+ if (!nextUsersOrder.includes(userId)) {
100
+ nextUsersOrder.push(userId);
101
+ }
102
+ }
103
+ for (const userId of this.sessionsByUserId.keys()) {
104
+ if (!nextUsersOrder.includes(userId)) {
105
+ nextUsersOrder.push(userId);
106
+ }
107
+ }
108
+ this.usersOrder = nextUsersOrder;
109
+ for (const userId of this.usersOrder) {
110
+ this.getOrCreateUser(userId);
111
+ }
112
+ }
113
+ restoreCurrentSession() {
114
+ const currentSession = this.sessionManager.get();
115
+ if (currentSession?.userId) {
116
+ this.sessionsByUserId.set(currentSession.userId, currentSession);
117
+ this.getOrCreateUser(currentSession.userId);
118
+ this.touchUser(currentSession.userId);
119
+ this.persistSessionsByUser();
120
+ return;
121
+ }
122
+ this.setCurrentSessionFromOrder();
123
+ }
112
124
  touchUser(userId) {
113
125
  this.usersOrder = [userId, ...this.usersOrder.filter((id) => id !== userId)];
114
126
  this.persistUsersOrder();
@@ -167,8 +179,11 @@ class App {
167
179
  });
168
180
  }
169
181
  async bootstrapSessionOnLoad() {
182
+ await this.sessionManager.whenReady();
183
+ this.restorePersistedUsers();
184
+ this.restoreCurrentSession();
170
185
  const session = this.sessionManager.get();
171
- if (!session || typeof localStorage === 'undefined') {
186
+ if (!session || !this.sessionManager.hasPersistentStorage()) {
172
187
  return;
173
188
  }
174
189
  try {
package/dist/session.d.ts CHANGED
@@ -4,15 +4,22 @@ export declare class SessionManager {
4
4
  private readonly usersKey;
5
5
  private readonly sessionsKey;
6
6
  private readonly storage;
7
+ private readonly hydrationPromise;
7
8
  private session;
9
+ private usersOrder;
10
+ private sessionsByUser;
8
11
  constructor(appId: string);
9
- load(): SessionData | null;
12
+ private hydrate;
13
+ whenReady(): Promise<void>;
14
+ hasPersistentStorage(): boolean;
10
15
  get(): SessionData | null;
11
16
  set(session: SessionData): void;
12
17
  clear(): void;
13
18
  getUsersOrder(): string[];
14
19
  setUsersOrder(order: string[]): void;
15
- getSessionsByUser(): Record<string, SessionData>;
20
+ getSessionsByUser(): {
21
+ [x: string]: SessionData;
22
+ };
16
23
  setSessionsByUser(sessionsByUser: Record<string, SessionData>): void;
17
24
  }
18
25
  //# sourceMappingURL=session.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAwBrC,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,OAAO,CAA2B;gBAE9B,KAAK,EAAE,MAAM;IAOzB,IAAI,IAAI,WAAW,GAAG,IAAI;IAW1B,GAAG;IAIH,GAAG,CAAC,OAAO,EAAE,WAAW;IAKxB,KAAK;IAKL,aAAa;IAYb,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE;IAQ7B,iBAAiB;IAuBjB,iBAAiB,CAAC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;CAO9D"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAgDrC,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;IAC1C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAe;IAChD,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,UAAU,CAAe;IACjC,OAAO,CAAC,cAAc,CAAkC;gBAE5C,KAAK,EAAE,MAAM;YAUX,OAAO;IAOrB,SAAS;IAIT,oBAAoB;IAIpB,GAAG;IAIH,GAAG,CAAC,OAAO,EAAE,WAAW;IAKxB,KAAK;IAKL,aAAa;IAIb,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE;IAS7B,iBAAiB;;;IAIjB,iBAAiB,CAAC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;CAQ9D"}
package/dist/session.js CHANGED
@@ -1,44 +1,76 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SessionManager = void 0;
4
- const memoryStore = new Map();
5
- const getStorage = () => {
6
- if (typeof localStorage !== 'undefined') {
7
- return {
8
- getItem: (key) => localStorage.getItem(key),
9
- setItem: (key, value) => localStorage.setItem(key, value),
10
- removeItem: (key) => localStorage.removeItem(key)
11
- };
12
- }
13
- return {
14
- getItem: (key) => memoryStore.get(key) ?? null,
15
- setItem: (key, value) => {
16
- memoryStore.set(key, value);
17
- },
18
- removeItem: (key) => {
19
- memoryStore.delete(key);
4
+ const storage_1 = require("./storage");
5
+ const parseSession = (raw) => {
6
+ if (!raw)
7
+ return null;
8
+ try {
9
+ return JSON.parse(raw);
10
+ }
11
+ catch {
12
+ return null;
13
+ }
14
+ };
15
+ const parseUsersOrder = (raw) => {
16
+ if (!raw)
17
+ return [];
18
+ try {
19
+ const parsed = JSON.parse(raw);
20
+ if (!Array.isArray(parsed))
21
+ return [];
22
+ return parsed.filter((item) => typeof item === 'string');
23
+ }
24
+ catch {
25
+ return [];
26
+ }
27
+ };
28
+ const parseSessionsByUser = (raw) => {
29
+ if (!raw)
30
+ return {};
31
+ try {
32
+ const parsed = JSON.parse(raw);
33
+ const normalized = {};
34
+ for (const [userId, session] of Object.entries(parsed)) {
35
+ if (session &&
36
+ typeof session === 'object' &&
37
+ typeof session.accessToken === 'string' &&
38
+ typeof session.refreshToken === 'string' &&
39
+ typeof session.userId === 'string') {
40
+ normalized[userId] = session;
41
+ }
20
42
  }
21
- };
43
+ return normalized;
44
+ }
45
+ catch {
46
+ return {};
47
+ }
22
48
  };
23
49
  class SessionManager {
24
50
  constructor(appId) {
25
- this.storage = getStorage();
51
+ this.storage = (0, storage_1.createStorage)();
26
52
  this.session = null;
53
+ this.usersOrder = [];
54
+ this.sessionsByUser = {};
27
55
  this.key = `flowerbase:${appId}:session`;
28
56
  this.usersKey = `flowerbase:${appId}:users`;
29
57
  this.sessionsKey = `flowerbase:${appId}:sessions`;
30
- this.session = this.load();
31
- }
32
- load() {
33
- const raw = this.storage.getItem(this.key);
34
- if (!raw)
35
- return null;
36
- try {
37
- return JSON.parse(raw);
38
- }
39
- catch {
40
- return null;
41
- }
58
+ this.session = parseSession(this.storage.getItem(this.key));
59
+ this.usersOrder = parseUsersOrder(this.storage.getItem(this.usersKey));
60
+ this.sessionsByUser = parseSessionsByUser(this.storage.getItem(this.sessionsKey));
61
+ this.hydrationPromise = this.hydrate();
62
+ }
63
+ async hydrate() {
64
+ const hydrated = await this.storage.hydrate([this.key, this.usersKey, this.sessionsKey]);
65
+ this.session = parseSession(hydrated[this.key] ?? null);
66
+ this.usersOrder = parseUsersOrder(hydrated[this.usersKey] ?? null);
67
+ this.sessionsByUser = parseSessionsByUser(hydrated[this.sessionsKey] ?? null);
68
+ }
69
+ whenReady() {
70
+ return this.hydrationPromise;
71
+ }
72
+ hasPersistentStorage() {
73
+ return this.storage.isPersistent;
42
74
  }
43
75
  get() {
44
76
  return this.session;
@@ -52,20 +84,10 @@ class SessionManager {
52
84
  this.storage.removeItem(this.key);
53
85
  }
54
86
  getUsersOrder() {
55
- const raw = this.storage.getItem(this.usersKey);
56
- if (!raw)
57
- return [];
58
- try {
59
- const parsed = JSON.parse(raw);
60
- if (!Array.isArray(parsed))
61
- return [];
62
- return parsed.filter((item) => typeof item === 'string');
63
- }
64
- catch {
65
- return [];
66
- }
87
+ return [...this.usersOrder];
67
88
  }
68
89
  setUsersOrder(order) {
90
+ this.usersOrder = [...order];
69
91
  if (order.length === 0) {
70
92
  this.storage.removeItem(this.usersKey);
71
93
  return;
@@ -73,28 +95,10 @@ class SessionManager {
73
95
  this.storage.setItem(this.usersKey, JSON.stringify(order));
74
96
  }
75
97
  getSessionsByUser() {
76
- const raw = this.storage.getItem(this.sessionsKey);
77
- if (!raw)
78
- return {};
79
- try {
80
- const parsed = JSON.parse(raw);
81
- const normalized = {};
82
- for (const [userId, session] of Object.entries(parsed)) {
83
- if (session &&
84
- typeof session === 'object' &&
85
- typeof session.accessToken === 'string' &&
86
- typeof session.refreshToken === 'string' &&
87
- typeof session.userId === 'string') {
88
- normalized[userId] = session;
89
- }
90
- }
91
- return normalized;
92
- }
93
- catch {
94
- return {};
95
- }
98
+ return { ...this.sessionsByUser };
96
99
  }
97
100
  setSessionsByUser(sessionsByUser) {
101
+ this.sessionsByUser = { ...sessionsByUser };
98
102
  if (Object.keys(sessionsByUser).length === 0) {
99
103
  this.storage.removeItem(this.sessionsKey);
100
104
  return;
@@ -0,0 +1,11 @@
1
+ type StorageSnapshot = Record<string, string | null>;
2
+ export type PersistedStorage = {
3
+ isPersistent: boolean;
4
+ getItem: (key: string) => string | null;
5
+ setItem: (key: string, value: string) => void;
6
+ removeItem: (key: string) => void;
7
+ hydrate: (keys: string[]) => Promise<StorageSnapshot>;
8
+ };
9
+ export declare const createStorage: () => PersistedStorage;
10
+ export {};
11
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAA;AAEpD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,YAAY,EAAE,OAAO,CAAA;IACrB,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAA;IACvC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7C,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,eAAe,CAAC,CAAA;CACtD,CAAA;AA8BD,eAAO,MAAM,aAAa,QAAO,gBAkBhC,CAAA"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createStorage = void 0;
4
+ const memoryStore = new Map();
5
+ const getStorage = () => {
6
+ const browserStorage = globalThis.localStorage;
7
+ if (browserStorage &&
8
+ typeof browserStorage.getItem === 'function' &&
9
+ typeof browserStorage.setItem === 'function' &&
10
+ typeof browserStorage.removeItem === 'function') {
11
+ return {
12
+ getItem: (key) => browserStorage.getItem(key),
13
+ setItem: (key, value) => browserStorage.setItem(key, value),
14
+ removeItem: (key) => browserStorage.removeItem(key)
15
+ };
16
+ }
17
+ return {
18
+ getItem: (key) => memoryStore.get(key) ?? null,
19
+ setItem: (key, value) => {
20
+ memoryStore.set(key, value);
21
+ },
22
+ removeItem: (key) => {
23
+ memoryStore.delete(key);
24
+ }
25
+ };
26
+ };
27
+ const createStorage = () => {
28
+ const browserStorage = globalThis.localStorage;
29
+ const isPersistent = !!browserStorage &&
30
+ typeof browserStorage.getItem === 'function' &&
31
+ typeof browserStorage.setItem === 'function' &&
32
+ typeof browserStorage.removeItem === 'function';
33
+ const storage = getStorage();
34
+ return {
35
+ isPersistent,
36
+ getItem: storage.getItem,
37
+ setItem: storage.setItem,
38
+ removeItem: storage.removeItem,
39
+ async hydrate(keys) {
40
+ return Object.fromEntries(keys.map((key) => [key, storage.getItem(key)]));
41
+ }
42
+ };
43
+ };
44
+ exports.createStorage = createStorage;
@@ -0,0 +1,11 @@
1
+ type StorageSnapshot = Record<string, string | null>;
2
+ export type PersistedStorage = {
3
+ isPersistent: boolean;
4
+ getItem: (key: string) => string | null;
5
+ setItem: (key: string, value: string) => void;
6
+ removeItem: (key: string) => void;
7
+ hydrate: (keys: string[]) => Promise<StorageSnapshot>;
8
+ };
9
+ export declare const createStorage: () => PersistedStorage;
10
+ export {};
11
+ //# sourceMappingURL=storage.native.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.native.d.ts","sourceRoot":"","sources":["../src/storage.native.ts"],"names":[],"mappings":"AAEA,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAA;AAEpD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,YAAY,EAAE,OAAO,CAAA;IACrB,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAA;IACvC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7C,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,eAAe,CAAC,CAAA;CACtD,CAAA;AAOD,eAAO,MAAM,aAAa,QAAO,gBA+B/B,CAAA"}
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createStorage = void 0;
7
+ const async_storage_1 = __importDefault(require("@react-native-async-storage/async-storage"));
8
+ const memoryStore = new Map();
9
+ const getSnapshot = (keys) => Object.fromEntries(keys.map((key) => [key, memoryStore.get(key) ?? null]));
10
+ const createStorage = () => ({
11
+ isPersistent: true,
12
+ getItem: (key) => memoryStore.get(key) ?? null,
13
+ setItem: (key, value) => {
14
+ memoryStore.set(key, value);
15
+ void async_storage_1.default.setItem(key, value).catch(() => {
16
+ // Ignore write failures and keep the in-memory cache alive.
17
+ });
18
+ },
19
+ removeItem: (key) => {
20
+ memoryStore.delete(key);
21
+ void async_storage_1.default.removeItem(key).catch(() => {
22
+ // Ignore delete failures and keep the in-memory cache alive.
23
+ });
24
+ },
25
+ async hydrate(keys) {
26
+ try {
27
+ const entries = await async_storage_1.default.multiGet(keys);
28
+ for (const [key, value] of entries) {
29
+ if (value === null) {
30
+ memoryStore.delete(key);
31
+ continue;
32
+ }
33
+ memoryStore.set(key, value);
34
+ }
35
+ }
36
+ catch {
37
+ // Ignore storage read failures and keep the in-memory cache alive.
38
+ }
39
+ return getSnapshot(keys);
40
+ }
41
+ });
42
+ exports.createStorage = createStorage;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowerforce/flowerbase-client",
3
- "version": "0.3.0",
3
+ "version": "0.3.1-beta.0",
4
4
  "description": "Client for Flowerbase",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/app.ts CHANGED
@@ -52,29 +52,8 @@ export class App {
52
52
  this.baseUrl = (config.baseUrl ?? '').replace(/\/$/, '')
53
53
  this.timeout = config.timeout ?? 10000
54
54
  this.sessionManager = new SessionManager(this.id)
55
- const persistedSessionsByUser = this.sessionManager.getSessionsByUser()
56
- for (const [userId, session] of Object.entries(persistedSessionsByUser)) {
57
- this.sessionsByUserId.set(userId, session)
58
- }
59
- this.usersOrder = this.sessionManager.getUsersOrder()
60
- for (const userId of this.sessionsByUserId.keys()) {
61
- if (!this.usersOrder.includes(userId)) {
62
- this.usersOrder.push(userId)
63
- }
64
- }
65
- for (const userId of this.usersOrder) {
66
- this.getOrCreateUser(userId)
67
- }
68
-
69
- const currentSession = this.sessionManager.get()
70
- if (currentSession?.userId) {
71
- this.sessionsByUserId.set(currentSession.userId, currentSession)
72
- this.getOrCreateUser(currentSession.userId)
73
- this.touchUser(currentSession.userId)
74
- this.persistSessionsByUser()
75
- } else {
76
- this.setCurrentSessionFromOrder()
77
- }
55
+ this.restorePersistedUsers()
56
+ this.restoreCurrentSession()
78
57
  this.sessionBootstrapPromise = this.bootstrapSessionOnLoad()
79
58
 
80
59
  this.emailPasswordAuth = {
@@ -157,6 +136,44 @@ export class App {
157
136
  this.sessionManager.setUsersOrder(this.usersOrder)
158
137
  }
159
138
 
139
+ private restorePersistedUsers() {
140
+ const persistedSessionsByUser = this.sessionManager.getSessionsByUser()
141
+ for (const [userId, session] of Object.entries(persistedSessionsByUser)) {
142
+ this.sessionsByUserId.set(userId, session)
143
+ }
144
+
145
+ const persistedOrder = this.sessionManager.getUsersOrder()
146
+ const nextUsersOrder: string[] = []
147
+ for (const userId of persistedOrder) {
148
+ if (!nextUsersOrder.includes(userId)) {
149
+ nextUsersOrder.push(userId)
150
+ }
151
+ }
152
+ for (const userId of this.sessionsByUserId.keys()) {
153
+ if (!nextUsersOrder.includes(userId)) {
154
+ nextUsersOrder.push(userId)
155
+ }
156
+ }
157
+ this.usersOrder = nextUsersOrder
158
+
159
+ for (const userId of this.usersOrder) {
160
+ this.getOrCreateUser(userId)
161
+ }
162
+ }
163
+
164
+ private restoreCurrentSession() {
165
+ const currentSession = this.sessionManager.get()
166
+ if (currentSession?.userId) {
167
+ this.sessionsByUserId.set(currentSession.userId, currentSession)
168
+ this.getOrCreateUser(currentSession.userId)
169
+ this.touchUser(currentSession.userId)
170
+ this.persistSessionsByUser()
171
+ return
172
+ }
173
+
174
+ this.setCurrentSessionFromOrder()
175
+ }
176
+
160
177
  private touchUser(userId: string) {
161
178
  this.usersOrder = [userId, ...this.usersOrder.filter((id) => id !== userId)]
162
179
  this.persistUsersOrder()
@@ -225,8 +242,12 @@ export class App {
225
242
  }
226
243
 
227
244
  private async bootstrapSessionOnLoad(): Promise<void> {
245
+ await this.sessionManager.whenReady()
246
+ this.restorePersistedUsers()
247
+ this.restoreCurrentSession()
248
+
228
249
  const session = this.sessionManager.get()
229
- if (!session || typeof localStorage === 'undefined') {
250
+ if (!session || !this.sessionManager.hasPersistentStorage()) {
230
251
  return
231
252
  }
232
253
 
package/src/session.ts CHANGED
@@ -1,24 +1,48 @@
1
1
  import { SessionData } from './types'
2
+ import { createStorage } from './storage'
2
3
 
3
- const memoryStore = new Map<string, string>()
4
+ const parseSession = (raw: string | null): SessionData | null => {
5
+ if (!raw) return null
4
6
 
5
- const getStorage = () => {
6
- if (typeof localStorage !== 'undefined') {
7
- return {
8
- getItem: (key: string) => localStorage.getItem(key),
9
- setItem: (key: string, value: string) => localStorage.setItem(key, value),
10
- removeItem: (key: string) => localStorage.removeItem(key)
11
- }
7
+ try {
8
+ return JSON.parse(raw) as SessionData
9
+ } catch {
10
+ return null
11
+ }
12
+ }
13
+
14
+ const parseUsersOrder = (raw: string | null) => {
15
+ if (!raw) return []
16
+
17
+ try {
18
+ const parsed = JSON.parse(raw)
19
+ if (!Array.isArray(parsed)) return []
20
+ return parsed.filter((item): item is string => typeof item === 'string')
21
+ } catch {
22
+ return []
12
23
  }
24
+ }
13
25
 
14
- return {
15
- getItem: (key: string) => memoryStore.get(key) ?? null,
16
- setItem: (key: string, value: string) => {
17
- memoryStore.set(key, value)
18
- },
19
- removeItem: (key: string) => {
20
- memoryStore.delete(key)
26
+ const parseSessionsByUser = (raw: string | null) => {
27
+ if (!raw) return {} as Record<string, SessionData>
28
+
29
+ try {
30
+ const parsed = JSON.parse(raw) as Record<string, SessionData>
31
+ const normalized: Record<string, SessionData> = {}
32
+ for (const [userId, session] of Object.entries(parsed)) {
33
+ if (
34
+ session &&
35
+ typeof session === 'object' &&
36
+ typeof session.accessToken === 'string' &&
37
+ typeof session.refreshToken === 'string' &&
38
+ typeof session.userId === 'string'
39
+ ) {
40
+ normalized[userId] = session
41
+ }
21
42
  }
43
+ return normalized
44
+ } catch {
45
+ return {} as Record<string, SessionData>
22
46
  }
23
47
  }
24
48
 
@@ -26,25 +50,35 @@ export class SessionManager {
26
50
  private readonly key: string
27
51
  private readonly usersKey: string
28
52
  private readonly sessionsKey: string
29
- private readonly storage = getStorage()
53
+ private readonly storage = createStorage()
54
+ private readonly hydrationPromise: Promise<void>
30
55
  private session: SessionData | null = null
56
+ private usersOrder: string[] = []
57
+ private sessionsByUser: Record<string, SessionData> = {}
31
58
 
32
59
  constructor(appId: string) {
33
60
  this.key = `flowerbase:${appId}:session`
34
61
  this.usersKey = `flowerbase:${appId}:users`
35
62
  this.sessionsKey = `flowerbase:${appId}:sessions`
36
- this.session = this.load()
63
+ this.session = parseSession(this.storage.getItem(this.key))
64
+ this.usersOrder = parseUsersOrder(this.storage.getItem(this.usersKey))
65
+ this.sessionsByUser = parseSessionsByUser(this.storage.getItem(this.sessionsKey))
66
+ this.hydrationPromise = this.hydrate()
37
67
  }
38
68
 
39
- load(): SessionData | null {
40
- const raw = this.storage.getItem(this.key)
41
- if (!raw) return null
69
+ private async hydrate() {
70
+ const hydrated = await this.storage.hydrate([this.key, this.usersKey, this.sessionsKey])
71
+ this.session = parseSession(hydrated[this.key] ?? null)
72
+ this.usersOrder = parseUsersOrder(hydrated[this.usersKey] ?? null)
73
+ this.sessionsByUser = parseSessionsByUser(hydrated[this.sessionsKey] ?? null)
74
+ }
42
75
 
43
- try {
44
- return JSON.parse(raw) as SessionData
45
- } catch {
46
- return null
47
- }
76
+ whenReady() {
77
+ return this.hydrationPromise
78
+ }
79
+
80
+ hasPersistentStorage() {
81
+ return this.storage.isPersistent
48
82
  }
49
83
 
50
84
  get() {
@@ -62,18 +96,11 @@ export class SessionManager {
62
96
  }
63
97
 
64
98
  getUsersOrder() {
65
- const raw = this.storage.getItem(this.usersKey)
66
- if (!raw) return []
67
- try {
68
- const parsed = JSON.parse(raw)
69
- if (!Array.isArray(parsed)) return []
70
- return parsed.filter((item): item is string => typeof item === 'string')
71
- } catch {
72
- return []
73
- }
99
+ return [...this.usersOrder]
74
100
  }
75
101
 
76
102
  setUsersOrder(order: string[]) {
103
+ this.usersOrder = [...order]
77
104
  if (order.length === 0) {
78
105
  this.storage.removeItem(this.usersKey)
79
106
  return
@@ -82,29 +109,11 @@ export class SessionManager {
82
109
  }
83
110
 
84
111
  getSessionsByUser() {
85
- const raw = this.storage.getItem(this.sessionsKey)
86
- if (!raw) return {} as Record<string, SessionData>
87
- try {
88
- const parsed = JSON.parse(raw) as Record<string, SessionData>
89
- const normalized: Record<string, SessionData> = {}
90
- for (const [userId, session] of Object.entries(parsed)) {
91
- if (
92
- session &&
93
- typeof session === 'object' &&
94
- typeof session.accessToken === 'string' &&
95
- typeof session.refreshToken === 'string' &&
96
- typeof session.userId === 'string'
97
- ) {
98
- normalized[userId] = session
99
- }
100
- }
101
- return normalized
102
- } catch {
103
- return {} as Record<string, SessionData>
104
- }
112
+ return { ...this.sessionsByUser }
105
113
  }
106
114
 
107
115
  setSessionsByUser(sessionsByUser: Record<string, SessionData>) {
116
+ this.sessionsByUser = { ...sessionsByUser }
108
117
  if (Object.keys(sessionsByUser).length === 0) {
109
118
  this.storage.removeItem(this.sessionsKey)
110
119
  return
@@ -0,0 +1,49 @@
1
+ import AsyncStorage from '@react-native-async-storage/async-storage'
2
+
3
+ type StorageSnapshot = Record<string, string | null>
4
+
5
+ export type PersistedStorage = {
6
+ isPersistent: boolean
7
+ getItem: (key: string) => string | null
8
+ setItem: (key: string, value: string) => void
9
+ removeItem: (key: string) => void
10
+ hydrate: (keys: string[]) => Promise<StorageSnapshot>
11
+ }
12
+
13
+ const memoryStore = new Map<string, string>()
14
+
15
+ const getSnapshot = (keys: string[]): StorageSnapshot =>
16
+ Object.fromEntries(keys.map((key) => [key, memoryStore.get(key) ?? null]))
17
+
18
+ export const createStorage = (): PersistedStorage => ({
19
+ isPersistent: true,
20
+ getItem: (key) => memoryStore.get(key) ?? null,
21
+ setItem: (key, value) => {
22
+ memoryStore.set(key, value)
23
+ void AsyncStorage.setItem(key, value).catch(() => {
24
+ // Ignore write failures and keep the in-memory cache alive.
25
+ })
26
+ },
27
+ removeItem: (key) => {
28
+ memoryStore.delete(key)
29
+ void AsyncStorage.removeItem(key).catch(() => {
30
+ // Ignore delete failures and keep the in-memory cache alive.
31
+ })
32
+ },
33
+ async hydrate(keys) {
34
+ try {
35
+ const entries = await AsyncStorage.multiGet(keys)
36
+ for (const [key, value] of entries) {
37
+ if (value === null) {
38
+ memoryStore.delete(key)
39
+ continue
40
+ }
41
+ memoryStore.set(key, value)
42
+ }
43
+ } catch {
44
+ // Ignore storage read failures and keep the in-memory cache alive.
45
+ }
46
+
47
+ return getSnapshot(keys)
48
+ }
49
+ })
package/src/storage.ts ADDED
@@ -0,0 +1,57 @@
1
+ type StorageSnapshot = Record<string, string | null>
2
+
3
+ export type PersistedStorage = {
4
+ isPersistent: boolean
5
+ getItem: (key: string) => string | null
6
+ setItem: (key: string, value: string) => void
7
+ removeItem: (key: string) => void
8
+ hydrate: (keys: string[]) => Promise<StorageSnapshot>
9
+ }
10
+
11
+ const memoryStore = new Map<string, string>()
12
+
13
+ const getStorage = () => {
14
+ const browserStorage = globalThis.localStorage
15
+ if (
16
+ browserStorage &&
17
+ typeof browserStorage.getItem === 'function' &&
18
+ typeof browserStorage.setItem === 'function' &&
19
+ typeof browserStorage.removeItem === 'function'
20
+ ) {
21
+ return {
22
+ getItem: (key: string) => browserStorage.getItem(key),
23
+ setItem: (key: string, value: string) => browserStorage.setItem(key, value),
24
+ removeItem: (key: string) => browserStorage.removeItem(key)
25
+ }
26
+ }
27
+
28
+ return {
29
+ getItem: (key: string) => memoryStore.get(key) ?? null,
30
+ setItem: (key: string, value: string) => {
31
+ memoryStore.set(key, value)
32
+ },
33
+ removeItem: (key: string) => {
34
+ memoryStore.delete(key)
35
+ }
36
+ }
37
+ }
38
+
39
+ export const createStorage = (): PersistedStorage => {
40
+ const browserStorage = globalThis.localStorage
41
+ const isPersistent =
42
+ !!browserStorage &&
43
+ typeof browserStorage.getItem === 'function' &&
44
+ typeof browserStorage.setItem === 'function' &&
45
+ typeof browserStorage.removeItem === 'function'
46
+ const storage = getStorage()
47
+
48
+ return {
49
+ isPersistent,
50
+ getItem: storage.getItem,
51
+ setItem: storage.setItem,
52
+ removeItem: storage.removeItem,
53
+ async hydrate(keys) {
54
+ return Object.fromEntries(keys.map((key) => [key, storage.getItem(key)]))
55
+ }
56
+ }
57
+ }
@@ -1,14 +0,0 @@
1
- import { SessionData } from './types';
2
- export declare class SessionManager {
3
- private readonly key;
4
- private session;
5
- private readonly asyncStorage;
6
- private hydrationPromise;
7
- constructor(appId: string);
8
- private hydrateFromAsyncStorage;
9
- load(): SessionData | null;
10
- get(): SessionData | null;
11
- set(session: SessionData): void;
12
- clear(): void;
13
- }
14
- //# sourceMappingURL=session.native.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"session.native.d.ts","sourceRoot":"","sources":["../src/session.native.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAsBrC,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,gBAAgB,CAA6B;gBAEzC,KAAK,EAAE,MAAM;IAMzB,OAAO,CAAC,uBAAuB;IAwB/B,IAAI,IAAI,WAAW,GAAG,IAAI;IAI1B,GAAG;IAIH,GAAG,CAAC,OAAO,EAAE,WAAW;IAYxB,KAAK;CAUN"}
@@ -1,76 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.SessionManager = void 0;
7
- const async_storage_1 = __importDefault(require("@react-native-async-storage/async-storage"));
8
- const memoryStore = new Map();
9
- const getAsyncStorage = () => async_storage_1.default;
10
- const parseSession = (raw) => {
11
- if (!raw)
12
- return null;
13
- try {
14
- return JSON.parse(raw);
15
- }
16
- catch {
17
- return null;
18
- }
19
- };
20
- class SessionManager {
21
- constructor(appId) {
22
- this.session = null;
23
- this.asyncStorage = getAsyncStorage();
24
- this.hydrationPromise = null;
25
- this.key = `flowerbase:${appId}:session`;
26
- this.session = this.load();
27
- void this.hydrateFromAsyncStorage();
28
- }
29
- hydrateFromAsyncStorage() {
30
- if (!this.asyncStorage) {
31
- return Promise.resolve();
32
- }
33
- if (this.hydrationPromise) {
34
- return this.hydrationPromise;
35
- }
36
- this.hydrationPromise = this.asyncStorage
37
- .getItem(this.key)
38
- .then((raw) => {
39
- const parsed = parseSession(raw);
40
- if (!parsed)
41
- return;
42
- this.session = parsed;
43
- memoryStore.set(this.key, JSON.stringify(parsed));
44
- })
45
- .catch(() => {
46
- // Ignore storage read failures and keep memory fallback.
47
- });
48
- return this.hydrationPromise;
49
- }
50
- load() {
51
- return parseSession(memoryStore.get(this.key) ?? null);
52
- }
53
- get() {
54
- return this.session;
55
- }
56
- set(session) {
57
- this.session = session;
58
- const raw = JSON.stringify(session);
59
- memoryStore.set(this.key, raw);
60
- if (this.asyncStorage) {
61
- void this.asyncStorage.setItem(this.key, raw).catch(() => {
62
- // Ignore write failures and keep memory fallback.
63
- });
64
- }
65
- }
66
- clear() {
67
- this.session = null;
68
- memoryStore.delete(this.key);
69
- if (this.asyncStorage) {
70
- void this.asyncStorage.removeItem(this.key).catch(() => {
71
- // Ignore delete failures and keep memory fallback.
72
- });
73
- }
74
- }
75
- }
76
- exports.SessionManager = SessionManager;
@@ -1,89 +0,0 @@
1
- import { SessionData } from './types'
2
- import AsyncStorage from '@react-native-async-storage/async-storage'
3
-
4
- type StorageLike = {
5
- getItem: (key: string) => Promise<string | null>
6
- setItem: (key: string, value: string) => Promise<void>
7
- removeItem: (key: string) => Promise<void>
8
- }
9
-
10
- const memoryStore = new Map<string, string>()
11
-
12
- const getAsyncStorage = (): StorageLike => AsyncStorage
13
-
14
- const parseSession = (raw: string | null): SessionData | null => {
15
- if (!raw) return null
16
- try {
17
- return JSON.parse(raw) as SessionData
18
- } catch {
19
- return null
20
- }
21
- }
22
-
23
- export class SessionManager {
24
- private readonly key: string
25
- private session: SessionData | null = null
26
- private readonly asyncStorage = getAsyncStorage()
27
- private hydrationPromise: Promise<void> | null = null
28
-
29
- constructor(appId: string) {
30
- this.key = `flowerbase:${appId}:session`
31
- this.session = this.load()
32
- void this.hydrateFromAsyncStorage()
33
- }
34
-
35
- private hydrateFromAsyncStorage() {
36
- if (!this.asyncStorage) {
37
- return Promise.resolve()
38
- }
39
-
40
- if (this.hydrationPromise) {
41
- return this.hydrationPromise
42
- }
43
-
44
- this.hydrationPromise = this.asyncStorage
45
- .getItem(this.key)
46
- .then((raw) => {
47
- const parsed = parseSession(raw)
48
- if (!parsed) return
49
- this.session = parsed
50
- memoryStore.set(this.key, JSON.stringify(parsed))
51
- })
52
- .catch(() => {
53
- // Ignore storage read failures and keep memory fallback.
54
- })
55
-
56
- return this.hydrationPromise
57
- }
58
-
59
- load(): SessionData | null {
60
- return parseSession(memoryStore.get(this.key) ?? null)
61
- }
62
-
63
- get() {
64
- return this.session
65
- }
66
-
67
- set(session: SessionData) {
68
- this.session = session
69
- const raw = JSON.stringify(session)
70
- memoryStore.set(this.key, raw)
71
-
72
- if (this.asyncStorage) {
73
- void this.asyncStorage.setItem(this.key, raw).catch(() => {
74
- // Ignore write failures and keep memory fallback.
75
- })
76
- }
77
- }
78
-
79
- clear() {
80
- this.session = null
81
- memoryStore.delete(this.key)
82
-
83
- if (this.asyncStorage) {
84
- void this.asyncStorage.removeItem(this.key).catch(() => {
85
- // Ignore delete failures and keep memory fallback.
86
- })
87
- }
88
- }
89
- }