dolphin-client 1.0.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.
@@ -0,0 +1,24 @@
1
+ export interface OfflineMutation {
2
+ id?: number;
3
+ method: string;
4
+ path: string;
5
+ payload: any;
6
+ timestamp: number;
7
+ }
8
+ export declare class DolphinOffline {
9
+ client: any;
10
+ db: any;
11
+ isOnline: boolean;
12
+ private memoryCache;
13
+ private memoryMutations;
14
+ constructor(client: any);
15
+ private initDB;
16
+ private setupNetworkListeners;
17
+ getCache(key: string): Promise<any>;
18
+ setCache(key: string, data: any): Promise<void>;
19
+ queueMutation(method: string, path: string, payload: any): Promise<void>;
20
+ getMutations(): Promise<OfflineMutation[]>;
21
+ removeMutation(id: number): Promise<void>;
22
+ syncMutations(): Promise<void>;
23
+ }
24
+ export declare function attachOffline(clientProto: any): void;
package/dist/pwa.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare function attachPwa(clientProto: any): void;
@@ -0,0 +1,22 @@
1
+ export declare class DolphinStore {
2
+ client: any;
3
+ data: Map<string, any>;
4
+ listeners: Set<any>;
5
+ subscribed: Set<string>;
6
+ /** @param {DolphinClient} client */
7
+ constructor(client: any);
8
+ /** @private */
9
+ _getCollection(name: any): any;
10
+ /** @private */
11
+ _fetchAndSync(name: any): Promise<void>;
12
+ /** @private */
13
+ _applyTransform(state: any): void;
14
+ /** @private */
15
+ _handleRemoteUpdate(collection: any, update: any): void;
16
+ /** Subscribe for React useSyncExternalStore */
17
+ subscribe(listener: any): () => boolean;
18
+ /** @param {string} collection */
19
+ getSnapshot(collection: any): any;
20
+ /** @private */
21
+ _notify(): void;
22
+ }
package/dist/store.js ADDED
@@ -0,0 +1,131 @@
1
+ export class DolphinStore {
2
+ /** @param {DolphinClient} client */
3
+ constructor(client) {
4
+ this.client = client;
5
+ /** @type {Map<string, any>} */
6
+ this.data = new Map();
7
+ /** @type {Set<function()>} */
8
+ this.listeners = new Set();
9
+ /** @type {Set<string>} */
10
+ this.subscribed = new Set();
11
+ return new Proxy(this, {
12
+ get: (target, prop) => {
13
+ if (prop in target)
14
+ return target[prop];
15
+ if (typeof prop === 'string')
16
+ return this._getCollection(prop);
17
+ }
18
+ });
19
+ }
20
+ /** @private */
21
+ _getCollection(name) {
22
+ if (!this.data.has(name)) {
23
+ const collection = {
24
+ _rawItems: [],
25
+ items: [],
26
+ loading: true,
27
+ error: null,
28
+ success: false,
29
+ _filter: null,
30
+ _sort: null,
31
+ where: (fn) => {
32
+ collection._filter = fn;
33
+ this._applyTransform(collection);
34
+ return collection;
35
+ },
36
+ orderBy: (key, direction = 'asc') => {
37
+ collection._sort = { key, direction };
38
+ this._applyTransform(collection);
39
+ return collection;
40
+ },
41
+ reset: () => {
42
+ collection._filter = null;
43
+ collection._sort = null;
44
+ this._applyTransform(collection);
45
+ return collection;
46
+ },
47
+ };
48
+ this.data.set(name, collection);
49
+ this._fetchAndSync(name);
50
+ }
51
+ return this.data.get(name);
52
+ }
53
+ /** @private */
54
+ async _fetchAndSync(name) {
55
+ const state = this.data.get(name);
56
+ try {
57
+ const res = await this.client.api.get(`/${name.toLowerCase()}`);
58
+ state._rawItems = Array.isArray(res) ? res : (res.data || []);
59
+ state.loading = false;
60
+ state.success = true;
61
+ state.error = null;
62
+ this._applyTransform(state);
63
+ if (!this.subscribed.has(name)) {
64
+ this.client.subscribe(`db:sync/${name.toLowerCase()}`, (update) => {
65
+ this._handleRemoteUpdate(name, update);
66
+ });
67
+ this.subscribed.add(name);
68
+ }
69
+ }
70
+ catch (e) {
71
+ state.loading = false;
72
+ state.success = false;
73
+ state.error = e.data?.error || e.message || 'Fetch failed';
74
+ this._notify();
75
+ }
76
+ }
77
+ /** @private */
78
+ _applyTransform(state) {
79
+ let result = [...state._rawItems];
80
+ if (state._filter)
81
+ result = result.filter(state._filter);
82
+ if (state._sort) {
83
+ const { key, direction } = state._sort;
84
+ result.sort((a, b) => {
85
+ if (a[key] === b[key])
86
+ return 0;
87
+ return (a[key] > b[key] ? 1 : -1) * (direction === 'asc' ? 1 : -1);
88
+ });
89
+ }
90
+ state.items = result;
91
+ this._notify();
92
+ }
93
+ /** @private */
94
+ _handleRemoteUpdate(collection, update) {
95
+ const state = this.data.get(collection);
96
+ if (!state)
97
+ return;
98
+ const { type, data } = update;
99
+ let items = state._rawItems;
100
+ if (type === 'create') {
101
+ items = [...items, data];
102
+ }
103
+ else if (type === 'update') {
104
+ items = items.map(i => (i.id === data.id || i._id === data._id) ? { ...i, ...data } : i);
105
+ }
106
+ else if (type === 'delete') {
107
+ items = items.filter(i => {
108
+ if (data.id != null && i.id === data.id)
109
+ return false;
110
+ if (data._id != null && i._id === data._id)
111
+ return false;
112
+ return true;
113
+ });
114
+ }
115
+ state._rawItems = items;
116
+ this._applyTransform(state);
117
+ }
118
+ /** Subscribe for React useSyncExternalStore */
119
+ subscribe(listener) {
120
+ this.listeners.add(listener);
121
+ return () => this.listeners.delete(listener);
122
+ }
123
+ /** @param {string} collection */
124
+ getSnapshot(collection) {
125
+ return this.data.get(collection) || { items: [], loading: false, error: null, success: false };
126
+ }
127
+ /** @private */
128
+ _notify() {
129
+ this.listeners.forEach(l => l());
130
+ }
131
+ }
@@ -0,0 +1,20 @@
1
+ export declare class DolphinTestUtils {
2
+ static render(html: string): {
3
+ container: any;
4
+ find: (sel: string) => any;
5
+ fireEvent: (el: any, eventType: string) => void;
6
+ };
7
+ static mockWebSocket(): {
8
+ readyState: number;
9
+ send: (data: string) => void;
10
+ close: jest.Mock<any, any, any>;
11
+ onopen: jest.Mock<any, any, any>;
12
+ onmessage: jest.Mock<any, any, any>;
13
+ onclose: jest.Mock<any, any, any>;
14
+ onerror: jest.Mock<any, any, any>;
15
+ sentMessages: string[];
16
+ };
17
+ static simulateClick(el: any): void;
18
+ static simulateChange(el: any, value: string): void;
19
+ }
20
+ export declare function attachTesting(clientProto: any): void;
@@ -0,0 +1,2 @@
1
+ export declare function validateField(value: string, rulesStr: string, allValues?: Record<string, string>): string | null;
2
+ export declare function attachValidation(clientProto: any): void;
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "dolphin-client",
3
+ "version": "1.0.0",
4
+ "description": "HTML is back! Hookless, framework-agnostic real-time reactive DOM-binding client for Dolphin Server with WebSockets, WebRTC signaling, and offline REST API fallbacks.",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md",
19
+ "LICENSE"
20
+ ],
21
+ "scripts": {
22
+ "build": "npm run build:iife && npm run build:esm && npm run build:cjs && tsc",
23
+ "build:iife": "esbuild ./src/index.ts --bundle --outfile=dist/dolphin-client.js --format=iife --global-name=DolphinModule",
24
+ "build:esm": "esbuild ./src/index.ts --bundle --outfile=dist/index.js --format=esm",
25
+ "build:cjs": "esbuild ./src/index.ts --bundle --outfile=dist/index.cjs --format=cjs",
26
+ "test": "jest"
27
+ },
28
+ "jest": {
29
+ "preset": "ts-jest",
30
+ "testEnvironment": "node"
31
+ },
32
+ "keywords": [
33
+ "dolphin",
34
+ "client",
35
+ "realtime",
36
+ "hookless",
37
+ "reactive",
38
+ "dom-binding",
39
+ "websocket",
40
+ "webrtc",
41
+ "intercom"
42
+ ],
43
+ "author": "Shankar Phuyal",
44
+ "license": "ISC",
45
+ "dependencies": {},
46
+ "devDependencies": {
47
+ "esbuild": "^0.28.0",
48
+ "typescript": "^5.4.3",
49
+ "jest": "^29.7.0",
50
+ "@types/jest": "^29.5.12",
51
+ "ts-jest": "^29.1.2"
52
+ }
53
+ }