@wakit/core 0.0.0-stage → 0.1.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/README.md CHANGED
@@ -1,3 +1,266 @@
1
- # Temporary Holding Version
1
+ <h1 align="center">Wakit</h1>
2
+ <h3 align="center">Your toolkit for Progressive Web Applications</h3>
2
3
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
4
+ ---
5
+
6
+ Wakit (Web Applications Kit) is a set of tools to build Progressive Web Applications (mobile like applications using web).
7
+ It includes an ORM, a network system and an event system, all working together.
8
+
9
+ It's a great addition for applications built using **capacitor.js** (Ionic for example)
10
+
11
+ ## How
12
+
13
+ Wakit core combines every part of the system in a single package:
14
+
15
+ - [@wakit/waorm](https://www.npmjs.com/package/@wakit/waorm) — your ORM, using IndexedDB by default
16
+ - [@wakit/networker](https://www.npmjs.com/package/@wakit/networker) — the network system, a wrapper of axios
17
+ - [@wakit/events](https://www.npmjs.com/package/@wakit/events) — the event system
18
+
19
+ `await init({ database, toast, network })`
20
+
21
+ A single call sets up your database and network. All events from the different parts are wired into the core event
22
+ system, so you only need to subscribe in one place.
23
+
24
+ ## Installation
25
+
26
+ `npm i @wakit/core`
27
+
28
+ ## Usage
29
+
30
+ #### Initialization
31
+
32
+ Call `init` once when your application starts. Every option is optional, so just pass what you need:
33
+
34
+ ```typescript
35
+ import { init } from '@wakit/core'
36
+
37
+ await init({
38
+ database: {
39
+ name: 'MyDatabase',
40
+ // Increment the version every time you do a change on the schema
41
+ version: 1,
42
+ stores: [
43
+ {
44
+ name: 'users',
45
+ indexes: [
46
+ { name: 'name' },
47
+ { name: 'email', unique: true },
48
+ ],
49
+ },
50
+ ],
51
+ },
52
+ toast: {
53
+ success: (msg: string) => console.log(msg),
54
+ error: (msg: string) => console.error(msg),
55
+ },
56
+ network: {
57
+ pingUrl: 'https://example.com/ping',
58
+ },
59
+ })
60
+ ```
61
+
62
+ - `database` — the database config, see [@wakit/waorm](https://www.npmjs.com/package/@wakit/waorm) for all the options
63
+ - `toast` — the toast system used to display network errors
64
+ - `network.pingUrl` — when set, requests first check the internet connection by pinging this url, and skip the request when offline
65
+ - `debug` — logs the initialization steps to the console. Defaults to `false`
66
+
67
+
68
+ ##### Waiting for Wakit
69
+
70
+ If some part of your application may run before `init` finishes, use `waitForWakit`. It throws if wakit isn't ready
71
+ after ~2 seconds:
72
+
73
+ ```typescript
74
+ import { waitForWakit } from '@wakit/core'
75
+
76
+ await waitForWakit()
77
+ ```
78
+
79
+ #### Models & Network
80
+
81
+ Core re-exports the most used functions and types, so you don't need to import each package:
82
+
83
+ ```typescript
84
+ import { Model, collect, network } from '@wakit/core'
85
+
86
+ class User extends Model {
87
+ storeName(): string {
88
+ return 'users'
89
+ }
90
+ }
91
+
92
+ const user = () => (new User)
93
+
94
+ const data = await network.get('/user')
95
+ await user().hydrate(data).save()
96
+
97
+ await collect(user().all()).count()
98
+ ```
99
+
100
+ Check [@wakit/waorm](https://www.npmjs.com/package/@wakit/waorm) and [@wakit/networker](https://www.npmjs.com/package/@wakit/networker)
101
+ for everything you can do with models and network.
102
+
103
+ #### Events
104
+
105
+ Subscribing to events is super easy, just use `subscribe` with any of the events wakit provides:
106
+
107
+ ```typescript
108
+ import { subscribe, unsubscribe, NETWORK_OFFLINE } from '@wakit/core'
109
+
110
+ const eventId = subscribe(NETWORK_OFFLINE, () => {
111
+ alert('You are offline')
112
+ })
113
+
114
+ onbeforeunload = () => unsubscribe(eventId)
115
+ ```
116
+
117
+ ##### Wakit
118
+
119
+ - `WAKIT_READY` — `init` finished
120
+
121
+ ##### Database
122
+
123
+ - `DATABASE_READY` — database is initialized
124
+ - `DATABASE_INIT_ERROR` — database failed to initialize. Context is the error
125
+ - `DATABASE_BLOCKED` — another connection is blocking the upgrade. Context is `{ name, oldVersion, newVersion }`
126
+ - `DATABASE_VERSION_CHANGE` — a newer version was opened (e.g. in another tab). Context is `{ name, oldVersion, newVersion }`
127
+ - `MODEL_OPERATION_ERROR` — a model operation failed. Context is the error
128
+
129
+ ##### Network
130
+
131
+ - `NETWORK_ONLINE` / `NETWORK_OFFLINE` — result of every connection check
132
+ - `NETWORK_RECONNECTED` / `NETWORK_DISCONNECTED` — connection was restored / lost (only when it changes)
133
+ - `NETWORK_SLOW_CONNECTION` — the ping took longer than 350ms
134
+ - `NETWORK_HANDLED_ERROR` — a request error was handled. Context is the error
135
+
136
+ ##### Version Changes
137
+
138
+ Database events can fire during `init`, so subscribe to them before calling it.
139
+
140
+ When a newer `version` is opened, the existing connection is closed and can't be used anymore, so reload the app:
141
+
142
+ ```typescript
143
+ import { init, subscribe, DATABASE_BLOCKED, DATABASE_VERSION_CHANGE } from '@wakit/core'
144
+
145
+ subscribe(DATABASE_VERSION_CHANGE, () => location.reload())
146
+ subscribe(DATABASE_BLOCKED, () => alert('Please close other tabs'))
147
+
148
+ await init({ database: { ... } })
149
+ ```
150
+
151
+ #### Error Handling
152
+
153
+ `init` throws if the database fails to initialize, after dispatching `DATABASE_INIT_ERROR`. Wrap in try/catch or listen for errors:
154
+
155
+ ```typescript
156
+ import { init, subscribe, DATABASE_INIT_ERROR, MODEL_OPERATION_ERROR } from '@wakit/core'
157
+
158
+ subscribe(DATABASE_INIT_ERROR, (err) => console.error('DB init failed:', err))
159
+ subscribe(MODEL_OPERATION_ERROR, (err) => console.error('Model op failed:', err))
160
+
161
+ await init({ database: { ... } })
162
+ ```
163
+
164
+ ## Example
165
+
166
+ Here is an example setup for a simple Todo App
167
+
168
+ #### JavaScript
169
+ ```javascript
170
+ import { init, subscribe, Model, network, WAKIT_READY, NETWORK_RECONNECTED } from '@wakit/core'
171
+
172
+ class Todo extends Model {
173
+ storeName() {
174
+ return 'todos'
175
+ }
176
+ }
177
+
178
+ const todo = () => (new Todo)
179
+
180
+ const syncTodos = async () => {
181
+ const todos = await network.get('/todos')
182
+
183
+ for (const data of todos ?? []) {
184
+ await todo().hydrate(data).save()
185
+ }
186
+ }
187
+
188
+ subscribe(WAKIT_READY, syncTodos)
189
+ subscribe(NETWORK_RECONNECTED, syncTodos)
190
+
191
+ await init({
192
+ database: {
193
+ name: 'TodoApp',
194
+ version: 1,
195
+ stores: [
196
+ {
197
+ name: 'todos',
198
+ indexes: [
199
+ { name: 'due_by' },
200
+ ],
201
+ },
202
+ ],
203
+ },
204
+ network: {
205
+ pingUrl: 'https://example.com/ping',
206
+ },
207
+ })
208
+
209
+ ///// Using within the application /////
210
+
211
+ await todo().hydrate({ name: 'Clean room', due_by: '2025-01-01' }).save()
212
+ ```
213
+ #### TypeScript
214
+ ```typescript
215
+ import { init, subscribe, Model, network, WAKIT_READY, NETWORK_RECONNECTED } from '@wakit/core'
216
+ import type { Resource } from '@wakit/core'
217
+
218
+ interface TodoResource extends Resource {
219
+ name: string;
220
+ due_by: string;
221
+ }
222
+
223
+ class Todo extends Model<TodoResource> {
224
+ public name?: string;
225
+ public due_by?: string;
226
+
227
+ storeName(): string {
228
+ return 'todos'
229
+ }
230
+ }
231
+
232
+ const todo = () => (new Todo)
233
+
234
+ const syncTodos = async () => {
235
+ const todos = await network.get<TodoResource[]>('/todos')
236
+
237
+ for (const data of todos ?? []) {
238
+ await todo().hydrate(data).save()
239
+ }
240
+ }
241
+
242
+ subscribe(WAKIT_READY, syncTodos)
243
+ subscribe(NETWORK_RECONNECTED, syncTodos)
244
+
245
+ await init({
246
+ database: {
247
+ name: 'TodoApp',
248
+ version: 1,
249
+ stores: [
250
+ {
251
+ name: 'todos',
252
+ indexes: [
253
+ { name: 'due_by' },
254
+ ],
255
+ },
256
+ ],
257
+ },
258
+ network: {
259
+ pingUrl: 'https://example.com/ping',
260
+ },
261
+ })
262
+
263
+ ///// Using within the application /////
264
+
265
+ await todo().hydrate({ name: 'Clean room', due_by: '2025-01-01' }).save()
266
+ ```
@@ -0,0 +1,4 @@
1
+ import tseslint from 'typescript-eslint';
2
+ declare const _default: tseslint.FlatConfig.ConfigArray;
3
+ export default _default;
4
+ //# sourceMappingURL=eslint.config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eslint.config.d.ts","sourceRoot":"","sources":["../eslint.config.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,mBAAmB,CAAA;;AAExC,wBAoBC"}
@@ -0,0 +1,20 @@
1
+ import tseslint from 'typescript-eslint';
2
+ export default tseslint.config({
3
+ ignores: ['dist/**'],
4
+ }, {
5
+ files: ['**/*.ts'],
6
+ extends: [tseslint.configs.base],
7
+ rules: {
8
+ 'space-unary-ops': ['error', { words: true, nonwords: false, overrides: { '!': true } }],
9
+ 'quotes': ['error', 'single', { avoidEscape: true, allowTemplateLiterals: true }],
10
+ 'semi': ['error', 'never'],
11
+ 'indent': ['error', 2, { SwitchCase: 1, ignoredNodes: ['CallExpression > ObjectExpression', 'CallExpression > ObjectExpression *', 'CallExpression > ArrowFunctionExpression > BlockStatement', 'CallExpression > ArrowFunctionExpression > BlockStatement *'] }],
12
+ 'no-var': 'error',
13
+ 'prefer-const': 'error',
14
+ 'space-before-blocks': 'error',
15
+ 'arrow-spacing': 'error',
16
+ 'spaced-comment': ['error', 'always'],
17
+ 'curly': ['error', 'all'],
18
+ },
19
+ });
20
+ //# sourceMappingURL=eslint.config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eslint.config.js","sourceRoot":"","sources":["../eslint.config.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,mBAAmB,CAAA;AAExC,eAAe,QAAQ,CAAC,MAAM,CAC5B;IACE,OAAO,EAAE,CAAC,SAAS,CAAC;CACrB,EACD;IACE,KAAK,EAAE,CAAC,SAAS,CAAC;IAClB,OAAO,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC;IAChC,KAAK,EAAE;QACL,iBAAiB,EAAE,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC;QACxF,QAAQ,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAAC;QACjF,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC;QAC1B,QAAQ,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,mCAAmC,EAAE,qCAAqC,EAAE,2DAA2D,EAAE,6DAA6D,CAAC,EAAE,CAAC;QACjQ,QAAQ,EAAE,OAAO;QACjB,cAAc,EAAE,OAAO;QACvB,qBAAqB,EAAE,OAAO;QAC9B,eAAe,EAAE,OAAO;QACxB,gBAAgB,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC;QACrC,OAAO,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC;KAC1B;CACF,CACF,CAAA"}
@@ -0,0 +1,14 @@
1
+ import type { IEvent } from '@wakit/events';
2
+ export declare const NETWORK_OFFLINE: IEvent;
3
+ export declare const NETWORK_ONLINE: IEvent;
4
+ export declare const NETWORK_DISCONNECTED: IEvent;
5
+ export declare const NETWORK_RECONNECTED: IEvent;
6
+ export declare const NETWORK_SLOW_CONNECTION: IEvent;
7
+ export declare const NETWORK_HANDLED_ERROR: IEvent;
8
+ export declare const DATABASE_READY: IEvent;
9
+ export declare const DATABASE_INIT_ERROR: IEvent;
10
+ export declare const DATABASE_BLOCKED: IEvent;
11
+ export declare const DATABASE_VERSION_CHANGE: IEvent;
12
+ export declare const MODEL_OPERATION_ERROR: IEvent;
13
+ export declare const WAKIT_READY: IEvent;
14
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAE3C,eAAO,MAAM,eAAe,EAAE,MAAgC,CAAA;AAC9D,eAAO,MAAM,cAAc,EAAE,MAA+B,CAAA;AAC5D,eAAO,MAAM,oBAAoB,EAAE,MAAqC,CAAA;AACxE,eAAO,MAAM,mBAAmB,EAAE,MAAoC,CAAA;AACtE,eAAO,MAAM,uBAAuB,EAAE,MAAwC,CAAA;AAE9E,eAAO,MAAM,qBAAqB,EAAE,MAAsC,CAAA;AAE1E,eAAO,MAAM,cAAc,EAAE,MAA+B,CAAA;AAC5D,eAAO,MAAM,mBAAmB,EAAE,MAAoC,CAAA;AACtE,eAAO,MAAM,gBAAgB,EAAE,MAAiC,CAAA;AAChE,eAAO,MAAM,uBAAuB,EAAE,MAAwC,CAAA;AAC9E,eAAO,MAAM,qBAAqB,EAAE,MAAsC,CAAA;AAE1E,eAAO,MAAM,WAAW,EAAE,MAAsB,CAAA"}
package/dist/events.js ADDED
@@ -0,0 +1,13 @@
1
+ export const NETWORK_OFFLINE = 'wakit:network:offline';
2
+ export const NETWORK_ONLINE = 'wakit:network:online';
3
+ export const NETWORK_DISCONNECTED = 'wakit:network:disconnected';
4
+ export const NETWORK_RECONNECTED = 'wakit:network:reconnected';
5
+ export const NETWORK_SLOW_CONNECTION = 'wakit:network:slow_connection';
6
+ export const NETWORK_HANDLED_ERROR = 'wakit:network:handled_error';
7
+ export const DATABASE_READY = 'wakit:database:ready';
8
+ export const DATABASE_INIT_ERROR = 'wakit:database:init_error';
9
+ export const DATABASE_BLOCKED = 'wakit:database:blocked';
10
+ export const DATABASE_VERSION_CHANGE = 'wakit:database:version_change';
11
+ export const MODEL_OPERATION_ERROR = 'wakit:model:operation_error';
12
+ export const WAKIT_READY = 'wakit:ready';
13
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../events.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAAW,uBAAuB,CAAA;AAC9D,MAAM,CAAC,MAAM,cAAc,GAAW,sBAAsB,CAAA;AAC5D,MAAM,CAAC,MAAM,oBAAoB,GAAW,4BAA4B,CAAA;AACxE,MAAM,CAAC,MAAM,mBAAmB,GAAW,2BAA2B,CAAA;AACtE,MAAM,CAAC,MAAM,uBAAuB,GAAW,+BAA+B,CAAA;AAE9E,MAAM,CAAC,MAAM,qBAAqB,GAAW,6BAA6B,CAAA;AAE1E,MAAM,CAAC,MAAM,cAAc,GAAW,sBAAsB,CAAA;AAC5D,MAAM,CAAC,MAAM,mBAAmB,GAAW,2BAA2B,CAAA;AACtE,MAAM,CAAC,MAAM,gBAAgB,GAAW,wBAAwB,CAAA;AAChE,MAAM,CAAC,MAAM,uBAAuB,GAAW,+BAA+B,CAAA;AAC9E,MAAM,CAAC,MAAM,qBAAqB,GAAW,6BAA6B,CAAA;AAE1E,MAAM,CAAC,MAAM,WAAW,GAAW,aAAa,CAAA"}
@@ -0,0 +1,21 @@
1
+ import type { WaormDatabaseConfig } from '@wakit/waorm';
2
+ import type { ToastSystem } from '@wakit/networker';
3
+ export type * from '@wakit/waorm';
4
+ export type * from '@wakit/events';
5
+ export { Model, collect, generateNewSlug, generateNewId, isDirty, isNew, isInstance } from '@wakit/waorm';
6
+ export { dispatch, dispatchFor, subscribe, unsubscribe, unsubscribeGroup } from '@wakit/events';
7
+ export { network } from '@wakit/networker';
8
+ export * from './events.js';
9
+ export interface WakitConfig {
10
+ database?: WaormDatabaseConfig<IDBDatabase>;
11
+ toast?: ToastSystem;
12
+ network?: {
13
+ pingUrl: string;
14
+ };
15
+ debug?: boolean;
16
+ }
17
+ declare const wait: (timeout?: number) => Promise<void>;
18
+ declare const waitForWakit: () => Promise<void>;
19
+ declare const init: (config: WakitConfig) => Promise<void>;
20
+ export { wait, init, waitForWakit, };
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAkCnD,mBAAmB,cAAc,CAAA;AACjC,mBAAmB,eAAe,CAAA;AAElC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzG,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAC/F,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAE1C,cAAc,aAAa,CAAA;AAE3B,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;IAC5C,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,OAAO,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;KAAE,CAAC;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAkBD,QAAA,MAAM,IAAI,GAAS,gBAAc,kBAEhC,CAAA;AAED,QAAA,MAAM,YAAY,qBASjB,CAAA;AAED,QAAA,MAAM,IAAI,GAAU,QAAQ,WAAW,kBAyCtC,CAAA;AAED,OAAO,EACL,IAAI,EACJ,IAAI,EACJ,YAAY,GACb,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,72 @@
1
+ import { dispatch } from '@wakit/events';
2
+ import { initDB, onDatabaseBlocked, onDatabaseInitError, onDatabaseVersionChange, onModelOperationError, } from '@wakit/waorm';
3
+ import { network, onNetworkDisconnected, onNetworkOffline, onNetworkOnline, onNetworkReconnected, onNetworkSlowConnection, setPingUrl, } from '@wakit/networker';
4
+ import { NETWORK_ONLINE, NETWORK_OFFLINE, NETWORK_RECONNECTED, NETWORK_DISCONNECTED, NETWORK_SLOW_CONNECTION, NETWORK_HANDLED_ERROR, DATABASE_READY, DATABASE_INIT_ERROR, DATABASE_BLOCKED, DATABASE_VERSION_CHANGE, MODEL_OPERATION_ERROR, WAKIT_READY, } from './events.js';
5
+ export { Model, collect, generateNewSlug, generateNewId, isDirty, isNew, isInstance } from '@wakit/waorm';
6
+ export { dispatch, dispatchFor, subscribe, unsubscribe, unsubscribeGroup } from '@wakit/events';
7
+ export { network } from '@wakit/networker';
8
+ export * from './events.js';
9
+ let initializing = false;
10
+ let initialized = false;
11
+ let debug = false;
12
+ const log = (message) => {
13
+ if (debug) {
14
+ console.debug(`[wakit] ${message}`);
15
+ }
16
+ };
17
+ // registered once at load, before any initDB: init error / blocked fire during setup
18
+ onDatabaseInitError((error) => dispatch(DATABASE_INIT_ERROR, error));
19
+ onDatabaseBlocked((context) => dispatch(DATABASE_BLOCKED, context));
20
+ onDatabaseVersionChange((context) => dispatch(DATABASE_VERSION_CHANGE, context));
21
+ onModelOperationError((error) => dispatch(MODEL_OPERATION_ERROR, error));
22
+ const wait = async (timeout = 1000) => {
23
+ await new Promise((resolve) => setTimeout(() => resolve(), timeout));
24
+ };
25
+ const waitForWakit = async () => {
26
+ let steps = 0;
27
+ while (!initialized && steps++ < 200) {
28
+ await wait(10);
29
+ }
30
+ if (!initialized) {
31
+ throw new Error('Timeout while waiting. Failed to initialize Wakit');
32
+ }
33
+ };
34
+ const init = async (config) => {
35
+ if (initializing || initialized) {
36
+ return;
37
+ }
38
+ initializing = true;
39
+ debug = config.debug ?? false;
40
+ if (config.database) {
41
+ log('starting database config');
42
+ try {
43
+ await initDB(config.database);
44
+ }
45
+ catch (err) {
46
+ initializing = false;
47
+ throw err;
48
+ }
49
+ dispatch(DATABASE_READY);
50
+ }
51
+ log('setting up network');
52
+ network.config({
53
+ onHandledError: (error) => dispatch(NETWORK_HANDLED_ERROR, error),
54
+ toast: config.toast,
55
+ handleErrors: true,
56
+ checkInternetConnection: !!config.network?.pingUrl,
57
+ });
58
+ if (!!config.network?.pingUrl) {
59
+ setPingUrl(config.network.pingUrl);
60
+ }
61
+ onNetworkOnline(() => dispatch(NETWORK_ONLINE));
62
+ onNetworkOffline(() => dispatch(NETWORK_OFFLINE));
63
+ onNetworkReconnected(() => dispatch(NETWORK_RECONNECTED));
64
+ onNetworkDisconnected(() => dispatch(NETWORK_DISCONNECTED));
65
+ onNetworkSlowConnection(() => dispatch(NETWORK_SLOW_CONNECTION));
66
+ initializing = false;
67
+ initialized = true;
68
+ log('ready');
69
+ dispatch(WAKIT_READY);
70
+ };
71
+ export { wait, init, waitForWakit, };
72
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import tseslint from 'typescript-eslint'
2
+
3
+ export default tseslint.config(
4
+ {
5
+ ignores: ['dist/**'],
6
+ },
7
+ {
8
+ files: ['**/*.ts'],
9
+ extends: [tseslint.configs.base],
10
+ rules: {
11
+ 'space-unary-ops': ['error', { words: true, nonwords: false, overrides: { '!': true } }],
12
+ 'quotes': ['error', 'single', { avoidEscape: true, allowTemplateLiterals: true }],
13
+ 'semi': ['error', 'never'],
14
+ 'indent': ['error', 2, { SwitchCase: 1, ignoredNodes: ['CallExpression > ObjectExpression', 'CallExpression > ObjectExpression *', 'CallExpression > ArrowFunctionExpression > BlockStatement', 'CallExpression > ArrowFunctionExpression > BlockStatement *'] }],
15
+ 'no-var': 'error',
16
+ 'prefer-const': 'error',
17
+ 'space-before-blocks': 'error',
18
+ 'arrow-spacing': 'error',
19
+ 'spaced-comment': ['error', 'always'],
20
+ 'curly': ['error', 'all'],
21
+ },
22
+ },
23
+ )
package/events.ts ADDED
@@ -0,0 +1,17 @@
1
+ import type { IEvent } from '@wakit/events'
2
+
3
+ export const NETWORK_OFFLINE: IEvent = 'wakit:network:offline'
4
+ export const NETWORK_ONLINE: IEvent = 'wakit:network:online'
5
+ export const NETWORK_DISCONNECTED: IEvent = 'wakit:network:disconnected'
6
+ export const NETWORK_RECONNECTED: IEvent = 'wakit:network:reconnected'
7
+ export const NETWORK_SLOW_CONNECTION: IEvent = 'wakit:network:slow_connection'
8
+
9
+ export const NETWORK_HANDLED_ERROR: IEvent = 'wakit:network:handled_error'
10
+
11
+ export const DATABASE_READY: IEvent = 'wakit:database:ready'
12
+ export const DATABASE_INIT_ERROR: IEvent = 'wakit:database:init_error'
13
+ export const DATABASE_BLOCKED: IEvent = 'wakit:database:blocked'
14
+ export const DATABASE_VERSION_CHANGE: IEvent = 'wakit:database:version_change'
15
+ export const MODEL_OPERATION_ERROR: IEvent = 'wakit:model:operation_error'
16
+
17
+ export const WAKIT_READY: IEvent = 'wakit:ready'
package/index.ts ADDED
@@ -0,0 +1,130 @@
1
+ import type { WaormDatabaseConfig } from '@wakit/waorm'
2
+ import type { ToastSystem } from '@wakit/networker'
3
+ import { dispatch} from '@wakit/events'
4
+ import {
5
+ initDB,
6
+ onDatabaseBlocked,
7
+ onDatabaseInitError,
8
+ onDatabaseVersionChange,
9
+ onModelOperationError,
10
+ } from '@wakit/waorm'
11
+ import {
12
+ network,
13
+ onNetworkDisconnected,
14
+ onNetworkOffline,
15
+ onNetworkOnline,
16
+ onNetworkReconnected,
17
+ onNetworkSlowConnection,
18
+ setPingUrl,
19
+ } from '@wakit/networker'
20
+
21
+ import {
22
+ NETWORK_ONLINE,
23
+ NETWORK_OFFLINE,
24
+ NETWORK_RECONNECTED,
25
+ NETWORK_DISCONNECTED,
26
+ NETWORK_SLOW_CONNECTION,
27
+ NETWORK_HANDLED_ERROR,
28
+ DATABASE_READY,
29
+ DATABASE_INIT_ERROR,
30
+ DATABASE_BLOCKED,
31
+ DATABASE_VERSION_CHANGE,
32
+ MODEL_OPERATION_ERROR,
33
+ WAKIT_READY,
34
+ } from './events.js'
35
+
36
+ export type * from '@wakit/waorm'
37
+ export type * from '@wakit/events'
38
+
39
+ export { Model, collect, generateNewSlug, generateNewId, isDirty, isNew, isInstance } from '@wakit/waorm'
40
+ export { dispatch, dispatchFor, subscribe, unsubscribe, unsubscribeGroup } from '@wakit/events'
41
+ export { network } from '@wakit/networker'
42
+
43
+ export * from './events.js'
44
+
45
+ export interface WakitConfig {
46
+ database?: WaormDatabaseConfig<IDBDatabase>,
47
+ toast?: ToastSystem,
48
+ network?: { pingUrl: string; };
49
+ debug?: boolean;
50
+ }
51
+
52
+ let initializing = false
53
+ let initialized = false
54
+ let debug = false
55
+
56
+ const log = (message: string) => {
57
+ if (debug) {
58
+ console.debug(`[wakit] ${message}`)
59
+ }
60
+ }
61
+
62
+ // registered once at load, before any initDB: init error / blocked fire during setup
63
+ onDatabaseInitError((error: unknown) => dispatch(DATABASE_INIT_ERROR, error))
64
+ onDatabaseBlocked((context: unknown) => dispatch(DATABASE_BLOCKED, context))
65
+ onDatabaseVersionChange((context: unknown) => dispatch(DATABASE_VERSION_CHANGE, context))
66
+ onModelOperationError((error: unknown) => dispatch(MODEL_OPERATION_ERROR, error))
67
+
68
+ const wait = async(timeout = 1000) => {
69
+ await new Promise<void>((resolve) => setTimeout(() => resolve(), timeout))
70
+ }
71
+
72
+ const waitForWakit = async() => {
73
+ let steps = 0
74
+ while (! initialized && steps++ < 200) {
75
+ await wait(10)
76
+ }
77
+
78
+ if (! initialized) {
79
+ throw new Error('Timeout while waiting. Failed to initialize Wakit')
80
+ }
81
+ }
82
+
83
+ const init = async (config: WakitConfig) => {
84
+ if (initializing || initialized) {
85
+ return
86
+ }
87
+
88
+ initializing = true
89
+ debug = config.debug ?? false
90
+
91
+ if (config.database) {
92
+ log('starting database config')
93
+ try {
94
+ await initDB(config.database)
95
+ } catch (err) {
96
+ initializing = false
97
+ throw err
98
+ }
99
+ dispatch(DATABASE_READY)
100
+ }
101
+
102
+ log('setting up network')
103
+ network.config({
104
+ onHandledError: (error) => dispatch(NETWORK_HANDLED_ERROR, error),
105
+ toast: config.toast,
106
+ handleErrors: true,
107
+ checkInternetConnection: !! config.network?.pingUrl,
108
+ })
109
+
110
+ if (!! config.network?.pingUrl) {
111
+ setPingUrl(config.network.pingUrl)
112
+ }
113
+
114
+ onNetworkOnline(() => dispatch(NETWORK_ONLINE))
115
+ onNetworkOffline(() => dispatch(NETWORK_OFFLINE))
116
+ onNetworkReconnected(() => dispatch(NETWORK_RECONNECTED))
117
+ onNetworkDisconnected(() => dispatch(NETWORK_DISCONNECTED))
118
+ onNetworkSlowConnection(() => dispatch(NETWORK_SLOW_CONNECTION))
119
+
120
+ initializing = false
121
+ initialized = true
122
+ log('ready')
123
+ dispatch(WAKIT_READY)
124
+ }
125
+
126
+ export {
127
+ wait,
128
+ init,
129
+ waitForWakit,
130
+ }
package/package.json CHANGED
@@ -1,6 +1,37 @@
1
- {
2
- "name": "@wakit/core",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
1
+ {
2
+ "name": "@wakit/core",
3
+ "version": "0.1.0",
4
+ "main": "dist/index.js",
5
+ "types": "dist/index.d.ts",
6
+ "type": "module",
7
+ "files": [
8
+ "dist",
9
+ "**/*.ts",
10
+ "!tests/*"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "test": "echo \"Error: no test specified\" && exit 1",
15
+ "lint": "eslint .",
16
+ "typecheck": "tsc --noEmit"
17
+ },
18
+ "keywords": [
19
+ "pwa",
20
+ "webapps"
21
+ ],
22
+ "author": "Joao Matos",
23
+ "license": "MIT",
24
+ "description": "Set of tools for creating Web Applications",
25
+ "devDependencies": {
26
+ "@types/node": "^25.0.3",
27
+ "eslint": "^10.12.0",
28
+ "jiti": "^2.7.0",
29
+ "typescript": "^6.0.3",
30
+ "typescript-eslint": "^8.71.1"
31
+ },
32
+ "dependencies": {
33
+ "@wakit/events": "^1.1.0",
34
+ "@wakit/networker": "^1.2.1",
35
+ "@wakit/waorm": "^1.3.0"
36
+ }
37
+ }