@nditure/gania 0.0.0 → 0.0.2
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/index.cjs +28 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +28 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -28,17 +28,21 @@ module.exports = __toCommonJS(index_exports);
|
|
|
28
28
|
|
|
29
29
|
// src/cache/gania-cache.ts
|
|
30
30
|
var GaniaCache = class {
|
|
31
|
-
constructor(dbName, version = 1) {
|
|
32
|
-
this.dbName = dbName;
|
|
33
|
-
this.version = version;
|
|
34
|
-
}
|
|
35
|
-
dbName;
|
|
36
|
-
version;
|
|
37
31
|
db = null;
|
|
32
|
+
storeNames = [
|
|
33
|
+
"responses",
|
|
34
|
+
"mutations"
|
|
35
|
+
];
|
|
36
|
+
DB_NAME = "ganiadb";
|
|
37
|
+
VERSION = 1;
|
|
38
38
|
ramCache = /* @__PURE__ */ new Map();
|
|
39
39
|
hydratedStores = /* @__PURE__ */ new Set();
|
|
40
40
|
activeHydrations = /* @__PURE__ */ new Map();
|
|
41
41
|
channel = null;
|
|
42
|
+
ready;
|
|
43
|
+
constructor() {
|
|
44
|
+
this.ready = this.#init();
|
|
45
|
+
}
|
|
42
46
|
getDatabase() {
|
|
43
47
|
if (!this.db) {
|
|
44
48
|
throw new Error("GaniaCache has not been initialized.");
|
|
@@ -52,12 +56,12 @@ var GaniaCache = class {
|
|
|
52
56
|
}
|
|
53
57
|
return map;
|
|
54
58
|
}
|
|
55
|
-
async init(
|
|
59
|
+
async #init() {
|
|
56
60
|
return new Promise((resolve, reject) => {
|
|
57
|
-
const request = indexedDB.open(this.
|
|
61
|
+
const request = indexedDB.open(this.DB_NAME, this.VERSION);
|
|
58
62
|
request.onupgradeneeded = () => {
|
|
59
63
|
const db = request.result;
|
|
60
|
-
for (const storeName of storeNames) {
|
|
64
|
+
for (const storeName of this.storeNames) {
|
|
61
65
|
if (!db.objectStoreNames.contains(storeName)) {
|
|
62
66
|
db.createObjectStore(storeName);
|
|
63
67
|
}
|
|
@@ -65,10 +69,10 @@ var GaniaCache = class {
|
|
|
65
69
|
};
|
|
66
70
|
request.onsuccess = () => {
|
|
67
71
|
this.db = request.result;
|
|
68
|
-
for (const storeName of storeNames) {
|
|
72
|
+
for (const storeName of this.storeNames) {
|
|
69
73
|
this.ramCache.set(storeName, /* @__PURE__ */ new Map());
|
|
70
74
|
}
|
|
71
|
-
this.channel = new BroadcastChannel(`gania-cache:${this.
|
|
75
|
+
this.channel = new BroadcastChannel(`gania-cache:${this.DB_NAME}`);
|
|
72
76
|
this.channel.onmessage = (event) => this.handleBroadcast(event.data);
|
|
73
77
|
resolve(this);
|
|
74
78
|
};
|
|
@@ -135,6 +139,7 @@ var GaniaCache = class {
|
|
|
135
139
|
}
|
|
136
140
|
}
|
|
137
141
|
async get(store, key) {
|
|
142
|
+
await this.ready;
|
|
138
143
|
const storeMap = this.getStoreMap(store);
|
|
139
144
|
if (storeMap.has(key)) {
|
|
140
145
|
return storeMap.get(key) ?? null;
|
|
@@ -154,6 +159,7 @@ var GaniaCache = class {
|
|
|
154
159
|
});
|
|
155
160
|
}
|
|
156
161
|
async set(store, key, value) {
|
|
162
|
+
await this.ready;
|
|
157
163
|
const storeMap = this.getStoreMap(store);
|
|
158
164
|
storeMap.set(key, value);
|
|
159
165
|
const db = this.getDatabase();
|
|
@@ -171,6 +177,7 @@ var GaniaCache = class {
|
|
|
171
177
|
});
|
|
172
178
|
}
|
|
173
179
|
async delete(store, key) {
|
|
180
|
+
await this.ready;
|
|
174
181
|
this.getStoreMap(store).delete(key);
|
|
175
182
|
const db = this.getDatabase();
|
|
176
183
|
await new Promise((resolve, reject) => {
|
|
@@ -186,6 +193,7 @@ var GaniaCache = class {
|
|
|
186
193
|
});
|
|
187
194
|
}
|
|
188
195
|
async clear(store) {
|
|
196
|
+
await this.ready;
|
|
189
197
|
this.getStoreMap(store).clear();
|
|
190
198
|
const db = this.getDatabase();
|
|
191
199
|
await new Promise((resolve, reject) => {
|
|
@@ -200,16 +208,20 @@ var GaniaCache = class {
|
|
|
200
208
|
});
|
|
201
209
|
}
|
|
202
210
|
async keys(store) {
|
|
211
|
+
await this.ready;
|
|
203
212
|
await this.hydrateStore(store);
|
|
204
213
|
return Array.from(this.getStoreMap(store).keys());
|
|
205
214
|
}
|
|
206
215
|
async entries(store) {
|
|
216
|
+
await this.ready;
|
|
207
217
|
await this.hydrateStore(store);
|
|
208
218
|
return Array.from(this.getStoreMap(store).entries());
|
|
209
219
|
}
|
|
210
|
-
destroy() {
|
|
220
|
+
async destroy() {
|
|
211
221
|
this.channel?.close();
|
|
222
|
+
this.db?.close();
|
|
212
223
|
this.channel = null;
|
|
224
|
+
this.db = null;
|
|
213
225
|
}
|
|
214
226
|
};
|
|
215
227
|
|
|
@@ -248,17 +260,18 @@ async function getResponseData(response, dataType = "json") {
|
|
|
248
260
|
|
|
249
261
|
// src/gania.ts
|
|
250
262
|
var Gania = class {
|
|
251
|
-
online;
|
|
252
263
|
baseUrl;
|
|
253
264
|
/**
|
|
254
265
|
* The *`gdb`* is the indexedDB abstracted storage for the Gania data
|
|
255
266
|
*/
|
|
256
267
|
gdb;
|
|
257
268
|
constructor(options) {
|
|
258
|
-
this.
|
|
259
|
-
this.gdb = new GaniaCache("ganiadb");
|
|
269
|
+
this.gdb = new GaniaCache();
|
|
260
270
|
this.baseUrl = options?.baseUrl;
|
|
261
271
|
}
|
|
272
|
+
get online() {
|
|
273
|
+
return navigator.onLine;
|
|
274
|
+
}
|
|
262
275
|
async request({
|
|
263
276
|
method,
|
|
264
277
|
input,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/cache/gania-cache.ts","../src/response.ts","../src/gania.ts","../src/create.ts"],"sourcesContent":["import { create } from \"./create\";\r\n\r\nconst gania = create();\r\n\r\nexport default gania\r\n\r\nexport { default as Gania } from \"./gania\";\r\nexport { create };\r\nexport * from \"./types\"\r\n","type CacheEvent =\r\n | {\r\n type: \"set\";\r\n store: string;\r\n key: IDBValidKey;\r\n value: unknown;\r\n }\r\n | {\r\n type: \"delete\";\r\n store: string;\r\n key: IDBValidKey;\r\n }\r\n | {\r\n type: \"clear\";\r\n store: string;\r\n };\r\n\r\ntype StoreDef<K = unknown, V = unknown> = {\r\n key: K;\r\n value: V;\r\n};\r\nexport type CacheSchema<T> = { [K in keyof T]: StoreDef };\r\n\r\nexport class GaniaCache<Schema extends CacheSchema<Schema>> {\r\n private db: IDBDatabase | null = null;\r\n\r\n private readonly ramCache = new Map<keyof Schema, Map<unknown, unknown>>();\r\n\r\n private readonly hydratedStores = new Set<keyof Schema>();\r\n\r\n private readonly activeHydrations = new Map<keyof Schema, Promise<void>>();\r\n\r\n private channel: BroadcastChannel | null = null;\r\n\r\n constructor(\r\n private readonly dbName: string,\r\n private readonly version = 1,\r\n ) {}\r\n\r\n private getDatabase(): IDBDatabase {\r\n if (!this.db) {\r\n throw new Error(\"GaniaCache has not been initialized.\");\r\n }\r\n\r\n return this.db;\r\n }\r\n\r\n private getStoreMap<K extends keyof Schema>(\r\n store: K,\r\n ): Map<Schema[K][\"key\"], Schema[K][\"value\"]> {\r\n const map = this.ramCache.get(store);\r\n\r\n if (!map) {\r\n throw new Error(`Store \"${String(store)}\" is not initialized.`);\r\n }\r\n\r\n return map as Map<Schema[K][\"key\"], Schema[K][\"value\"]>;\r\n }\r\n\r\n async init(storeNames: (keyof Schema & string)[]): Promise<this> {\r\n return new Promise((resolve, reject) => {\r\n const request = indexedDB.open(this.dbName, this.version);\r\n\r\n request.onupgradeneeded = () => {\r\n const db = request.result;\r\n\r\n for (const storeName of storeNames) {\r\n if (!db.objectStoreNames.contains(storeName)) {\r\n db.createObjectStore(storeName);\r\n }\r\n }\r\n };\r\n\r\n request.onsuccess = () => {\r\n this.db = request.result;\r\n\r\n for (const storeName of storeNames) {\r\n this.ramCache.set(storeName, new Map());\r\n }\r\n\r\n this.channel = new BroadcastChannel(`gania-cache:${this.dbName}`);\r\n\r\n this.channel.onmessage = (event) => this.handleBroadcast(event.data);\r\n\r\n resolve(this);\r\n };\r\n\r\n request.onerror = () => reject(request.error);\r\n });\r\n }\r\n\r\n private handleBroadcast(event: CacheEvent) {\r\n const storeMap = this.ramCache.get(event.store as keyof Schema);\r\n\r\n if (!storeMap) return;\r\n\r\n switch (event.type) {\r\n case \"set\":\r\n storeMap.set(event.key, event.value);\r\n break;\r\n\r\n case \"delete\":\r\n storeMap.delete(event.key);\r\n break;\r\n\r\n case \"clear\":\r\n storeMap.clear();\r\n break;\r\n }\r\n }\r\n\r\n private broadcast(event: CacheEvent) {\r\n this.channel?.postMessage(event);\r\n }\r\n private async performHydration<K extends keyof Schema>(\r\n store: K,\r\n ): Promise<void> {\r\n const db = this.getDatabase();\r\n\r\n const tx = db.transaction(store as string, \"readonly\");\r\n\r\n const objectStore = tx.objectStore(store as string);\r\n\r\n const [keys, values] = await Promise.all([\r\n new Promise<IDBValidKey[]>((resolve, reject) => {\r\n const req = objectStore.getAllKeys();\r\n\r\n req.onsuccess = () => resolve(req.result as IDBValidKey[]);\r\n\r\n req.onerror = () => reject(req.error);\r\n }),\r\n\r\n new Promise<unknown[]>((resolve, reject) => {\r\n const req = objectStore.getAll();\r\n\r\n req.onsuccess = () => resolve(req.result);\r\n\r\n req.onerror = () => reject(req.error);\r\n }),\r\n ]);\r\n\r\n const storeMap = this.getStoreMap(store);\r\n\r\n keys.forEach((key, index) => {\r\n storeMap.set(\r\n key as Schema[K][\"key\"],\r\n values[index] as Schema[K][\"value\"],\r\n );\r\n });\r\n\r\n this.hydratedStores.add(store);\r\n }\r\n private async hydrateStore<K extends keyof Schema>(store: K): Promise<void> {\r\n // Already hydrated\r\n if (this.hydratedStores.has(store)) {\r\n return;\r\n }\r\n\r\n // Hydration currently in progress\r\n const activeHydration = this.activeHydrations.get(store);\r\n\r\n if (activeHydration) {\r\n return activeHydration;\r\n }\r\n\r\n const hydrationPromise = this.performHydration(store);\r\n\r\n this.activeHydrations.set(store, hydrationPromise);\r\n\r\n try {\r\n await hydrationPromise;\r\n } finally {\r\n this.activeHydrations.delete(store);\r\n }\r\n }\r\n\r\n async get<K extends keyof Schema>(\r\n store: K,\r\n key: Schema[K][\"key\"],\r\n ): Promise<Schema[K][\"value\"] | null> {\r\n const storeMap = this.getStoreMap(store);\r\n\r\n if (storeMap.has(key)) {\r\n return storeMap.get(key) ?? null;\r\n }\r\n\r\n const db = this.getDatabase();\r\n\r\n return new Promise((resolve) => {\r\n const tx = db.transaction(store as string, \"readonly\");\r\n\r\n const request = tx.objectStore(store as string).get(key as IDBValidKey);\r\n\r\n request.onsuccess = () => {\r\n const value = request.result ?? null;\r\n\r\n if (value !== null) {\r\n storeMap.set(key, value);\r\n }\r\n\r\n resolve(value as Schema[K][\"value\"] | null);\r\n };\r\n\r\n request.onerror = () => resolve(null);\r\n });\r\n }\r\n\r\n async set<K extends keyof Schema>(\r\n store: K,\r\n key: Schema[K][\"key\"],\r\n value: Schema[K][\"value\"],\r\n ): Promise<void> {\r\n const storeMap = this.getStoreMap(store);\r\n\r\n storeMap.set(key, value);\r\n\r\n const db = this.getDatabase();\r\n\r\n await new Promise<void>((resolve, reject) => {\r\n const tx = db.transaction(store as string, \"readwrite\");\r\n\r\n const request = tx\r\n .objectStore(store as string)\r\n .put(value, key as IDBValidKey);\r\n\r\n request.onsuccess = () => resolve();\r\n\r\n request.onerror = () => reject(request.error);\r\n });\r\n\r\n this.broadcast({\r\n type: \"set\",\r\n store: String(store),\r\n key: key as IDBValidKey,\r\n value,\r\n });\r\n }\r\n\r\n async delete<K extends keyof Schema>(\r\n store: K,\r\n key: Schema[K][\"key\"],\r\n ): Promise<void> {\r\n this.getStoreMap(store).delete(key);\r\n\r\n const db = this.getDatabase();\r\n\r\n await new Promise<void>((resolve, reject) => {\r\n const tx = db.transaction(store as string, \"readwrite\");\r\n\r\n const request = tx\r\n .objectStore(store as string)\r\n .delete(key as IDBValidKey);\r\n\r\n request.onsuccess = () => resolve();\r\n\r\n request.onerror = () => reject(request.error);\r\n });\r\n\r\n this.broadcast({\r\n type: \"delete\",\r\n store: String(store),\r\n key: key as IDBValidKey,\r\n });\r\n }\r\n\r\n async clear<K extends keyof Schema>(store: K): Promise<void> {\r\n this.getStoreMap(store).clear();\r\n\r\n const db = this.getDatabase();\r\n\r\n await new Promise<void>((resolve, reject) => {\r\n const tx = db.transaction(store as string, \"readwrite\");\r\n\r\n const request = tx.objectStore(store as string).clear();\r\n\r\n request.onsuccess = () => resolve();\r\n\r\n request.onerror = () => reject(request.error);\r\n });\r\n\r\n this.broadcast({\r\n type: \"clear\",\r\n store: String(store),\r\n });\r\n }\r\n\r\n async keys<K extends keyof Schema>(store: K): Promise<Schema[K][\"key\"][]> {\r\n await this.hydrateStore(store);\r\n\r\n return Array.from(this.getStoreMap(store).keys());\r\n }\r\n\r\n async entries<K extends keyof Schema>(\r\n store: K,\r\n ): Promise<[Schema[K][\"key\"], Schema[K][\"value\"]][]> {\r\n await this.hydrateStore(store);\r\n\r\n return Array.from(this.getStoreMap(store).entries());\r\n }\r\n\r\n destroy() {\r\n this.channel?.close();\r\n this.channel = null;\r\n }\r\n}\r\n","import { GaniaResponse, ResponseDataType } from \"./types\";\r\n\r\nexport class GaniaError<T = any> extends Error {\r\n response?: GaniaResponse<T>;\r\n\r\n constructor(message: string, response?: GaniaResponse<T>) {\r\n super(message);\r\n this.name = \"GaniaError\";\r\n this.response = response;\r\n }\r\n}\r\n\r\nexport async function getResponseData<T = any>(\r\n response: Response,\r\n dataType: ResponseDataType = \"json\",\r\n): Promise<{ data: T; dataType: ResponseDataType }> {\r\n // Handle explicit types safely without unsafe dynamic property lookups\r\n if (dataType !== \"flexible\") {\r\n let data: any;\r\n if (dataType === \"json\") data = await response.json();\r\n else if (dataType === \"text\") data = await response.text();\r\n else if (dataType === \"blob\") data = await response.blob();\r\n else if (dataType === \"bytes\") {\r\n const buffer = await response.arrayBuffer();\r\n data = new Uint8Array(buffer);\r\n }\r\n return { data, dataType };\r\n }\r\n\r\n // Handle the 'flexible' inferred fallback chain correctly\r\n try {\r\n const data = await response.json();\r\n return { data, dataType: \"json\" };\r\n } catch {\r\n try {\r\n const data = await response.text() as T;\r\n return { data, dataType: \"text\" };\r\n } catch {\r\n try {\r\n const data = await response.blob() as T;\r\n return { data, dataType: \"blob\" };\r\n } catch {\r\n const buffer = await response.arrayBuffer();\r\n const data = new Uint8Array(buffer) as T;\r\n return { data, dataType: \"bytes\" };\r\n }\r\n }\r\n }\r\n}\r\n","import { GaniaCache } from \"./cache/gania-cache\";\r\nimport { getResponseData } from \"./response\";\r\nimport {\r\n BaseUrl,\r\n CreateGaniaOptions,\r\n GaniaDbSchema,\r\n GaniaRequestConfig,\r\n GaniaRequestInit,\r\n GaniaResponse,\r\n} from \"./types\";\r\n\r\nexport default class Gania {\r\n readonly online: boolean;\r\n public baseUrl?: BaseUrl;\r\n /**\r\n * The *`gdb`* is the indexedDB abstracted storage for the Gania data\r\n */\r\n private readonly gdb: GaniaCache<GaniaDbSchema>;\r\n constructor(options?: CreateGaniaOptions) {\r\n this.online = navigator.onLine;\r\n this.gdb = new GaniaCache<GaniaDbSchema>(\"ganiadb\");\r\n this.baseUrl = options?.baseUrl;\r\n }\r\n async request<T = unknown>({\r\n method,\r\n input,\r\n ...init\r\n }: GaniaRequestConfig): Promise<GaniaResponse<T>> {\r\n if (!this.online) {\r\n if (method === \"GET\") {\r\n const cached = await this.gdb.get(\r\n \"responses\",\r\n this.createCacheKey(method, input),\r\n );\r\n\r\n return {\r\n data: cached?.data as T,\r\n } as GaniaResponse<T>;\r\n }\r\n\r\n await this.gdb.set(\"mutations\", this.createCacheKey(method!, input), {\r\n method: method!,\r\n url: String(input),\r\n body: init.body,\r\n timestamp: Date.now(),\r\n });\r\n\r\n return {\r\n queued: true,\r\n } as GaniaResponse<T>;\r\n }\r\n if (typeof input === \"string\") input = `${this.baseUrl || \"\"}${input}`;\r\n else input;\r\n const response = await fetch(input, {\r\n ...init,\r\n method,\r\n });\r\n const { data, dataType } = await getResponseData<T>(\r\n response,\r\n init.dataType ?? \"flexible\",\r\n );\r\n if (method === \"GET\") {\r\n await this.gdb.set(\"responses\", this.createCacheKey(method, input), {\r\n data,\r\n timestamp: Date.now(),\r\n });\r\n }\r\n return {\r\n data,\r\n status: response.status,\r\n statusText: response.statusText,\r\n headers: response.headers,\r\n ok: response.ok,\r\n dataType,\r\n };\r\n }\r\n createCacheKey(method: string, input: string | URL | Request): string {\r\n return `${method.trim().toUpperCase()}:${String(input)}`;\r\n }\r\n async get<T = any>(input: (string | Request) | URL, init?: GaniaRequestInit) {\r\n return this.request<T>({ method: \"GET\", input, ...init });\r\n }\r\n async post<T = unknown>(\r\n input: string | URL | Request,\r\n body?: BodyInit,\r\n init?: GaniaRequestInit,\r\n ) {\r\n return this.request<T>({\r\n input,\r\n method: \"POST\",\r\n body,\r\n ...init,\r\n });\r\n }\r\n async put<T = unknown>(\r\n input: string | URL | Request,\r\n body?: BodyInit,\r\n init?: GaniaRequestInit,\r\n ) {\r\n return this.request<T>({\r\n input,\r\n method: \"PUT\",\r\n body,\r\n ...init,\r\n });\r\n }\r\n async patch<T = unknown>(\r\n input: string | URL | Request,\r\n body?: BodyInit,\r\n init?: GaniaRequestInit,\r\n ) {\r\n return this.request<T>({\r\n input,\r\n method: \"PATCH\",\r\n body,\r\n ...init,\r\n });\r\n }\r\n async delete<T = unknown>(\r\n input: string | URL | Request,\r\n init?: GaniaRequestInit,\r\n ) {\r\n return this.request<T>({\r\n input,\r\n method: \"DELETE\",\r\n ...init,\r\n });\r\n }\r\n}\r\n","import Gania from \"./gania\";\r\nimport { CreateGaniaOptions, GaniaInstance, GaniaRequestConfig } from \"./types\";\r\n\r\nexport function create(options?: CreateGaniaOptions): GaniaInstance {\r\n const context = new Gania(options);\r\n\r\n const instance = Object.assign(\r\n <T = unknown>(config: GaniaRequestConfig) => context.request<T>(config),\r\n\r\n {\r\n request: context.request.bind(context),\r\n get: context.get.bind(context),\r\n post: context.post.bind(context),\r\n put: context.put.bind(context),\r\n patch: context.patch.bind(context),\r\n delete: context.delete.bind(context),\r\n create,\r\n },\r\n ) as GaniaInstance;\r\n\r\n return instance;\r\n}"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/cache/gania-cache.ts","../src/response.ts","../src/gania.ts","../src/create.ts"],"sourcesContent":["import { create } from \"./create\";\r\n\r\nconst gania = create();\r\n\r\nexport default gania\r\n\r\nexport { default as Gania } from \"./gania\";\r\nexport { create };\r\nexport * from \"./types\"\r\n","import { GaniaDbSchema } from \"../types\";\r\n\r\ntype CacheEvent =\r\n | {\r\n type: \"set\";\r\n store: string;\r\n key: IDBValidKey;\r\n value: unknown;\r\n }\r\n | {\r\n type: \"delete\";\r\n store: string;\r\n key: IDBValidKey;\r\n }\r\n | {\r\n type: \"clear\";\r\n store: string;\r\n };\r\n\r\nexport class GaniaCache {\r\n private db: IDBDatabase | null = null;\r\n private readonly storeNames = [\r\n \"responses\",\r\n \"mutations\",\r\n ] as const satisfies (keyof GaniaDbSchema)[];\r\n\r\n private readonly DB_NAME = \"ganiadb\";\r\n private readonly VERSION = 1;\r\n\r\n private readonly ramCache = new Map<\r\n keyof GaniaDbSchema,\r\n Map<unknown, unknown>\r\n >();\r\n\r\n private readonly hydratedStores = new Set<keyof GaniaDbSchema>();\r\n\r\n private readonly activeHydrations = new Map<\r\n keyof GaniaDbSchema,\r\n Promise<void>\r\n >();\r\n\r\n private channel: BroadcastChannel | null = null;\r\n\r\n private readonly ready: Promise<this>;\r\n\r\n constructor() {\r\n this.ready = this.#init();\r\n }\r\n\r\n private getDatabase(): IDBDatabase {\r\n if (!this.db) {\r\n throw new Error(\"GaniaCache has not been initialized.\");\r\n }\r\n\r\n return this.db;\r\n }\r\n\r\n private getStoreMap<K extends keyof GaniaDbSchema>(\r\n store: K,\r\n ): Map<GaniaDbSchema[K][\"key\"], GaniaDbSchema[K][\"value\"]> {\r\n const map = this.ramCache.get(store);\r\n\r\n if (!map) {\r\n throw new Error(`Store \"${String(store)}\" is not initialized.`);\r\n }\r\n\r\n return map as Map<GaniaDbSchema[K][\"key\"], GaniaDbSchema[K][\"value\"]>;\r\n }\r\n\r\n async #init(): Promise<this> {\r\n return new Promise((resolve, reject) => {\r\n const request = indexedDB.open(this.DB_NAME, this.VERSION);\r\n\r\n request.onupgradeneeded = () => {\r\n const db = request.result;\r\n\r\n for (const storeName of this.storeNames) {\r\n if (!db.objectStoreNames.contains(storeName as string)) {\r\n db.createObjectStore(storeName as string);\r\n }\r\n }\r\n };\r\n\r\n request.onsuccess = () => {\r\n this.db = request.result;\r\n\r\n for (const storeName of this.storeNames) {\r\n this.ramCache.set(storeName, new Map());\r\n }\r\n\r\n this.channel = new BroadcastChannel(`gania-cache:${this.DB_NAME}`);\r\n\r\n this.channel.onmessage = (event) => this.handleBroadcast(event.data);\r\n\r\n resolve(this);\r\n };\r\n\r\n request.onerror = () => reject(request.error);\r\n });\r\n }\r\n\r\n private handleBroadcast(event: CacheEvent) {\r\n const storeMap = this.ramCache.get(event.store as keyof GaniaDbSchema);\r\n\r\n if (!storeMap) return;\r\n\r\n switch (event.type) {\r\n case \"set\":\r\n storeMap.set(event.key, event.value);\r\n break;\r\n\r\n case \"delete\":\r\n storeMap.delete(event.key);\r\n break;\r\n\r\n case \"clear\":\r\n storeMap.clear();\r\n break;\r\n }\r\n }\r\n\r\n private broadcast(event: CacheEvent) {\r\n this.channel?.postMessage(event);\r\n }\r\n private async performHydration<K extends keyof GaniaDbSchema>(\r\n store: K,\r\n ): Promise<void> {\r\n const db = this.getDatabase();\r\n\r\n const tx = db.transaction(store as string, \"readonly\");\r\n\r\n const objectStore = tx.objectStore(store as string);\r\n\r\n const [keys, values] = await Promise.all([\r\n new Promise<IDBValidKey[]>((resolve, reject) => {\r\n const req = objectStore.getAllKeys();\r\n\r\n req.onsuccess = () => resolve(req.result as IDBValidKey[]);\r\n\r\n req.onerror = () => reject(req.error);\r\n }),\r\n\r\n new Promise<unknown[]>((resolve, reject) => {\r\n const req = objectStore.getAll();\r\n\r\n req.onsuccess = () => resolve(req.result);\r\n\r\n req.onerror = () => reject(req.error);\r\n }),\r\n ]);\r\n\r\n const storeMap = this.getStoreMap(store);\r\n\r\n keys.forEach((key, index) => {\r\n storeMap.set(\r\n key as GaniaDbSchema[K][\"key\"],\r\n values[index] as GaniaDbSchema[K][\"value\"],\r\n );\r\n });\r\n\r\n this.hydratedStores.add(store);\r\n }\r\n private async hydrateStore<K extends keyof GaniaDbSchema>(\r\n store: K,\r\n ): Promise<void> {\r\n // Already hydrated\r\n if (this.hydratedStores.has(store)) {\r\n return;\r\n }\r\n\r\n // Hydration currently in progress\r\n const activeHydration = this.activeHydrations.get(store);\r\n\r\n if (activeHydration) {\r\n return activeHydration;\r\n }\r\n\r\n const hydrationPromise = this.performHydration(store);\r\n\r\n this.activeHydrations.set(store, hydrationPromise);\r\n\r\n try {\r\n await hydrationPromise;\r\n } finally {\r\n this.activeHydrations.delete(store);\r\n }\r\n }\r\n\r\n async get<K extends keyof GaniaDbSchema>(\r\n store: K,\r\n key: GaniaDbSchema[K][\"key\"],\r\n ): Promise<GaniaDbSchema[K][\"value\"] | null> {\r\n await this.ready;\r\n const storeMap = this.getStoreMap(store);\r\n\r\n if (storeMap.has(key)) {\r\n return storeMap.get(key) ?? null;\r\n }\r\n\r\n const db = this.getDatabase();\r\n\r\n return new Promise((resolve) => {\r\n const tx = db.transaction(store as string, \"readonly\");\r\n\r\n const request = tx.objectStore(store as string).get(key as IDBValidKey);\r\n\r\n request.onsuccess = () => {\r\n const value = request.result ?? null;\r\n\r\n if (value !== null) {\r\n storeMap.set(key, value);\r\n }\r\n\r\n resolve(value as GaniaDbSchema[K][\"value\"] | null);\r\n };\r\n\r\n request.onerror = () => resolve(null);\r\n });\r\n }\r\n\r\n async set<K extends keyof GaniaDbSchema>(\r\n store: K,\r\n key: GaniaDbSchema[K][\"key\"],\r\n value: GaniaDbSchema[K][\"value\"],\r\n ): Promise<void> {\r\n await this.ready;\r\n const storeMap = this.getStoreMap(store);\r\n\r\n storeMap.set(key, value);\r\n\r\n const db = this.getDatabase();\r\n\r\n await new Promise<void>((resolve, reject) => {\r\n const tx = db.transaction(store as string, \"readwrite\");\r\n\r\n const request = tx\r\n .objectStore(store as string)\r\n .put(value, key as IDBValidKey);\r\n\r\n request.onsuccess = () => resolve();\r\n\r\n request.onerror = () => reject(request.error);\r\n });\r\n\r\n this.broadcast({\r\n type: \"set\",\r\n store: String(store),\r\n key: key as IDBValidKey,\r\n value,\r\n });\r\n }\r\n\r\n async delete<K extends keyof GaniaDbSchema>(\r\n store: K,\r\n key: GaniaDbSchema[K][\"key\"],\r\n ): Promise<void> {\r\n await this.ready;\r\n this.getStoreMap(store).delete(key);\r\n\r\n const db = this.getDatabase();\r\n\r\n await new Promise<void>((resolve, reject) => {\r\n const tx = db.transaction(store as string, \"readwrite\");\r\n\r\n const request = tx\r\n .objectStore(store as string)\r\n .delete(key as IDBValidKey);\r\n\r\n request.onsuccess = () => resolve();\r\n\r\n request.onerror = () => reject(request.error);\r\n });\r\n\r\n this.broadcast({\r\n type: \"delete\",\r\n store: String(store),\r\n key: key as IDBValidKey,\r\n });\r\n }\r\n\r\n async clear<K extends keyof GaniaDbSchema>(store: K): Promise<void> {\r\n await this.ready;\r\n this.getStoreMap(store).clear();\r\n\r\n const db = this.getDatabase();\r\n\r\n await new Promise<void>((resolve, reject) => {\r\n const tx = db.transaction(store as string, \"readwrite\");\r\n\r\n const request = tx.objectStore(store as string).clear();\r\n\r\n request.onsuccess = () => resolve();\r\n\r\n request.onerror = () => reject(request.error);\r\n });\r\n\r\n this.broadcast({\r\n type: \"clear\",\r\n store: String(store),\r\n });\r\n }\r\n\r\n async keys<K extends keyof GaniaDbSchema>(\r\n store: K,\r\n ): Promise<GaniaDbSchema[K][\"key\"][]> {\r\n await this.ready;\r\n await this.hydrateStore(store);\r\n\r\n return Array.from(this.getStoreMap(store).keys());\r\n }\r\n\r\n async entries<K extends keyof GaniaDbSchema>(\r\n store: K,\r\n ): Promise<[GaniaDbSchema[K][\"key\"], GaniaDbSchema[K][\"value\"]][]> {\r\n await this.ready;\r\n await this.hydrateStore(store);\r\n\r\n return Array.from(this.getStoreMap(store).entries());\r\n }\r\n\r\n async destroy() {\r\n this.channel?.close();\r\n this.db?.close();\r\n\r\n this.channel = null;\r\n this.db = null;\r\n }\r\n}\r\n","import { GaniaResponse, ResponseDataType } from \"./types\";\r\n\r\nexport class GaniaError<T = any> extends Error {\r\n response?: GaniaResponse<T>;\r\n\r\n constructor(message: string, response?: GaniaResponse<T>) {\r\n super(message);\r\n this.name = \"GaniaError\";\r\n this.response = response;\r\n }\r\n}\r\n\r\nexport async function getResponseData<T = any>(\r\n response: Response,\r\n dataType: ResponseDataType = \"json\",\r\n): Promise<{ data: T; dataType: ResponseDataType }> {\r\n // Handle explicit types safely without unsafe dynamic property lookups\r\n if (dataType !== \"flexible\") {\r\n let data: any;\r\n if (dataType === \"json\") data = await response.json();\r\n else if (dataType === \"text\") data = await response.text();\r\n else if (dataType === \"blob\") data = await response.blob();\r\n else if (dataType === \"bytes\") {\r\n const buffer = await response.arrayBuffer();\r\n data = new Uint8Array(buffer);\r\n }\r\n return { data, dataType };\r\n }\r\n\r\n // Handle the 'flexible' inferred fallback chain correctly\r\n try {\r\n const data = await response.json();\r\n return { data, dataType: \"json\" };\r\n } catch {\r\n try {\r\n const data = await response.text() as T;\r\n return { data, dataType: \"text\" };\r\n } catch {\r\n try {\r\n const data = await response.blob() as T;\r\n return { data, dataType: \"blob\" };\r\n } catch {\r\n const buffer = await response.arrayBuffer();\r\n const data = new Uint8Array(buffer) as T;\r\n return { data, dataType: \"bytes\" };\r\n }\r\n }\r\n }\r\n}\r\n","import { GaniaCache } from \"./cache/gania-cache\";\r\nimport { getResponseData } from \"./response\";\r\nimport {\r\n BaseUrl,\r\n CreateGaniaOptions,\r\n GaniaRequestConfig,\r\n GaniaRequestInit,\r\n GaniaResponse,\r\n} from \"./types\";\r\n\r\nexport default class Gania {\r\n public baseUrl?: BaseUrl;\r\n /**\r\n * The *`gdb`* is the indexedDB abstracted storage for the Gania data\r\n */\r\n private readonly gdb: GaniaCache;\r\n constructor(options?: CreateGaniaOptions) {\r\n this.gdb = new GaniaCache();\r\n this.baseUrl = options?.baseUrl;\r\n }\r\n get online() {\r\n return navigator.onLine;\r\n }\r\n async request<T = unknown>({\r\n method,\r\n input,\r\n ...init\r\n }: GaniaRequestConfig): Promise<GaniaResponse<T>> {\r\n if (!this.online) {\r\n if (method === \"GET\") {\r\n const cached = await this.gdb.get(\r\n \"responses\",\r\n this.createCacheKey(method, input),\r\n );\r\n\r\n return {\r\n data: cached?.data as T,\r\n } as GaniaResponse<T>;\r\n }\r\n\r\n await this.gdb.set(\"mutations\", this.createCacheKey(method!, input), {\r\n method: method!,\r\n url: String(input),\r\n body: init.body,\r\n timestamp: Date.now(),\r\n });\r\n\r\n return {\r\n queued: true,\r\n } as GaniaResponse<T>;\r\n }\r\n if (typeof input === \"string\") input = `${this.baseUrl || \"\"}${input}`;\r\n else input;\r\n const response = await fetch(input, {\r\n ...init,\r\n method,\r\n });\r\n const { data, dataType } = await getResponseData<T>(\r\n response,\r\n init.dataType ?? \"flexible\",\r\n );\r\n if (method === \"GET\") {\r\n await this.gdb.set(\"responses\", this.createCacheKey(method, input), {\r\n data,\r\n timestamp: Date.now(),\r\n });\r\n }\r\n return {\r\n data,\r\n status: response.status,\r\n statusText: response.statusText,\r\n headers: response.headers,\r\n ok: response.ok,\r\n dataType,\r\n };\r\n }\r\n createCacheKey(method: string, input: string | URL | Request): string {\r\n return `${method.trim().toUpperCase()}:${String(input)}`;\r\n }\r\n async get<T = any>(input: (string | Request) | URL, init?: GaniaRequestInit) {\r\n return this.request<T>({ method: \"GET\", input, ...init });\r\n }\r\n async post<T = unknown>(\r\n input: string | URL | Request,\r\n body?: BodyInit,\r\n init?: GaniaRequestInit,\r\n ) {\r\n return this.request<T>({\r\n input,\r\n method: \"POST\",\r\n body,\r\n ...init,\r\n });\r\n }\r\n async put<T = unknown>(\r\n input: string | URL | Request,\r\n body?: BodyInit,\r\n init?: GaniaRequestInit,\r\n ) {\r\n return this.request<T>({\r\n input,\r\n method: \"PUT\",\r\n body,\r\n ...init,\r\n });\r\n }\r\n async patch<T = unknown>(\r\n input: string | URL | Request,\r\n body?: BodyInit,\r\n init?: GaniaRequestInit,\r\n ) {\r\n return this.request<T>({\r\n input,\r\n method: \"PATCH\",\r\n body,\r\n ...init,\r\n });\r\n }\r\n async delete<T = unknown>(\r\n input: string | URL | Request,\r\n init?: GaniaRequestInit,\r\n ) {\r\n return this.request<T>({\r\n input,\r\n method: \"DELETE\",\r\n ...init,\r\n });\r\n }\r\n}\r\n","import Gania from \"./gania\";\r\nimport { CreateGaniaOptions, GaniaInstance, GaniaRequestConfig } from \"./types\";\r\n\r\nexport function create(options?: CreateGaniaOptions): GaniaInstance {\r\n const context = new Gania(options);\r\n\r\n const instance = Object.assign(\r\n <T = unknown>(config: GaniaRequestConfig) => context.request<T>(config),\r\n\r\n {\r\n request: context.request.bind(context),\r\n get: context.get.bind(context),\r\n post: context.post.bind(context),\r\n put: context.put.bind(context),\r\n patch: context.patch.bind(context),\r\n delete: context.delete.bind(context),\r\n create,\r\n },\r\n ) as GaniaInstance;\r\n\r\n return instance;\r\n}"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -55,13 +55,13 @@ interface GaniaInstance {
|
|
|
55
55
|
declare function create(options?: CreateGaniaOptions): GaniaInstance;
|
|
56
56
|
|
|
57
57
|
declare class Gania {
|
|
58
|
-
readonly online: boolean;
|
|
59
58
|
baseUrl?: BaseUrl;
|
|
60
59
|
/**
|
|
61
60
|
* The *`gdb`* is the indexedDB abstracted storage for the Gania data
|
|
62
61
|
*/
|
|
63
62
|
private readonly gdb;
|
|
64
63
|
constructor(options?: CreateGaniaOptions);
|
|
64
|
+
get online(): boolean;
|
|
65
65
|
request<T = unknown>({ method, input, ...init }: GaniaRequestConfig): Promise<GaniaResponse<T>>;
|
|
66
66
|
createCacheKey(method: string, input: string | URL | Request): string;
|
|
67
67
|
get<T = any>(input: (string | Request) | URL, init?: GaniaRequestInit): Promise<GaniaResponse<T>>;
|
package/dist/index.d.ts
CHANGED
|
@@ -55,13 +55,13 @@ interface GaniaInstance {
|
|
|
55
55
|
declare function create(options?: CreateGaniaOptions): GaniaInstance;
|
|
56
56
|
|
|
57
57
|
declare class Gania {
|
|
58
|
-
readonly online: boolean;
|
|
59
58
|
baseUrl?: BaseUrl;
|
|
60
59
|
/**
|
|
61
60
|
* The *`gdb`* is the indexedDB abstracted storage for the Gania data
|
|
62
61
|
*/
|
|
63
62
|
private readonly gdb;
|
|
64
63
|
constructor(options?: CreateGaniaOptions);
|
|
64
|
+
get online(): boolean;
|
|
65
65
|
request<T = unknown>({ method, input, ...init }: GaniaRequestConfig): Promise<GaniaResponse<T>>;
|
|
66
66
|
createCacheKey(method: string, input: string | URL | Request): string;
|
|
67
67
|
get<T = any>(input: (string | Request) | URL, init?: GaniaRequestInit): Promise<GaniaResponse<T>>;
|
package/dist/index.js
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
// src/cache/gania-cache.ts
|
|
2
2
|
var GaniaCache = class {
|
|
3
|
-
constructor(dbName, version = 1) {
|
|
4
|
-
this.dbName = dbName;
|
|
5
|
-
this.version = version;
|
|
6
|
-
}
|
|
7
|
-
dbName;
|
|
8
|
-
version;
|
|
9
3
|
db = null;
|
|
4
|
+
storeNames = [
|
|
5
|
+
"responses",
|
|
6
|
+
"mutations"
|
|
7
|
+
];
|
|
8
|
+
DB_NAME = "ganiadb";
|
|
9
|
+
VERSION = 1;
|
|
10
10
|
ramCache = /* @__PURE__ */ new Map();
|
|
11
11
|
hydratedStores = /* @__PURE__ */ new Set();
|
|
12
12
|
activeHydrations = /* @__PURE__ */ new Map();
|
|
13
13
|
channel = null;
|
|
14
|
+
ready;
|
|
15
|
+
constructor() {
|
|
16
|
+
this.ready = this.#init();
|
|
17
|
+
}
|
|
14
18
|
getDatabase() {
|
|
15
19
|
if (!this.db) {
|
|
16
20
|
throw new Error("GaniaCache has not been initialized.");
|
|
@@ -24,12 +28,12 @@ var GaniaCache = class {
|
|
|
24
28
|
}
|
|
25
29
|
return map;
|
|
26
30
|
}
|
|
27
|
-
async init(
|
|
31
|
+
async #init() {
|
|
28
32
|
return new Promise((resolve, reject) => {
|
|
29
|
-
const request = indexedDB.open(this.
|
|
33
|
+
const request = indexedDB.open(this.DB_NAME, this.VERSION);
|
|
30
34
|
request.onupgradeneeded = () => {
|
|
31
35
|
const db = request.result;
|
|
32
|
-
for (const storeName of storeNames) {
|
|
36
|
+
for (const storeName of this.storeNames) {
|
|
33
37
|
if (!db.objectStoreNames.contains(storeName)) {
|
|
34
38
|
db.createObjectStore(storeName);
|
|
35
39
|
}
|
|
@@ -37,10 +41,10 @@ var GaniaCache = class {
|
|
|
37
41
|
};
|
|
38
42
|
request.onsuccess = () => {
|
|
39
43
|
this.db = request.result;
|
|
40
|
-
for (const storeName of storeNames) {
|
|
44
|
+
for (const storeName of this.storeNames) {
|
|
41
45
|
this.ramCache.set(storeName, /* @__PURE__ */ new Map());
|
|
42
46
|
}
|
|
43
|
-
this.channel = new BroadcastChannel(`gania-cache:${this.
|
|
47
|
+
this.channel = new BroadcastChannel(`gania-cache:${this.DB_NAME}`);
|
|
44
48
|
this.channel.onmessage = (event) => this.handleBroadcast(event.data);
|
|
45
49
|
resolve(this);
|
|
46
50
|
};
|
|
@@ -107,6 +111,7 @@ var GaniaCache = class {
|
|
|
107
111
|
}
|
|
108
112
|
}
|
|
109
113
|
async get(store, key) {
|
|
114
|
+
await this.ready;
|
|
110
115
|
const storeMap = this.getStoreMap(store);
|
|
111
116
|
if (storeMap.has(key)) {
|
|
112
117
|
return storeMap.get(key) ?? null;
|
|
@@ -126,6 +131,7 @@ var GaniaCache = class {
|
|
|
126
131
|
});
|
|
127
132
|
}
|
|
128
133
|
async set(store, key, value) {
|
|
134
|
+
await this.ready;
|
|
129
135
|
const storeMap = this.getStoreMap(store);
|
|
130
136
|
storeMap.set(key, value);
|
|
131
137
|
const db = this.getDatabase();
|
|
@@ -143,6 +149,7 @@ var GaniaCache = class {
|
|
|
143
149
|
});
|
|
144
150
|
}
|
|
145
151
|
async delete(store, key) {
|
|
152
|
+
await this.ready;
|
|
146
153
|
this.getStoreMap(store).delete(key);
|
|
147
154
|
const db = this.getDatabase();
|
|
148
155
|
await new Promise((resolve, reject) => {
|
|
@@ -158,6 +165,7 @@ var GaniaCache = class {
|
|
|
158
165
|
});
|
|
159
166
|
}
|
|
160
167
|
async clear(store) {
|
|
168
|
+
await this.ready;
|
|
161
169
|
this.getStoreMap(store).clear();
|
|
162
170
|
const db = this.getDatabase();
|
|
163
171
|
await new Promise((resolve, reject) => {
|
|
@@ -172,16 +180,20 @@ var GaniaCache = class {
|
|
|
172
180
|
});
|
|
173
181
|
}
|
|
174
182
|
async keys(store) {
|
|
183
|
+
await this.ready;
|
|
175
184
|
await this.hydrateStore(store);
|
|
176
185
|
return Array.from(this.getStoreMap(store).keys());
|
|
177
186
|
}
|
|
178
187
|
async entries(store) {
|
|
188
|
+
await this.ready;
|
|
179
189
|
await this.hydrateStore(store);
|
|
180
190
|
return Array.from(this.getStoreMap(store).entries());
|
|
181
191
|
}
|
|
182
|
-
destroy() {
|
|
192
|
+
async destroy() {
|
|
183
193
|
this.channel?.close();
|
|
194
|
+
this.db?.close();
|
|
184
195
|
this.channel = null;
|
|
196
|
+
this.db = null;
|
|
185
197
|
}
|
|
186
198
|
};
|
|
187
199
|
|
|
@@ -220,17 +232,18 @@ async function getResponseData(response, dataType = "json") {
|
|
|
220
232
|
|
|
221
233
|
// src/gania.ts
|
|
222
234
|
var Gania = class {
|
|
223
|
-
online;
|
|
224
235
|
baseUrl;
|
|
225
236
|
/**
|
|
226
237
|
* The *`gdb`* is the indexedDB abstracted storage for the Gania data
|
|
227
238
|
*/
|
|
228
239
|
gdb;
|
|
229
240
|
constructor(options) {
|
|
230
|
-
this.
|
|
231
|
-
this.gdb = new GaniaCache("ganiadb");
|
|
241
|
+
this.gdb = new GaniaCache();
|
|
232
242
|
this.baseUrl = options?.baseUrl;
|
|
233
243
|
}
|
|
244
|
+
get online() {
|
|
245
|
+
return navigator.onLine;
|
|
246
|
+
}
|
|
234
247
|
async request({
|
|
235
248
|
method,
|
|
236
249
|
input,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cache/gania-cache.ts","../src/response.ts","../src/gania.ts","../src/create.ts","../src/index.ts"],"sourcesContent":["type CacheEvent =\r\n | {\r\n type: \"set\";\r\n store: string;\r\n key: IDBValidKey;\r\n value: unknown;\r\n }\r\n | {\r\n type: \"delete\";\r\n store: string;\r\n key: IDBValidKey;\r\n }\r\n | {\r\n type: \"clear\";\r\n store: string;\r\n };\r\n\r\ntype StoreDef<K = unknown, V = unknown> = {\r\n key: K;\r\n value: V;\r\n};\r\nexport type CacheSchema<T> = { [K in keyof T]: StoreDef };\r\n\r\nexport class GaniaCache<Schema extends CacheSchema<Schema>> {\r\n private db: IDBDatabase | null = null;\r\n\r\n private readonly ramCache = new Map<keyof Schema, Map<unknown, unknown>>();\r\n\r\n private readonly hydratedStores = new Set<keyof Schema>();\r\n\r\n private readonly activeHydrations = new Map<keyof Schema, Promise<void>>();\r\n\r\n private channel: BroadcastChannel | null = null;\r\n\r\n constructor(\r\n private readonly dbName: string,\r\n private readonly version = 1,\r\n ) {}\r\n\r\n private getDatabase(): IDBDatabase {\r\n if (!this.db) {\r\n throw new Error(\"GaniaCache has not been initialized.\");\r\n }\r\n\r\n return this.db;\r\n }\r\n\r\n private getStoreMap<K extends keyof Schema>(\r\n store: K,\r\n ): Map<Schema[K][\"key\"], Schema[K][\"value\"]> {\r\n const map = this.ramCache.get(store);\r\n\r\n if (!map) {\r\n throw new Error(`Store \"${String(store)}\" is not initialized.`);\r\n }\r\n\r\n return map as Map<Schema[K][\"key\"], Schema[K][\"value\"]>;\r\n }\r\n\r\n async init(storeNames: (keyof Schema & string)[]): Promise<this> {\r\n return new Promise((resolve, reject) => {\r\n const request = indexedDB.open(this.dbName, this.version);\r\n\r\n request.onupgradeneeded = () => {\r\n const db = request.result;\r\n\r\n for (const storeName of storeNames) {\r\n if (!db.objectStoreNames.contains(storeName)) {\r\n db.createObjectStore(storeName);\r\n }\r\n }\r\n };\r\n\r\n request.onsuccess = () => {\r\n this.db = request.result;\r\n\r\n for (const storeName of storeNames) {\r\n this.ramCache.set(storeName, new Map());\r\n }\r\n\r\n this.channel = new BroadcastChannel(`gania-cache:${this.dbName}`);\r\n\r\n this.channel.onmessage = (event) => this.handleBroadcast(event.data);\r\n\r\n resolve(this);\r\n };\r\n\r\n request.onerror = () => reject(request.error);\r\n });\r\n }\r\n\r\n private handleBroadcast(event: CacheEvent) {\r\n const storeMap = this.ramCache.get(event.store as keyof Schema);\r\n\r\n if (!storeMap) return;\r\n\r\n switch (event.type) {\r\n case \"set\":\r\n storeMap.set(event.key, event.value);\r\n break;\r\n\r\n case \"delete\":\r\n storeMap.delete(event.key);\r\n break;\r\n\r\n case \"clear\":\r\n storeMap.clear();\r\n break;\r\n }\r\n }\r\n\r\n private broadcast(event: CacheEvent) {\r\n this.channel?.postMessage(event);\r\n }\r\n private async performHydration<K extends keyof Schema>(\r\n store: K,\r\n ): Promise<void> {\r\n const db = this.getDatabase();\r\n\r\n const tx = db.transaction(store as string, \"readonly\");\r\n\r\n const objectStore = tx.objectStore(store as string);\r\n\r\n const [keys, values] = await Promise.all([\r\n new Promise<IDBValidKey[]>((resolve, reject) => {\r\n const req = objectStore.getAllKeys();\r\n\r\n req.onsuccess = () => resolve(req.result as IDBValidKey[]);\r\n\r\n req.onerror = () => reject(req.error);\r\n }),\r\n\r\n new Promise<unknown[]>((resolve, reject) => {\r\n const req = objectStore.getAll();\r\n\r\n req.onsuccess = () => resolve(req.result);\r\n\r\n req.onerror = () => reject(req.error);\r\n }),\r\n ]);\r\n\r\n const storeMap = this.getStoreMap(store);\r\n\r\n keys.forEach((key, index) => {\r\n storeMap.set(\r\n key as Schema[K][\"key\"],\r\n values[index] as Schema[K][\"value\"],\r\n );\r\n });\r\n\r\n this.hydratedStores.add(store);\r\n }\r\n private async hydrateStore<K extends keyof Schema>(store: K): Promise<void> {\r\n // Already hydrated\r\n if (this.hydratedStores.has(store)) {\r\n return;\r\n }\r\n\r\n // Hydration currently in progress\r\n const activeHydration = this.activeHydrations.get(store);\r\n\r\n if (activeHydration) {\r\n return activeHydration;\r\n }\r\n\r\n const hydrationPromise = this.performHydration(store);\r\n\r\n this.activeHydrations.set(store, hydrationPromise);\r\n\r\n try {\r\n await hydrationPromise;\r\n } finally {\r\n this.activeHydrations.delete(store);\r\n }\r\n }\r\n\r\n async get<K extends keyof Schema>(\r\n store: K,\r\n key: Schema[K][\"key\"],\r\n ): Promise<Schema[K][\"value\"] | null> {\r\n const storeMap = this.getStoreMap(store);\r\n\r\n if (storeMap.has(key)) {\r\n return storeMap.get(key) ?? null;\r\n }\r\n\r\n const db = this.getDatabase();\r\n\r\n return new Promise((resolve) => {\r\n const tx = db.transaction(store as string, \"readonly\");\r\n\r\n const request = tx.objectStore(store as string).get(key as IDBValidKey);\r\n\r\n request.onsuccess = () => {\r\n const value = request.result ?? null;\r\n\r\n if (value !== null) {\r\n storeMap.set(key, value);\r\n }\r\n\r\n resolve(value as Schema[K][\"value\"] | null);\r\n };\r\n\r\n request.onerror = () => resolve(null);\r\n });\r\n }\r\n\r\n async set<K extends keyof Schema>(\r\n store: K,\r\n key: Schema[K][\"key\"],\r\n value: Schema[K][\"value\"],\r\n ): Promise<void> {\r\n const storeMap = this.getStoreMap(store);\r\n\r\n storeMap.set(key, value);\r\n\r\n const db = this.getDatabase();\r\n\r\n await new Promise<void>((resolve, reject) => {\r\n const tx = db.transaction(store as string, \"readwrite\");\r\n\r\n const request = tx\r\n .objectStore(store as string)\r\n .put(value, key as IDBValidKey);\r\n\r\n request.onsuccess = () => resolve();\r\n\r\n request.onerror = () => reject(request.error);\r\n });\r\n\r\n this.broadcast({\r\n type: \"set\",\r\n store: String(store),\r\n key: key as IDBValidKey,\r\n value,\r\n });\r\n }\r\n\r\n async delete<K extends keyof Schema>(\r\n store: K,\r\n key: Schema[K][\"key\"],\r\n ): Promise<void> {\r\n this.getStoreMap(store).delete(key);\r\n\r\n const db = this.getDatabase();\r\n\r\n await new Promise<void>((resolve, reject) => {\r\n const tx = db.transaction(store as string, \"readwrite\");\r\n\r\n const request = tx\r\n .objectStore(store as string)\r\n .delete(key as IDBValidKey);\r\n\r\n request.onsuccess = () => resolve();\r\n\r\n request.onerror = () => reject(request.error);\r\n });\r\n\r\n this.broadcast({\r\n type: \"delete\",\r\n store: String(store),\r\n key: key as IDBValidKey,\r\n });\r\n }\r\n\r\n async clear<K extends keyof Schema>(store: K): Promise<void> {\r\n this.getStoreMap(store).clear();\r\n\r\n const db = this.getDatabase();\r\n\r\n await new Promise<void>((resolve, reject) => {\r\n const tx = db.transaction(store as string, \"readwrite\");\r\n\r\n const request = tx.objectStore(store as string).clear();\r\n\r\n request.onsuccess = () => resolve();\r\n\r\n request.onerror = () => reject(request.error);\r\n });\r\n\r\n this.broadcast({\r\n type: \"clear\",\r\n store: String(store),\r\n });\r\n }\r\n\r\n async keys<K extends keyof Schema>(store: K): Promise<Schema[K][\"key\"][]> {\r\n await this.hydrateStore(store);\r\n\r\n return Array.from(this.getStoreMap(store).keys());\r\n }\r\n\r\n async entries<K extends keyof Schema>(\r\n store: K,\r\n ): Promise<[Schema[K][\"key\"], Schema[K][\"value\"]][]> {\r\n await this.hydrateStore(store);\r\n\r\n return Array.from(this.getStoreMap(store).entries());\r\n }\r\n\r\n destroy() {\r\n this.channel?.close();\r\n this.channel = null;\r\n }\r\n}\r\n","import { GaniaResponse, ResponseDataType } from \"./types\";\r\n\r\nexport class GaniaError<T = any> extends Error {\r\n response?: GaniaResponse<T>;\r\n\r\n constructor(message: string, response?: GaniaResponse<T>) {\r\n super(message);\r\n this.name = \"GaniaError\";\r\n this.response = response;\r\n }\r\n}\r\n\r\nexport async function getResponseData<T = any>(\r\n response: Response,\r\n dataType: ResponseDataType = \"json\",\r\n): Promise<{ data: T; dataType: ResponseDataType }> {\r\n // Handle explicit types safely without unsafe dynamic property lookups\r\n if (dataType !== \"flexible\") {\r\n let data: any;\r\n if (dataType === \"json\") data = await response.json();\r\n else if (dataType === \"text\") data = await response.text();\r\n else if (dataType === \"blob\") data = await response.blob();\r\n else if (dataType === \"bytes\") {\r\n const buffer = await response.arrayBuffer();\r\n data = new Uint8Array(buffer);\r\n }\r\n return { data, dataType };\r\n }\r\n\r\n // Handle the 'flexible' inferred fallback chain correctly\r\n try {\r\n const data = await response.json();\r\n return { data, dataType: \"json\" };\r\n } catch {\r\n try {\r\n const data = await response.text() as T;\r\n return { data, dataType: \"text\" };\r\n } catch {\r\n try {\r\n const data = await response.blob() as T;\r\n return { data, dataType: \"blob\" };\r\n } catch {\r\n const buffer = await response.arrayBuffer();\r\n const data = new Uint8Array(buffer) as T;\r\n return { data, dataType: \"bytes\" };\r\n }\r\n }\r\n }\r\n}\r\n","import { GaniaCache } from \"./cache/gania-cache\";\r\nimport { getResponseData } from \"./response\";\r\nimport {\r\n BaseUrl,\r\n CreateGaniaOptions,\r\n GaniaDbSchema,\r\n GaniaRequestConfig,\r\n GaniaRequestInit,\r\n GaniaResponse,\r\n} from \"./types\";\r\n\r\nexport default class Gania {\r\n readonly online: boolean;\r\n public baseUrl?: BaseUrl;\r\n /**\r\n * The *`gdb`* is the indexedDB abstracted storage for the Gania data\r\n */\r\n private readonly gdb: GaniaCache<GaniaDbSchema>;\r\n constructor(options?: CreateGaniaOptions) {\r\n this.online = navigator.onLine;\r\n this.gdb = new GaniaCache<GaniaDbSchema>(\"ganiadb\");\r\n this.baseUrl = options?.baseUrl;\r\n }\r\n async request<T = unknown>({\r\n method,\r\n input,\r\n ...init\r\n }: GaniaRequestConfig): Promise<GaniaResponse<T>> {\r\n if (!this.online) {\r\n if (method === \"GET\") {\r\n const cached = await this.gdb.get(\r\n \"responses\",\r\n this.createCacheKey(method, input),\r\n );\r\n\r\n return {\r\n data: cached?.data as T,\r\n } as GaniaResponse<T>;\r\n }\r\n\r\n await this.gdb.set(\"mutations\", this.createCacheKey(method!, input), {\r\n method: method!,\r\n url: String(input),\r\n body: init.body,\r\n timestamp: Date.now(),\r\n });\r\n\r\n return {\r\n queued: true,\r\n } as GaniaResponse<T>;\r\n }\r\n if (typeof input === \"string\") input = `${this.baseUrl || \"\"}${input}`;\r\n else input;\r\n const response = await fetch(input, {\r\n ...init,\r\n method,\r\n });\r\n const { data, dataType } = await getResponseData<T>(\r\n response,\r\n init.dataType ?? \"flexible\",\r\n );\r\n if (method === \"GET\") {\r\n await this.gdb.set(\"responses\", this.createCacheKey(method, input), {\r\n data,\r\n timestamp: Date.now(),\r\n });\r\n }\r\n return {\r\n data,\r\n status: response.status,\r\n statusText: response.statusText,\r\n headers: response.headers,\r\n ok: response.ok,\r\n dataType,\r\n };\r\n }\r\n createCacheKey(method: string, input: string | URL | Request): string {\r\n return `${method.trim().toUpperCase()}:${String(input)}`;\r\n }\r\n async get<T = any>(input: (string | Request) | URL, init?: GaniaRequestInit) {\r\n return this.request<T>({ method: \"GET\", input, ...init });\r\n }\r\n async post<T = unknown>(\r\n input: string | URL | Request,\r\n body?: BodyInit,\r\n init?: GaniaRequestInit,\r\n ) {\r\n return this.request<T>({\r\n input,\r\n method: \"POST\",\r\n body,\r\n ...init,\r\n });\r\n }\r\n async put<T = unknown>(\r\n input: string | URL | Request,\r\n body?: BodyInit,\r\n init?: GaniaRequestInit,\r\n ) {\r\n return this.request<T>({\r\n input,\r\n method: \"PUT\",\r\n body,\r\n ...init,\r\n });\r\n }\r\n async patch<T = unknown>(\r\n input: string | URL | Request,\r\n body?: BodyInit,\r\n init?: GaniaRequestInit,\r\n ) {\r\n return this.request<T>({\r\n input,\r\n method: \"PATCH\",\r\n body,\r\n ...init,\r\n });\r\n }\r\n async delete<T = unknown>(\r\n input: string | URL | Request,\r\n init?: GaniaRequestInit,\r\n ) {\r\n return this.request<T>({\r\n input,\r\n method: \"DELETE\",\r\n ...init,\r\n });\r\n }\r\n}\r\n","import Gania from \"./gania\";\r\nimport { CreateGaniaOptions, GaniaInstance, GaniaRequestConfig } from \"./types\";\r\n\r\nexport function create(options?: CreateGaniaOptions): GaniaInstance {\r\n const context = new Gania(options);\r\n\r\n const instance = Object.assign(\r\n <T = unknown>(config: GaniaRequestConfig) => context.request<T>(config),\r\n\r\n {\r\n request: context.request.bind(context),\r\n get: context.get.bind(context),\r\n post: context.post.bind(context),\r\n put: context.put.bind(context),\r\n patch: context.patch.bind(context),\r\n delete: context.delete.bind(context),\r\n create,\r\n },\r\n ) as GaniaInstance;\r\n\r\n return instance;\r\n}","import { create } from \"./create\";\r\n\r\nconst gania = create();\r\n\r\nexport default gania\r\n\r\nexport { default as Gania } from \"./gania\";\r\nexport { create };\r\nexport * from \"./types\"\r\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/cache/gania-cache.ts","../src/response.ts","../src/gania.ts","../src/create.ts","../src/index.ts"],"sourcesContent":["import { GaniaDbSchema } from \"../types\";\r\n\r\ntype CacheEvent =\r\n | {\r\n type: \"set\";\r\n store: string;\r\n key: IDBValidKey;\r\n value: unknown;\r\n }\r\n | {\r\n type: \"delete\";\r\n store: string;\r\n key: IDBValidKey;\r\n }\r\n | {\r\n type: \"clear\";\r\n store: string;\r\n };\r\n\r\nexport class GaniaCache {\r\n private db: IDBDatabase | null = null;\r\n private readonly storeNames = [\r\n \"responses\",\r\n \"mutations\",\r\n ] as const satisfies (keyof GaniaDbSchema)[];\r\n\r\n private readonly DB_NAME = \"ganiadb\";\r\n private readonly VERSION = 1;\r\n\r\n private readonly ramCache = new Map<\r\n keyof GaniaDbSchema,\r\n Map<unknown, unknown>\r\n >();\r\n\r\n private readonly hydratedStores = new Set<keyof GaniaDbSchema>();\r\n\r\n private readonly activeHydrations = new Map<\r\n keyof GaniaDbSchema,\r\n Promise<void>\r\n >();\r\n\r\n private channel: BroadcastChannel | null = null;\r\n\r\n private readonly ready: Promise<this>;\r\n\r\n constructor() {\r\n this.ready = this.#init();\r\n }\r\n\r\n private getDatabase(): IDBDatabase {\r\n if (!this.db) {\r\n throw new Error(\"GaniaCache has not been initialized.\");\r\n }\r\n\r\n return this.db;\r\n }\r\n\r\n private getStoreMap<K extends keyof GaniaDbSchema>(\r\n store: K,\r\n ): Map<GaniaDbSchema[K][\"key\"], GaniaDbSchema[K][\"value\"]> {\r\n const map = this.ramCache.get(store);\r\n\r\n if (!map) {\r\n throw new Error(`Store \"${String(store)}\" is not initialized.`);\r\n }\r\n\r\n return map as Map<GaniaDbSchema[K][\"key\"], GaniaDbSchema[K][\"value\"]>;\r\n }\r\n\r\n async #init(): Promise<this> {\r\n return new Promise((resolve, reject) => {\r\n const request = indexedDB.open(this.DB_NAME, this.VERSION);\r\n\r\n request.onupgradeneeded = () => {\r\n const db = request.result;\r\n\r\n for (const storeName of this.storeNames) {\r\n if (!db.objectStoreNames.contains(storeName as string)) {\r\n db.createObjectStore(storeName as string);\r\n }\r\n }\r\n };\r\n\r\n request.onsuccess = () => {\r\n this.db = request.result;\r\n\r\n for (const storeName of this.storeNames) {\r\n this.ramCache.set(storeName, new Map());\r\n }\r\n\r\n this.channel = new BroadcastChannel(`gania-cache:${this.DB_NAME}`);\r\n\r\n this.channel.onmessage = (event) => this.handleBroadcast(event.data);\r\n\r\n resolve(this);\r\n };\r\n\r\n request.onerror = () => reject(request.error);\r\n });\r\n }\r\n\r\n private handleBroadcast(event: CacheEvent) {\r\n const storeMap = this.ramCache.get(event.store as keyof GaniaDbSchema);\r\n\r\n if (!storeMap) return;\r\n\r\n switch (event.type) {\r\n case \"set\":\r\n storeMap.set(event.key, event.value);\r\n break;\r\n\r\n case \"delete\":\r\n storeMap.delete(event.key);\r\n break;\r\n\r\n case \"clear\":\r\n storeMap.clear();\r\n break;\r\n }\r\n }\r\n\r\n private broadcast(event: CacheEvent) {\r\n this.channel?.postMessage(event);\r\n }\r\n private async performHydration<K extends keyof GaniaDbSchema>(\r\n store: K,\r\n ): Promise<void> {\r\n const db = this.getDatabase();\r\n\r\n const tx = db.transaction(store as string, \"readonly\");\r\n\r\n const objectStore = tx.objectStore(store as string);\r\n\r\n const [keys, values] = await Promise.all([\r\n new Promise<IDBValidKey[]>((resolve, reject) => {\r\n const req = objectStore.getAllKeys();\r\n\r\n req.onsuccess = () => resolve(req.result as IDBValidKey[]);\r\n\r\n req.onerror = () => reject(req.error);\r\n }),\r\n\r\n new Promise<unknown[]>((resolve, reject) => {\r\n const req = objectStore.getAll();\r\n\r\n req.onsuccess = () => resolve(req.result);\r\n\r\n req.onerror = () => reject(req.error);\r\n }),\r\n ]);\r\n\r\n const storeMap = this.getStoreMap(store);\r\n\r\n keys.forEach((key, index) => {\r\n storeMap.set(\r\n key as GaniaDbSchema[K][\"key\"],\r\n values[index] as GaniaDbSchema[K][\"value\"],\r\n );\r\n });\r\n\r\n this.hydratedStores.add(store);\r\n }\r\n private async hydrateStore<K extends keyof GaniaDbSchema>(\r\n store: K,\r\n ): Promise<void> {\r\n // Already hydrated\r\n if (this.hydratedStores.has(store)) {\r\n return;\r\n }\r\n\r\n // Hydration currently in progress\r\n const activeHydration = this.activeHydrations.get(store);\r\n\r\n if (activeHydration) {\r\n return activeHydration;\r\n }\r\n\r\n const hydrationPromise = this.performHydration(store);\r\n\r\n this.activeHydrations.set(store, hydrationPromise);\r\n\r\n try {\r\n await hydrationPromise;\r\n } finally {\r\n this.activeHydrations.delete(store);\r\n }\r\n }\r\n\r\n async get<K extends keyof GaniaDbSchema>(\r\n store: K,\r\n key: GaniaDbSchema[K][\"key\"],\r\n ): Promise<GaniaDbSchema[K][\"value\"] | null> {\r\n await this.ready;\r\n const storeMap = this.getStoreMap(store);\r\n\r\n if (storeMap.has(key)) {\r\n return storeMap.get(key) ?? null;\r\n }\r\n\r\n const db = this.getDatabase();\r\n\r\n return new Promise((resolve) => {\r\n const tx = db.transaction(store as string, \"readonly\");\r\n\r\n const request = tx.objectStore(store as string).get(key as IDBValidKey);\r\n\r\n request.onsuccess = () => {\r\n const value = request.result ?? null;\r\n\r\n if (value !== null) {\r\n storeMap.set(key, value);\r\n }\r\n\r\n resolve(value as GaniaDbSchema[K][\"value\"] | null);\r\n };\r\n\r\n request.onerror = () => resolve(null);\r\n });\r\n }\r\n\r\n async set<K extends keyof GaniaDbSchema>(\r\n store: K,\r\n key: GaniaDbSchema[K][\"key\"],\r\n value: GaniaDbSchema[K][\"value\"],\r\n ): Promise<void> {\r\n await this.ready;\r\n const storeMap = this.getStoreMap(store);\r\n\r\n storeMap.set(key, value);\r\n\r\n const db = this.getDatabase();\r\n\r\n await new Promise<void>((resolve, reject) => {\r\n const tx = db.transaction(store as string, \"readwrite\");\r\n\r\n const request = tx\r\n .objectStore(store as string)\r\n .put(value, key as IDBValidKey);\r\n\r\n request.onsuccess = () => resolve();\r\n\r\n request.onerror = () => reject(request.error);\r\n });\r\n\r\n this.broadcast({\r\n type: \"set\",\r\n store: String(store),\r\n key: key as IDBValidKey,\r\n value,\r\n });\r\n }\r\n\r\n async delete<K extends keyof GaniaDbSchema>(\r\n store: K,\r\n key: GaniaDbSchema[K][\"key\"],\r\n ): Promise<void> {\r\n await this.ready;\r\n this.getStoreMap(store).delete(key);\r\n\r\n const db = this.getDatabase();\r\n\r\n await new Promise<void>((resolve, reject) => {\r\n const tx = db.transaction(store as string, \"readwrite\");\r\n\r\n const request = tx\r\n .objectStore(store as string)\r\n .delete(key as IDBValidKey);\r\n\r\n request.onsuccess = () => resolve();\r\n\r\n request.onerror = () => reject(request.error);\r\n });\r\n\r\n this.broadcast({\r\n type: \"delete\",\r\n store: String(store),\r\n key: key as IDBValidKey,\r\n });\r\n }\r\n\r\n async clear<K extends keyof GaniaDbSchema>(store: K): Promise<void> {\r\n await this.ready;\r\n this.getStoreMap(store).clear();\r\n\r\n const db = this.getDatabase();\r\n\r\n await new Promise<void>((resolve, reject) => {\r\n const tx = db.transaction(store as string, \"readwrite\");\r\n\r\n const request = tx.objectStore(store as string).clear();\r\n\r\n request.onsuccess = () => resolve();\r\n\r\n request.onerror = () => reject(request.error);\r\n });\r\n\r\n this.broadcast({\r\n type: \"clear\",\r\n store: String(store),\r\n });\r\n }\r\n\r\n async keys<K extends keyof GaniaDbSchema>(\r\n store: K,\r\n ): Promise<GaniaDbSchema[K][\"key\"][]> {\r\n await this.ready;\r\n await this.hydrateStore(store);\r\n\r\n return Array.from(this.getStoreMap(store).keys());\r\n }\r\n\r\n async entries<K extends keyof GaniaDbSchema>(\r\n store: K,\r\n ): Promise<[GaniaDbSchema[K][\"key\"], GaniaDbSchema[K][\"value\"]][]> {\r\n await this.ready;\r\n await this.hydrateStore(store);\r\n\r\n return Array.from(this.getStoreMap(store).entries());\r\n }\r\n\r\n async destroy() {\r\n this.channel?.close();\r\n this.db?.close();\r\n\r\n this.channel = null;\r\n this.db = null;\r\n }\r\n}\r\n","import { GaniaResponse, ResponseDataType } from \"./types\";\r\n\r\nexport class GaniaError<T = any> extends Error {\r\n response?: GaniaResponse<T>;\r\n\r\n constructor(message: string, response?: GaniaResponse<T>) {\r\n super(message);\r\n this.name = \"GaniaError\";\r\n this.response = response;\r\n }\r\n}\r\n\r\nexport async function getResponseData<T = any>(\r\n response: Response,\r\n dataType: ResponseDataType = \"json\",\r\n): Promise<{ data: T; dataType: ResponseDataType }> {\r\n // Handle explicit types safely without unsafe dynamic property lookups\r\n if (dataType !== \"flexible\") {\r\n let data: any;\r\n if (dataType === \"json\") data = await response.json();\r\n else if (dataType === \"text\") data = await response.text();\r\n else if (dataType === \"blob\") data = await response.blob();\r\n else if (dataType === \"bytes\") {\r\n const buffer = await response.arrayBuffer();\r\n data = new Uint8Array(buffer);\r\n }\r\n return { data, dataType };\r\n }\r\n\r\n // Handle the 'flexible' inferred fallback chain correctly\r\n try {\r\n const data = await response.json();\r\n return { data, dataType: \"json\" };\r\n } catch {\r\n try {\r\n const data = await response.text() as T;\r\n return { data, dataType: \"text\" };\r\n } catch {\r\n try {\r\n const data = await response.blob() as T;\r\n return { data, dataType: \"blob\" };\r\n } catch {\r\n const buffer = await response.arrayBuffer();\r\n const data = new Uint8Array(buffer) as T;\r\n return { data, dataType: \"bytes\" };\r\n }\r\n }\r\n }\r\n}\r\n","import { GaniaCache } from \"./cache/gania-cache\";\r\nimport { getResponseData } from \"./response\";\r\nimport {\r\n BaseUrl,\r\n CreateGaniaOptions,\r\n GaniaRequestConfig,\r\n GaniaRequestInit,\r\n GaniaResponse,\r\n} from \"./types\";\r\n\r\nexport default class Gania {\r\n public baseUrl?: BaseUrl;\r\n /**\r\n * The *`gdb`* is the indexedDB abstracted storage for the Gania data\r\n */\r\n private readonly gdb: GaniaCache;\r\n constructor(options?: CreateGaniaOptions) {\r\n this.gdb = new GaniaCache();\r\n this.baseUrl = options?.baseUrl;\r\n }\r\n get online() {\r\n return navigator.onLine;\r\n }\r\n async request<T = unknown>({\r\n method,\r\n input,\r\n ...init\r\n }: GaniaRequestConfig): Promise<GaniaResponse<T>> {\r\n if (!this.online) {\r\n if (method === \"GET\") {\r\n const cached = await this.gdb.get(\r\n \"responses\",\r\n this.createCacheKey(method, input),\r\n );\r\n\r\n return {\r\n data: cached?.data as T,\r\n } as GaniaResponse<T>;\r\n }\r\n\r\n await this.gdb.set(\"mutations\", this.createCacheKey(method!, input), {\r\n method: method!,\r\n url: String(input),\r\n body: init.body,\r\n timestamp: Date.now(),\r\n });\r\n\r\n return {\r\n queued: true,\r\n } as GaniaResponse<T>;\r\n }\r\n if (typeof input === \"string\") input = `${this.baseUrl || \"\"}${input}`;\r\n else input;\r\n const response = await fetch(input, {\r\n ...init,\r\n method,\r\n });\r\n const { data, dataType } = await getResponseData<T>(\r\n response,\r\n init.dataType ?? \"flexible\",\r\n );\r\n if (method === \"GET\") {\r\n await this.gdb.set(\"responses\", this.createCacheKey(method, input), {\r\n data,\r\n timestamp: Date.now(),\r\n });\r\n }\r\n return {\r\n data,\r\n status: response.status,\r\n statusText: response.statusText,\r\n headers: response.headers,\r\n ok: response.ok,\r\n dataType,\r\n };\r\n }\r\n createCacheKey(method: string, input: string | URL | Request): string {\r\n return `${method.trim().toUpperCase()}:${String(input)}`;\r\n }\r\n async get<T = any>(input: (string | Request) | URL, init?: GaniaRequestInit) {\r\n return this.request<T>({ method: \"GET\", input, ...init });\r\n }\r\n async post<T = unknown>(\r\n input: string | URL | Request,\r\n body?: BodyInit,\r\n init?: GaniaRequestInit,\r\n ) {\r\n return this.request<T>({\r\n input,\r\n method: \"POST\",\r\n body,\r\n ...init,\r\n });\r\n }\r\n async put<T = unknown>(\r\n input: string | URL | Request,\r\n body?: BodyInit,\r\n init?: GaniaRequestInit,\r\n ) {\r\n return this.request<T>({\r\n input,\r\n method: \"PUT\",\r\n body,\r\n ...init,\r\n });\r\n }\r\n async patch<T = unknown>(\r\n input: string | URL | Request,\r\n body?: BodyInit,\r\n init?: GaniaRequestInit,\r\n ) {\r\n return this.request<T>({\r\n input,\r\n method: \"PATCH\",\r\n body,\r\n ...init,\r\n });\r\n }\r\n async delete<T = unknown>(\r\n input: string | URL | Request,\r\n init?: GaniaRequestInit,\r\n ) {\r\n return this.request<T>({\r\n input,\r\n method: \"DELETE\",\r\n ...init,\r\n });\r\n }\r\n}\r\n","import Gania from \"./gania\";\r\nimport { CreateGaniaOptions, GaniaInstance, GaniaRequestConfig } from \"./types\";\r\n\r\nexport function create(options?: CreateGaniaOptions): GaniaInstance {\r\n const context = new Gania(options);\r\n\r\n const instance = Object.assign(\r\n <T = unknown>(config: GaniaRequestConfig) => context.request<T>(config),\r\n\r\n {\r\n request: context.request.bind(context),\r\n get: context.get.bind(context),\r\n post: context.post.bind(context),\r\n put: context.put.bind(context),\r\n patch: context.patch.bind(context),\r\n delete: context.delete.bind(context),\r\n create,\r\n },\r\n ) as GaniaInstance;\r\n\r\n return instance;\r\n}","import { create } from \"./create\";\r\n\r\nconst gania = create();\r\n\r\nexport default gania\r\n\r\nexport { default as Gania } from \"./gania\";\r\nexport { create };\r\nexport * from \"./types\"\r\n"],"mappings":"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","names":[]}
|