Skip to content

Commit f38585e

Browse files
authored
Merge pull request #682 from NMFS-RADFish/storage
@nmfs-radfish/radfish v1.1.0: Add new storage classes
2 parents c6980fd + 4a4d88c commit f38585e

24 files changed

+1822
-339
lines changed

packages/radfish/Application.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Application, IndexedDBMethod, LocalStorageMethod } from './index';
22

3-
describe ('Application', () => {
3+
describe('Application', () => {
44
describe('storage', () => {
55
it('should return the storage method', () => {
66
// IndexedDB Storage application

packages/radfish/babel.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
presets: [
3+
'@babel/preset-env',
4+
'@babel/preset-typescript',
5+
],
6+
};

packages/radfish/index.js

Lines changed: 114 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,121 @@
1-
import { setupWorker } from "msw/browser";
1+
import { Store, Schema, LocalStorageConnector, IndexedDBConnector } from './storage';
22
import { StorageMethod, IndexedDBMethod, LocalStorageMethod } from "./on-device-storage/storage";
33

4-
class EventEmitter extends EventTarget {}
4+
const registerServiceWorker = async (url) => {
5+
if ("serviceWorker" in navigator) {
6+
try {
7+
const registration = await navigator.serviceWorker.register(url, {
8+
scope: "/",
9+
});
10+
if (registration.installing) {
11+
console.log("Service worker installing");
12+
} else if (registration.waiting) {
13+
console.log("Service worker installed");
14+
} else if (registration.active) {
15+
console.log("Service worker active");
16+
}
17+
return registration;
18+
} catch (error) {
19+
console.error(`Registration failed with ${error}`);
20+
}
21+
}
22+
};
523

624
export class Application {
725
constructor(options = {}) {
8-
this.emitter = new EventEmitter();
26+
this.emitter = new EventTarget();
927
this.serviceWorker = null;
1028
this.isOnline = navigator.onLine;
1129
this._options = options;
30+
this._initializationPromise = null;
1231

32+
// Register event listeners
1333
this._registerEventListeners();
1434

35+
// Initialize everything
36+
this._initializationPromise = this._initialize();
37+
}
38+
39+
/**
40+
* Initialize the application stores and collections
41+
* @private
42+
*/
43+
async _initialize() {
44+
// Initialize stores
45+
this.stores = null;
46+
if (this._options.stores && typeof this._options.stores === 'object') {
47+
this.stores = {};
48+
49+
// Initialize each store and its connector
50+
const storeInitPromises = [];
51+
52+
for (let storeKey in this._options.stores) {
53+
const store = this._options.stores[storeKey]
54+
let name = store.name || storeKey;
55+
let connector = store.connector;
56+
57+
if (!connector) {
58+
throw new Error(`Store ${name} is missing a connector`);
59+
}
60+
61+
// Create the store
62+
this.stores[name] = new Store({name, connector});
63+
64+
// Initialize the connector
65+
const initPromise = this.stores[name].connector.initialize()
66+
.then(async () => {
67+
// Add collections if they exist
68+
if (store.collections) {
69+
const collectionPromises = [];
70+
71+
for (let collectionKey in store.collections) {
72+
let collection = store.collections[collectionKey];
73+
let schema = collection.schema;
74+
75+
// Handle schema configuration object
76+
if (typeof schema === 'object' && !(schema instanceof Schema)) {
77+
// If schema doesn't have a name, use the collectionKey as default
78+
if (!schema.name) {
79+
schema = { ...schema, name: collectionKey };
80+
}
81+
schema = new Schema(schema);
82+
}
83+
84+
// Add collection (might be async for IndexedDBConnector)
85+
const addCollectionPromise = Promise.resolve(
86+
this.stores[name].connector.addCollection(schema)
87+
);
88+
collectionPromises.push(addCollectionPromise);
89+
}
90+
91+
// Wait for all collections to be added
92+
return Promise.all(collectionPromises);
93+
}
94+
});
95+
96+
storeInitPromises.push(initPromise);
97+
}
98+
99+
// Wait for all stores to be initialized
100+
await Promise.all(storeInitPromises);
101+
console.log(storeInitPromises[0])
102+
console.log(this.stores.weatherSurvey.connector.collections);
103+
}
104+
105+
// Dispatch the init event
15106
this._dispatch("init");
107+
108+
return true;
16109
}
17110

18111
get storage() {
19112
if (!this._options.storage) {
20113
return null;
21114
}
22115

116+
console.warn('Deprecation: Please update to use Connectors instead of StorageMethod: https://nmfs-radfish.github.io/radfish/design-system/storage');
117+
23118
if (!(this._options.storage instanceof StorageMethod)) {
24-
console.warn('Please update the storage method to be an instance of StorageMethod');
25-
26119
switch (this._options.storage?.type) {
27120
case "indexedDB": {
28121
return new IndexedDBMethod(
@@ -64,7 +157,11 @@ export class Application {
64157
this._options?.mocks?.handlers,
65158
this._options?.serviceWorker?.url
66159
);
67-
this._dispatch("ready", { worker });
160+
161+
this.serviceWorker = worker;
162+
163+
// Only dispatch ready event if worker is successfully installed or if no service worker was configured
164+
this._dispatch("ready");
68165
});
69166

70167
const handleOnline = (event) => {
@@ -83,21 +180,17 @@ export class Application {
83180
async _installServiceWorker(handlers, url) {
84181
if (!url) return null;
85182
console.info("Installing service worker");
86-
const worker = setupWorker(...((await handlers)?.default || []));
87-
const onUnhandledRequest = "bypass";
88-
89-
this.serviceWorker = worker;
90-
91-
worker
92-
.start({
93-
onUnhandledRequest,
94-
serviceWorker: {
95-
url: url,
96-
},
97-
})
98-
.then(() => {
99-
console.debug("Service worker installed");
100-
});
183+
184+
try {
185+
const registration = await registerServiceWorker(url);
186+
187+
console.debug("Service worker installed and started successfully");
188+
// return worker;
189+
return registration;
190+
} catch (error) {
191+
console.error("Failed to install service worker:", error);
192+
return null;
193+
}
101194
}
102195
}
103196

packages/radfish/jest.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/** @type {import('jest').Config} */
2+
const config = {
3+
testEnvironment: 'jsdom',
4+
};
5+
6+
module.exports = config;

packages/radfish/package.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
22
"name": "@nmfs-radfish/radfish",
3-
"version": "1.0.0",
3+
"version": "1.1.0",
44
"main": "index.js",
55
"scripts": {
6-
"test": "echo \"Error: no test specified\" && exit 1"
6+
"test": "jest"
77
},
88
"keywords": [],
99
"author": "",
@@ -13,5 +13,13 @@
1313
"dexie": "4.0.x",
1414
"msw": "^2.3.1",
1515
"react": "^18.3.1"
16+
},
17+
"devDependencies": {
18+
"@babel/core": "^7.26.8",
19+
"@babel/preset-env": "^7.26.8",
20+
"@babel/preset-typescript": "^7.26.0",
21+
"babel-jest": "^29.7.0",
22+
"jest": "^29.7.0",
23+
"jest-environment-jsdom": "^29.7.0"
1624
}
1725
}

0 commit comments

Comments
 (0)