dolphin-client 1.0.5 → 1.0.9

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/store.d.ts CHANGED
@@ -3,6 +3,8 @@ export declare class DolphinStore {
3
3
  data: Map<string, any>;
4
4
  listeners: Set<any>;
5
5
  subscribed: Set<string>;
6
+ /** @fix: Store unsubscribe functions so destroy() can clean up WS subscriptions (was: subscriptions never removed) */
7
+ _unsubscribers: Map<string, () => void>;
6
8
  /** @param {DolphinClient} client */
7
9
  constructor(client: any);
8
10
  /** @private */
@@ -19,4 +21,9 @@ export declare class DolphinStore {
19
21
  getSnapshot(collection: any): any;
20
22
  /** @private */
21
23
  _notify(): void;
24
+ /**
25
+ * Clean up all WebSocket subscriptions and listeners.
26
+ * Call this when the store is no longer needed to prevent resource leaks.
27
+ */
28
+ destroy(): void;
22
29
  }
package/fulltutorial.md CHANGED
@@ -731,4 +731,239 @@ By marrying the **reactive strength of Dolphin Client** with the **premium desig
731
731
  - **Auto Reconnect Policy**: Dolphin Client has an exponentional backoff reconnect strategy built-in. Set `maxReconnect` options to customize connection retry budgets.
732
732
  - **Graceful Hardware Fallbacks**: Always test your WebRTC systems with receive-only transceivers (`recvonly`) so desktop terminals with no microphoness/cameras can still receive and play signals properly.
733
733
 
734
+ ---
735
+
736
+ ## १६. Universal Backend Frameworks Integration (PHP & Node.js ब्याकइन्ड एकीकरण)
737
+
738
+ Dolphin Client comes with **native out-of-the-box support** for major backend frameworks, including PHP frameworks (CakePHP, WordPress, Laravel) and Node.js backend frameworks (Express, NestJS, Fastify). You do not need to configure any custom ajax headers or write error-handling logic—Dolphin handles it directly!
739
+
740
+ ### १६.१. Automatic CSRF and Nonce Token Injection
741
+ Mutating requests (`POST`, `PUT`, `PATCH`, `DELETE`) are automatically injected with security verification tokens to bypass server-side security checks:
742
+ 1. **Laravel**: Automatically reads standard token `<input type="hidden" name="_token" value="...">` produced by `@csrf` or `csrf-token` meta tags.
743
+ 2. **CakePHP**: Grabs `_csrfToken` hidden input fields or `csrfToken` cookies.
744
+ 3. **WordPress**: Automatically retrieves security nonces from `window.wpApiSettings.nonce` or `<meta name="wp-nonce">` and injects them in `X-WP-Nonce` header.
745
+ 4. **Node.js (CSRF protection)**: Reads standard `XSRF-TOKEN` or `_csrf` cookies/meta tags.
746
+
747
+ Dolphin automatically injects these tokens inside the **Request Headers** (`X-CSRF-Token`, `X-XSRF-TOKEN`, `X-WP-Nonce`) and **Request Payload** (`_csrfToken`, `_token`, `_csrf`) under the hood!
748
+
749
+ ### १६.२. HTTP Method Spoofing (`_method`)
750
+ Traditional HTML forms only support `GET` and `POST`. PHP and Node.js backend routers support HTTP Method Spoofing to process `PUT`, `PATCH`, or `DELETE`.
751
+ If `methodSpoofing: true` is configured in `options`, or a hidden `<input type="hidden" name="_method" value="PUT">` is present in a form:
752
+ - Dolphin Client maps the fetch request method to a `POST`.
753
+ - Attaches the spoofed method as a request header `X-HTTP-Method-Override: PUT` and inside the payload body as `_method: "PUT"`.
754
+
755
+ ### १६.३. Unified Validation Error Parsing
756
+ Different backends output validation errors in different structures. Dolphin Client includes a **Universal Error Adapter** that normalizes all formats into a flat `{ [field]: errorMessage }` object, then automatically publishes them to state `errors/{field}`:
757
+ - **Laravel / Yii Format**: `{ errors: { email: ["Must be valid email"] } }` → `errors/email` is updated.
758
+ - **CakePHP Format**: `{ errors: { email: { _required: "Email is required" } } }` → `errors/email` is updated.
759
+ - **Node.js (Joi/Yup/Express-Validator) Format**: `[ { path: "email", msg: "Invalid email" } ]` → `errors/email` is updated.
760
+
761
+ This means you can display server-side validation errors in HTML instantly with **zero JavaScript**:
762
+ ```html
763
+ <form data-api-submit="POST /users/register">
764
+ <input name="email" />
765
+ <!-- Server-side validation errors show up here instantly! -->
766
+ <span class="error" data-rt-bind="errors/email"></span>
767
+ </form>
768
+ ```
769
+
770
+ ### १६.४. Base Path & Subfolder Resolution
771
+ If your PHP/WordPress application is hosted locally under a subfolder (e.g. `http://localhost/my-wp-site/`), Dolphin Client automatically respects the `<base href="...">` or `<meta name="base-path">` tags to dynamically prefix all relative API targets (e.g., resolving `data-api-get="/api/posts"` to `http://localhost/my-wp-site/api/posts`).
772
+
773
+ ---
774
+
775
+ ## १७. Buildless SPA Architecture: Component Imports & Link Routing
776
+
777
+ Dolphin Client v2.0 empowers you to build pure, lightning-fast **Single Page Applications (SPAs)** using standard static HTML pages (like `home.html`, `about.html`, `product.html`) with **exactly zero lines of manual frontend JS** and **zero compiler/bundler setups!**
778
+
779
+ ### १७.१. Declarative Component Layout Imports (`data-import`)
780
+ Rather than copy-pasting headers, navs, and footers across all HTML pages, you can declare layouts dynamically:
781
+ ```html
782
+ <!-- index.html (Master Layout) -->
783
+ <body>
784
+ <!-- Imports header.html into this container dynamically -->
785
+ <div data-import="components/header.html"></div>
786
+
787
+ <main id="viewport">
788
+ <h1>Page Content</h1>
789
+ </main>
790
+
791
+ <div data-import="components/footer.html"></div>
792
+ </body>
793
+ ```
794
+
795
+ #### Under the Hood:
796
+ - **Promise-Based Caching**: Multiple duplicate imports of the same component (like identical buttons or sidebars) are fetched **exactly once** from the server using concurrent promise resolution.
797
+ - **Recursive Resolution**: Imported files can safely import sub-files (e.g., `header.html` importing `nav.html`).
798
+ - **Circular Check**: Safely breaks circular locks (e.g. layout A importing layout B which imports layout A) and displays an alert.
799
+ - **Reactivity Re-scanning**: Dolphin automatically executes store and DOM binding scans on newly imported HTML components.
800
+
801
+ ### १७.२. Instant SPA Viewport Router (`data-spa`)
802
+ Converts traditional page transitions into a smooth Single Page Application experience by hijacking links:
803
+ ```html
804
+ <!-- Links with data-spa will route dynamically without reloads! -->
805
+ <nav>
806
+ <a href="home.html" data-spa>Home</a>
807
+ <a href="about.html" data-spa>About Us</a>
808
+ <a href="product.html" data-spa>Products</a>
809
+ </nav>
810
+ ```
811
+
812
+ #### Configuration Options (in constructor):
813
+ - **`routerViewport`**: Selector pointing to the container to be replaced (default: `'main, #viewport, body'`).
814
+ - **`routerTransitions`**: Enables a smooth CSS fade transition between viewport changes (default: `true`).
815
+
816
+ ```javascript
817
+ const dolphin = new DolphinModule.DolphinClient(undefined, undefined, {
818
+ routerViewport: '#viewport',
819
+ routerTransitions: true
820
+ });
821
+ ```
822
+
823
+ #### Transition Styles (automatically injected):
824
+ When navigating, Dolphin applies a fading animation by adding `.dolphin-fade-out` and `.dolphin-fade-in` to the viewport, giving your buildless static site a fluid, modern, app-like finish!
825
+
826
+ ---
827
+
828
+ ## १८. Direct React Integration & DolphinStore API (React र DolphinStore एपीआई एकीकरण)
829
+
830
+ Dolphin Client मा भएको **DolphinStore** ले तपाईँलाई क्लाइन्ट-साइड स्टेट र ब्याकइन्ड डेटा कलेक्सनहरू (GET API र real-time WebSocket Syncing) सजिलै व्यवस्थापन गर्न दिन्छ। यसलाई तपाईँले म्यानुअल जाभास्क्रिप्ट कोड वा **React** सँग सजिलै जोड्न सक्नुहुन्छ।
831
+
832
+ ---
833
+
834
+ ### १८.१. DolphinStore JS API
835
+ जब तपाईँ `DolphinClient` इन्स्टन्स सिर्जना गर्नुहुन्छ, `dolphin.store` स्वतः उपलब्ध हुन्छ। कुनै पनि कलेक्सन प्रोपर्टी (जस्तै `store.devices` वा `store.orders`) पहिलो पटक एक्सेस गर्दा, यसले:
836
+ 1. **स्वचालित HTTP Fetch**: `/devices` वा `/orders` मा `GET` रिक्वेस्ट पठाउँछ।
837
+ 2. **स्वचालित WebSocket Sync**: `db:sync/devices` च्यानलमा स्वतः सब्सक्राइब गर्छ र ब्याकइन्डमा कुनै आइटम `create`, `update`, वा `delete` हुँदा कलेक्सन डेटा रियल-टाइम अपडेट गर्छ।
838
+
839
+ #### क) डेटा फिल्टरिङ र सर्टिङ (Filtering & Sorting)
840
+ तपाईँले स्टोर कलेक्सनहरूमा `.where(filterFn)` र `.orderBy(key, direction)` प्रयोग गरेर इन-मेमोरी फिल्टर र सर्ट गर्न सक्नुहुन्छ:
841
+
842
+ ```javascript
843
+ const orders = dolphin.store.orders;
844
+
845
+ // active र total 50 भन्दा बढी भएका अर्डरहरू फिल्टर गरी मूल्यअनुसार सर्ट गर्ने
846
+ const highValueOrders = orders
847
+ .where(o => o.status === 'active' && o.total > 50)
848
+ .orderBy('price', 'desc');
849
+
850
+ console.log("Filtered orders:", highValueOrders.items);
851
+ ```
852
+
853
+ #### ख) म्यानुअल सब्सक्राइब (Manual Subscription & Snapshot)
854
+ ```javascript
855
+ // १. स्टोरमा आउने जुनसुकै अपडेट सुन्न सब्सक्राइब गर्ने
856
+ const unsubscribe = dolphin.store.subscribe(() => {
857
+ const currentOrders = dolphin.store.getSnapshot('orders');
858
+ console.log("Store Updated! Orders:", currentOrders.items);
859
+ });
860
+
861
+ // २. काम सकिएपछि अनसबस्क्राइब गर्ने
862
+ unsubscribe();
863
+ ```
864
+
865
+ ---
866
+
867
+ ### १८.२. Hookless React Integration (क्लास कम्पोनेन्टमा प्रयोग)
868
+ यदि तपाईँ React मा कुनै पनि state hooks (`useState`, `useEffect`) प्रयोग नगरी Dolphin Store सँग सिधै रियल-टाइम डेटा बाइन्ड गर्न चाहनुहुन्छ भने, **React Class Components** सबैभन्दा उत्तम विकल्प हो। यसले React लाई विशुद्ध रूपमा रेन्डरिङ इन्जिन मात्र बनाउँछ:
869
+
870
+ ```jsx
871
+ import React from 'react';
872
+
873
+ class OrderDashboard extends React.Component {
874
+ constructor(props) {
875
+ super(props);
876
+ // १. initial store snapshot स्टेटमा राख्ने
877
+ this.state = {
878
+ orders: window.dolphin.store.getSnapshot('orders')
879
+ };
880
+ }
881
+
882
+ componentDidMount() {
883
+ // २. स्टोर अपडेट हुँदा लोकल स्टेट अपडेट गर्न सब्सक्राइब गर्ने
884
+ this.unsubscribe = window.dolphin.store.subscribe(() => {
885
+ this.setState({
886
+ orders: window.dolphin.store.getSnapshot('orders')
887
+ });
888
+ });
889
+ }
890
+
891
+ componentWillUnmount() {
892
+ // ३. कम्पोनेन्ट अनमाउन्ट हुँदा अनसबस्क्राइब गर्ने
893
+ if (this.unsubscribe) this.unsubscribe();
894
+ }
895
+
896
+ render() {
897
+ const { items, loading, error } = this.state.orders;
898
+
899
+ if (loading) return <div>लोड हुँदैछ...</div>;
900
+ if (error) return <div>त्रुटि: {error}</div>;
901
+
902
+ return (
903
+ <div className="orders-list">
904
+ <h2>रियल-टाइम अर्डरहरू ({items.length})</h2>
905
+ {items.map(order => (
906
+ <div key={order.id} className="order-item">
907
+ <span>अर्डर #{order.id}</span> - <span>रू. {order.amount}</span>
908
+ </div>
909
+ ))}
910
+ </div>
911
+ );
912
+ }
913
+ }
914
+
915
+ export default OrderDashboard;
916
+ ```
917
+
918
+ ---
919
+
920
+ ### १८.३. React Hook Integration using `useSyncExternalStore` (हूक कम्पोनेन्टमा प्रयोग)
921
+ यदि तपाईँ React 18+ को functional components प्रयोग गर्दै हुनुहुन्छ भने, React को आधिकारिक **`useSyncExternalStore`** API को प्रयोग गरेर Dolphin Store लाई विना कुनै अनावश्यक re-render वा state synchronization झन्झट सिधै हूकमा एकीकृत गर्न सक्नुहुन्छ:
922
+
923
+ ```jsx
924
+ import { useSyncExternalStore } from 'react';
925
+
926
+ // custom react hook सिर्जना गर्ने
927
+ function useDolphinCollection(collectionName) {
928
+ const store = window.dolphin.store;
929
+
930
+ // १. external store subscribe गर्ने तरिका
931
+ const subscribe = (onStoreChange) => store.subscribe(onStoreChange);
932
+
933
+ // २. snapshot लिनको लागि getSnapshot
934
+ const getSnapshot = () => store.getSnapshot(collectionName);
935
+
936
+ // React ले यो स्टोर अपडेट हुँदा स्वतः कम्पोनेन्टलाई re-render गराउँछ
937
+ return useSyncExternalStore(subscribe, getSnapshot);
938
+ }
939
+
940
+ // React component मा प्रयोग गर्दा:
941
+ export function UsersList() {
942
+ const { items, loading, error } = useDolphinCollection('users');
943
+
944
+ if (loading) return <p>लोड हुँदैछ...</p>;
945
+ if (error) return <p>त्रुटि भयो: {error}</p>;
946
+
947
+ return (
948
+ <ul>
949
+ {items.map(user => (
950
+ <li key={user.id}>{user.name}</li>
951
+ ))}
952
+ </ul>
953
+ );
954
+ }
955
+ ```
956
+
957
+ ---
958
+
959
+ ### १८.४. Prevent Resource Leaks with `destroy()`
960
+ जब तपाईँको सिंगल पेज वा स्टोर अब प्रयोगमा आउँदैन (जस्तै SPA navigation वा HMR/Hot Reloading को समयमा), स्टोरलाई पूर्ण रूपमा नष्ट गर्न `dolphin.store.destroy()` कल गर्नु आवश्यक हुन्छ। यसले सबै एक्टिभ WebSocket subscriptions र listeners हटाई मेमोरी लिक हुनबाट जोगाउँछ:
961
+
962
+ ```javascript
963
+ // clean up dolphin store
964
+ dolphin.store.destroy();
965
+ ```
966
+
967
+ ---
968
+
734
969
  Enjoy building hookless, lightning-fast, and premium real-time applications with **Dolphin Client**! 🐬
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dolphin-client",
3
- "version": "1.0.5",
3
+ "version": "1.0.9",
4
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
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -13,11 +13,17 @@
13
13
  "require": "./dist/index.cjs"
14
14
  }
15
15
  },
16
+ "bin": {
17
+ "dolphin-client": "./bin/cli.cjs"
18
+ },
16
19
  "files": [
17
20
  "dist",
18
21
  "README.md",
19
22
  "LICENSE",
20
- "fulltutorial.md"
23
+ "fulltutorial.md",
24
+ "scripts",
25
+ ".vscode",
26
+ "bin"
21
27
  ],
22
28
  "scripts": {
23
29
  "build": "npm run build:iife && npm run build:min && npm run build:esm && npm run build:cjs && tsc",
@@ -25,7 +31,8 @@
25
31
  "build:min": "esbuild ./src/index.ts --bundle --minify --outfile=dist/dolphin-client.min.js --format=iife --global-name=DolphinModule",
26
32
  "build:esm": "esbuild ./src/index.ts --bundle --outfile=dist/index.js --format=esm",
27
33
  "build:cjs": "esbuild ./src/index.ts --bundle --outfile=dist/index.cjs --format=cjs",
28
- "test": "jest"
34
+ "test": "jest",
35
+ "postinstall": "node scripts/postinstall.js"
29
36
  },
30
37
  "jest": {
31
38
  "preset": "ts-jest",
@@ -0,0 +1,57 @@
1
+ const path = require('path');
2
+ const fs = require('fs');
3
+
4
+ // This script runs automatically after npm install dolphin-client.
5
+ // It sets up the VS Code Custom HTML Data configuration in the host project's .vscode folder
6
+ // so autocomplete for Dolphin Client attributes works instantly out-of-the-box!
7
+
8
+ try {
9
+ const currentPath = __dirname;
10
+ // Check if we are inside a node_modules folder (production installation)
11
+ if (currentPath.includes('node_modules')) {
12
+ // Resolve host project root (e.g. node_modules/dolphin-client/scripts -> hostRoot)
13
+ const hostRoot = path.resolve(__dirname, '../../..');
14
+ const vscodeDir = path.join(hostRoot, '.vscode');
15
+
16
+ // 1. Ensure the host's .vscode directory exists
17
+ if (!fs.existsSync(vscodeDir)) {
18
+ fs.mkdirSync(vscodeDir, { recursive: true });
19
+ console.log('[Dolphin Client] Created .vscode directory in project root.');
20
+ }
21
+
22
+ // 2. Copy the dolphin-tags.json file to the host's .vscode folder
23
+ const sourceTags = path.resolve(__dirname, '../.vscode/dolphin-tags.json');
24
+ const destTags = path.join(vscodeDir, 'dolphin-tags.json');
25
+ if (fs.existsSync(sourceTags)) {
26
+ fs.copyFileSync(sourceTags, destTags);
27
+ console.log('[Dolphin Client] Copied HTML custom data configuration to .vscode/dolphin-tags.json');
28
+ }
29
+
30
+ // 3. Update the host's settings.json to include the custom data file path
31
+ const settingsPath = path.join(vscodeDir, 'settings.json');
32
+ let settings = {};
33
+ if (fs.existsSync(settingsPath)) {
34
+ try {
35
+ settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
36
+ } catch (e) {
37
+ settings = {};
38
+ }
39
+ }
40
+
41
+ if (!settings['html.customData']) {
42
+ settings['html.customData'] = [];
43
+ }
44
+
45
+ const relativePath = '.vscode/dolphin-tags.json';
46
+ if (!settings['html.customData'].includes(relativePath)) {
47
+ settings['html.customData'].push(relativePath);
48
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
49
+ console.log('[Dolphin Client] Registered dolphin-tags.json in .vscode/settings.json');
50
+ }
51
+
52
+ console.log('\x1b[36m%s\x1b[0m', '🐬 [Dolphin Client] VS Code Autocomplete successfully configured!');
53
+ console.log('\x1b[33m%s\x1b[0m', '👉 Note: Please run "Developer: Reload Window" in VS Code to activate suggestions.');
54
+ }
55
+ } catch (err) {
56
+ console.warn('[Dolphin Client] Failed to auto-configure VS Code autocomplete:', err.message);
57
+ }