dolphin-server-modules 2.11.7 → 2.11.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/DOLPHIN_MASTER_GUIDE_NEPALI.md +169 -21
- package/README.md +150 -106
- package/TUTORIAL_NEPALI.md +37 -1
- package/dist/client.test.js +11 -0
- package/dist/client.test.js.map +1 -1
- package/dist/demo-server.js +44 -0
- package/dist/demo-server.js.map +1 -1
- package/dist/gateway/gateway.d.ts +29 -0
- package/dist/gateway/gateway.js +119 -0
- package/dist/gateway/gateway.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/rpc/rpc.d.ts +38 -0
- package/dist/rpc/rpc.js +138 -0
- package/dist/rpc/rpc.js.map +1 -0
- package/dist/rpc/rpc.test.d.ts +1 -0
- package/dist/rpc/rpc.test.js +39 -0
- package/dist/rpc/rpc.test.js.map +1 -0
- package/dist/utils/adapters.d.ts +14 -0
- package/dist/utils/adapters.js +116 -0
- package/dist/utils/adapters.js.map +1 -0
- package/package.json +1 -1
- package/scripts/client.js +135 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Adapters for Express and Fastify
|
|
3
|
+
* Maps native requests/responses to Dolphin's standard ctx structure.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Express Adapter
|
|
7
|
+
* Maps (req, res, next) to Dolphin's standard ctx structure.
|
|
8
|
+
*/
|
|
9
|
+
export declare function toExpress(handler: Function): (req: any, res: any, next: any) => Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* Fastify Adapter
|
|
12
|
+
* Maps (request, reply) to Dolphin's standard ctx structure.
|
|
13
|
+
*/
|
|
14
|
+
export declare function toFastify(handler: Function): (request: any, reply: any) => Promise<void>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Adapters for Express and Fastify
|
|
3
|
+
* Maps native requests/responses to Dolphin's standard ctx structure.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Express Adapter
|
|
7
|
+
* Maps (req, res, next) to Dolphin's standard ctx structure.
|
|
8
|
+
*/
|
|
9
|
+
export function toExpress(handler) {
|
|
10
|
+
return async (req, res, next) => {
|
|
11
|
+
let pendingStatus = 200;
|
|
12
|
+
const ctx = {
|
|
13
|
+
req,
|
|
14
|
+
res,
|
|
15
|
+
params: req.params || {},
|
|
16
|
+
query: req.query || {},
|
|
17
|
+
body: req.body || {},
|
|
18
|
+
state: res.locals || {},
|
|
19
|
+
json: (data, status) => {
|
|
20
|
+
const finalStatus = status !== undefined ? status : pendingStatus;
|
|
21
|
+
res.status(finalStatus).json(data);
|
|
22
|
+
return ctx;
|
|
23
|
+
},
|
|
24
|
+
text: (data, status) => {
|
|
25
|
+
const finalStatus = status !== undefined ? status : pendingStatus;
|
|
26
|
+
res.status(finalStatus).send(String(data));
|
|
27
|
+
return ctx;
|
|
28
|
+
},
|
|
29
|
+
html: (data, status) => {
|
|
30
|
+
const finalStatus = status !== undefined ? status : pendingStatus;
|
|
31
|
+
res.status(finalStatus).send(String(data));
|
|
32
|
+
return ctx;
|
|
33
|
+
},
|
|
34
|
+
status: (code) => {
|
|
35
|
+
pendingStatus = code;
|
|
36
|
+
return ctx;
|
|
37
|
+
},
|
|
38
|
+
setHeader: (name, value) => {
|
|
39
|
+
res.setHeader(name, value);
|
|
40
|
+
return ctx;
|
|
41
|
+
},
|
|
42
|
+
getHeader: (name) => {
|
|
43
|
+
return req.headers[name.toLowerCase()];
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
try {
|
|
47
|
+
// If the handler is a middleware and takes next
|
|
48
|
+
if (handler.length >= 2) {
|
|
49
|
+
await handler(ctx, next);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
const result = await handler(ctx);
|
|
53
|
+
// If the handler returned a response directly instead of calling ctx.json()
|
|
54
|
+
if (result !== undefined && result !== null && !res.headersSent) {
|
|
55
|
+
ctx.json(result);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
next(err);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Fastify Adapter
|
|
66
|
+
* Maps (request, reply) to Dolphin's standard ctx structure.
|
|
67
|
+
*/
|
|
68
|
+
export function toFastify(handler) {
|
|
69
|
+
return async (request, reply) => {
|
|
70
|
+
let pendingStatus = 200;
|
|
71
|
+
const ctx = {
|
|
72
|
+
req: request.raw,
|
|
73
|
+
res: reply.raw,
|
|
74
|
+
params: request.params || {},
|
|
75
|
+
query: request.query || {},
|
|
76
|
+
body: request.body || {},
|
|
77
|
+
state: request.state || {},
|
|
78
|
+
json: (data, status) => {
|
|
79
|
+
const finalStatus = status !== undefined ? status : pendingStatus;
|
|
80
|
+
reply.status(finalStatus).send(data);
|
|
81
|
+
return ctx;
|
|
82
|
+
},
|
|
83
|
+
text: (data, status) => {
|
|
84
|
+
const finalStatus = status !== undefined ? status : pendingStatus;
|
|
85
|
+
reply.status(finalStatus).type('text/plain').send(String(data));
|
|
86
|
+
return ctx;
|
|
87
|
+
},
|
|
88
|
+
html: (data, status) => {
|
|
89
|
+
const finalStatus = status !== undefined ? status : pendingStatus;
|
|
90
|
+
reply.status(finalStatus).type('text/html').send(String(data));
|
|
91
|
+
return ctx;
|
|
92
|
+
},
|
|
93
|
+
status: (code) => {
|
|
94
|
+
pendingStatus = code;
|
|
95
|
+
return ctx;
|
|
96
|
+
},
|
|
97
|
+
setHeader: (name, value) => {
|
|
98
|
+
reply.header(name, value);
|
|
99
|
+
return ctx;
|
|
100
|
+
},
|
|
101
|
+
getHeader: (name) => {
|
|
102
|
+
return request.headers[name.toLowerCase()];
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
try {
|
|
106
|
+
const result = await handler(ctx);
|
|
107
|
+
if (result !== undefined && result !== null && !reply.sent) {
|
|
108
|
+
ctx.json(result);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
reply.send(err);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=adapters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapters.js","sourceRoot":"","sources":["../../src/utils/adapters.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/scripts/client.js
CHANGED
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
* @property {number} [chunkSize=65536] — file upload chunk size (bytes)
|
|
53
53
|
* @property {number} [maxReconnect=5] — max WebSocket reconnect attempts
|
|
54
54
|
* @property {boolean} [autoRefreshToken=true] — auto-refresh expired access token
|
|
55
|
+
* @property {boolean} [autoBroadcast=false] — auto-publish non-GET API requests to realtime
|
|
55
56
|
*/
|
|
56
57
|
|
|
57
58
|
// ─── APIHandler ───────────────────────────────────────────────────────────────
|
|
@@ -168,6 +169,13 @@ class APIHandler {
|
|
|
168
169
|
: await response.text();
|
|
169
170
|
|
|
170
171
|
if (!response.ok) throw { status: response.status, data };
|
|
172
|
+
|
|
173
|
+
// Auto Realtime Broadcast (Dual-Execution)
|
|
174
|
+
if (this.client.options.autoBroadcast && method !== 'GET') {
|
|
175
|
+
const topic = path.startsWith('/') ? path.slice(1) : path;
|
|
176
|
+
this.client.publish(topic, { method, payload: body, result: data });
|
|
177
|
+
}
|
|
178
|
+
|
|
171
179
|
return data;
|
|
172
180
|
|
|
173
181
|
} catch (err) {
|
|
@@ -473,6 +481,7 @@ class DolphinClient {
|
|
|
473
481
|
chunkSize: 65536, // 64 KB
|
|
474
482
|
maxReconnect: 5,
|
|
475
483
|
autoRefreshToken: true,
|
|
484
|
+
autoBroadcast: false,
|
|
476
485
|
...options,
|
|
477
486
|
};
|
|
478
487
|
|
|
@@ -505,6 +514,14 @@ class DolphinClient {
|
|
|
505
514
|
this._offlineQueue = [];
|
|
506
515
|
|
|
507
516
|
this.reconnectAttempts = 0;
|
|
517
|
+
|
|
518
|
+
if (typeof window !== 'undefined') {
|
|
519
|
+
if (document.readyState === 'loading') {
|
|
520
|
+
document.addEventListener('DOMContentLoaded', () => this._initDOMBinding());
|
|
521
|
+
} else {
|
|
522
|
+
this._initDOMBinding();
|
|
523
|
+
}
|
|
524
|
+
}
|
|
508
525
|
}
|
|
509
526
|
|
|
510
527
|
/** Save or clear the access token */
|
|
@@ -822,6 +839,124 @@ class DolphinClient {
|
|
|
822
839
|
* @param {function(FileMetadata): void} handler
|
|
823
840
|
*/
|
|
824
841
|
offFileAvailable(handler) { this.fileHandlers.delete(handler); }
|
|
842
|
+
|
|
843
|
+
// ── DOM Binding (Hookless Realtime) ───────────────────────────────────────
|
|
844
|
+
|
|
845
|
+
/** @private */
|
|
846
|
+
_initDOMBinding() {
|
|
847
|
+
if (this._domInitialized) return;
|
|
848
|
+
this._domInitialized = true;
|
|
849
|
+
|
|
850
|
+
// 1. Listen for inputs
|
|
851
|
+
document.addEventListener('input', (e) => {
|
|
852
|
+
if (!e.target || !e.target.getAttribute) return;
|
|
853
|
+
const topic = e.target.getAttribute('data-rt-push');
|
|
854
|
+
if (topic) {
|
|
855
|
+
const payload = { name: e.target.name, value: e.target.value };
|
|
856
|
+
this.pubPush(topic, payload);
|
|
857
|
+
}
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
// 2. Listen for form submits (RT + API)
|
|
861
|
+
document.addEventListener('submit', async (e) => {
|
|
862
|
+
if (!e.target || !e.target.getAttribute) return;
|
|
863
|
+
|
|
864
|
+
const rtTopic = e.target.getAttribute('data-rt-submit');
|
|
865
|
+
const apiTarget = e.target.getAttribute('data-api-submit');
|
|
866
|
+
|
|
867
|
+
if (rtTopic || apiTarget) {
|
|
868
|
+
e.preventDefault();
|
|
869
|
+
const formData = new FormData(e.target);
|
|
870
|
+
const data = Object.fromEntries(formData.entries());
|
|
871
|
+
|
|
872
|
+
if (rtTopic) {
|
|
873
|
+
this.publish(rtTopic, data);
|
|
874
|
+
} else if (apiTarget) {
|
|
875
|
+
const parts = apiTarget.trim().split(' ');
|
|
876
|
+
const method = parts.length > 1 ? parts[0].toUpperCase() : 'POST';
|
|
877
|
+
const path = parts.length > 1 ? parts[1] : parts[0];
|
|
878
|
+
try {
|
|
879
|
+
const result = await this.api.request(method, path, data);
|
|
880
|
+
const resultBind = e.target.getAttribute('data-api-result');
|
|
881
|
+
if (resultBind) this._updateDOM(resultBind, result);
|
|
882
|
+
} catch (err) {
|
|
883
|
+
console.error('[Dolphin] API Submit Error:', err);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
});
|
|
888
|
+
|
|
889
|
+
// 3. Listen for clicks (RT + API)
|
|
890
|
+
document.addEventListener('click', async (e) => {
|
|
891
|
+
if (!e.target || !e.target.closest) return;
|
|
892
|
+
|
|
893
|
+
const rtBtn = e.target.closest('[data-rt-click]');
|
|
894
|
+
const apiBtn = e.target.closest('[data-api-click]');
|
|
895
|
+
|
|
896
|
+
if (rtBtn) {
|
|
897
|
+
const topic = rtBtn.getAttribute('data-rt-click');
|
|
898
|
+
const actionData = rtBtn.getAttribute('data-rt-payload');
|
|
899
|
+
const payload = actionData ? JSON.parse(actionData) : {};
|
|
900
|
+
this.publish(topic, payload);
|
|
901
|
+
} else if (apiBtn) {
|
|
902
|
+
const apiTarget = apiBtn.getAttribute('data-api-click');
|
|
903
|
+
const actionData = apiBtn.getAttribute('data-api-payload');
|
|
904
|
+
const payload = actionData ? JSON.parse(actionData) : null;
|
|
905
|
+
const parts = apiTarget.trim().split(' ');
|
|
906
|
+
const method = parts.length > 1 ? parts[0].toUpperCase() : 'POST';
|
|
907
|
+
const path = parts.length > 1 ? parts[1] : parts[0];
|
|
908
|
+
try {
|
|
909
|
+
const result = await this.api.request(method, path, payload);
|
|
910
|
+
const resultBind = apiBtn.getAttribute('data-api-result');
|
|
911
|
+
if (resultBind) this._updateDOM(resultBind, result);
|
|
912
|
+
} catch (err) {
|
|
913
|
+
console.error('[Dolphin] API Click Error:', err);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
});
|
|
917
|
+
|
|
918
|
+
// 4. Update DOM when RT data arrives
|
|
919
|
+
// Note: Subscribe to all topics ('#') to auto-update DOM bindings
|
|
920
|
+
this.subscribe('#', (payload, topic) => {
|
|
921
|
+
this._updateDOM(topic, payload);
|
|
922
|
+
});
|
|
923
|
+
|
|
924
|
+
// 5. Auto-fetch API GET bindings
|
|
925
|
+
this._scanAndFetchAPIBinds();
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
/** @private */
|
|
929
|
+
async _scanAndFetchAPIBinds() {
|
|
930
|
+
if (typeof document === 'undefined') return;
|
|
931
|
+
const elements = document.querySelectorAll('[data-api-get]');
|
|
932
|
+
for (const el of elements) {
|
|
933
|
+
const path = el.getAttribute('data-api-get');
|
|
934
|
+
if (!path) continue;
|
|
935
|
+
try {
|
|
936
|
+
const result = await this.api.get(path);
|
|
937
|
+
if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') {
|
|
938
|
+
el.value = typeof result === 'object' ? (result.value !== undefined ? result.value : '') : result;
|
|
939
|
+
} else {
|
|
940
|
+
el.innerHTML = typeof result === 'object' ? (result.html || result.text || JSON.stringify(result)) : result;
|
|
941
|
+
}
|
|
942
|
+
} catch(e) {
|
|
943
|
+
console.error('[Dolphin] API Get Error:', e);
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
/** @private */
|
|
949
|
+
_updateDOM(topic, payload) {
|
|
950
|
+
if (typeof document === 'undefined') return;
|
|
951
|
+
const elements = document.querySelectorAll(`[data-rt-bind="${topic}"]`);
|
|
952
|
+
elements.forEach(el => {
|
|
953
|
+
if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') {
|
|
954
|
+
el.value = typeof payload === 'object' ? (payload.value !== undefined ? payload.value : '') : payload;
|
|
955
|
+
} else {
|
|
956
|
+
el.innerHTML = typeof payload === 'object' ? (payload.html || payload.text || JSON.stringify(payload)) : payload;
|
|
957
|
+
}
|
|
958
|
+
});
|
|
959
|
+
}
|
|
825
960
|
}
|
|
826
961
|
|
|
827
962
|
// ─── Exports ──────────────────────────────────────────────────────────────────
|