@lemoncloud/chatic-sockets-lib 0.3.1 → 0.3.2
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/client-socket-v2/index.d.ts +2 -0
- package/dist/client-socket-v2/index.js +1 -0
- package/dist/client-socket-v2/plans/channel-sync-plan.d.ts +1 -1
- package/dist/client-socket-v2/plans/chat-sync-plan.d.ts +54 -0
- package/dist/client-socket-v2/plans/chat-sync-plan.js +166 -0
- package/dist/lib/channel/types.d.ts +1 -2
- package/dist/lib/chat/types.d.ts +6 -1
- package/dist/lib/chat/views.d.ts +62 -0
- package/dist/lib/chat/views.js +2 -0
- package/package.json +1 -1
- package/dist/modules/chat/model.d.ts +0 -107
- package/dist/modules/chat/model.js +0 -28
- package/dist/modules/chat/types.d.ts +0 -65
- package/dist/modules/chat/types.js +0 -55
- package/dist/modules/chat/views.d.ts +0 -50
- package/dist/modules/chat/views.js +0 -23
- package/dist/modules/sockets/model.d.ts +0 -206
- package/dist/modules/sockets/model.js +0 -28
- package/dist/modules/sockets/types.d.ts +0 -100
- package/dist/modules/sockets/types.js +0 -86
- package/dist/modules/sockets/views.d.ts +0 -67
- package/dist/modules/sockets/views.js +0 -23
|
@@ -18,6 +18,8 @@ export * from './socket-runtime';
|
|
|
18
18
|
export * from './create-device-runtime';
|
|
19
19
|
export * from './plans/device-sync-plan';
|
|
20
20
|
export * from './plans/channel-sync-plan';
|
|
21
|
+
export * from './plans/chat-sync-plan';
|
|
22
|
+
export type { ChatSyncType, ChatSyncData, ChatSyncMessage } from '../lib/chat/types';
|
|
21
23
|
export * from './plans/place-sync-plan';
|
|
22
24
|
export * from './plans/profile-sync-plan';
|
|
23
25
|
export * from './gateways/create-domain-gateway';
|
|
@@ -36,6 +36,7 @@ __exportStar(require("./socket-runtime"), exports);
|
|
|
36
36
|
__exportStar(require("./create-device-runtime"), exports);
|
|
37
37
|
__exportStar(require("./plans/device-sync-plan"), exports);
|
|
38
38
|
__exportStar(require("./plans/channel-sync-plan"), exports);
|
|
39
|
+
__exportStar(require("./plans/chat-sync-plan"), exports);
|
|
39
40
|
__exportStar(require("./plans/place-sync-plan"), exports);
|
|
40
41
|
__exportStar(require("./plans/profile-sync-plan"), exports);
|
|
41
42
|
__exportStar(require("./gateways/create-domain-gateway"), exports);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChannelView } from '../../
|
|
1
|
+
import type { ChannelView } from '../../lib/chat/views';
|
|
2
2
|
import type { SocketMessage } from '../../lib/types';
|
|
3
3
|
import type { DomainSyncContext, DomainSyncPlan, SyncBackoffOptions, SyncFailureInfo, SyncTargetDescriptor } from '../types';
|
|
4
4
|
export interface ChannelSyncTarget extends SyncTargetDescriptor {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { ChatView } from '../../lib/chat/views';
|
|
2
|
+
import type { SocketMessage } from '../../lib/types';
|
|
3
|
+
import type { DomainSyncContext, DomainSyncPlan, SyncBackoffOptions, SyncFailureInfo, SyncTargetDescriptor } from '../types';
|
|
4
|
+
/** Sync target for one channel's chat messages. */
|
|
5
|
+
export interface ChatSyncTarget extends SyncTargetDescriptor {
|
|
6
|
+
type: 'chat';
|
|
7
|
+
}
|
|
8
|
+
/** Applied message window. `lastNo` is the top (next expected is `lastNo + 1`); messages older than `minNo` are left for the app to lazy-load. */
|
|
9
|
+
export interface ChatSyncSnapshot {
|
|
10
|
+
id: string;
|
|
11
|
+
lastNo: number;
|
|
12
|
+
minNo: number;
|
|
13
|
+
messages: ChatView[];
|
|
14
|
+
}
|
|
15
|
+
export interface ChatSyncPlanOptions {
|
|
16
|
+
/** Max messages fetched in one catch-up; anything older is left for the app to lazy-load. Default 50. */
|
|
17
|
+
cap?: number;
|
|
18
|
+
/** Max messages kept in the snapshot window to bound memory; the app holds full history via `onApply`. Default 500. */
|
|
19
|
+
maxMessages?: number;
|
|
20
|
+
idleBackoff?: SyncBackoffOptions;
|
|
21
|
+
/** Called after messages are applied, with the applied delta (ascending) and the new snapshot. */
|
|
22
|
+
onApply?: (target: ChatSyncTarget, applied: ChatView[], snapshot: ChatSyncSnapshot) => void;
|
|
23
|
+
/** Called when the engine stops the target. */
|
|
24
|
+
onRemove?: (target: ChatSyncTarget, previous?: ChatSyncSnapshot) => void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Per-channel chat message sync (append-only events).
|
|
28
|
+
* - `onTrigger` (chat.sync): applies the message payload directly, with no read round-trip on the normal path.
|
|
29
|
+
* - `onConnected`: catches up from `lastNo` to `channel.chatNo` (bounded by `cap`) after a reconnect.
|
|
30
|
+
* - `run`: no-op (event-driven, no polling).
|
|
31
|
+
*/
|
|
32
|
+
export declare class ChatSyncPlan implements DomainSyncPlan<ChatSyncTarget> {
|
|
33
|
+
private readonly options;
|
|
34
|
+
readonly domain = "chat";
|
|
35
|
+
readonly idleBackoff: SyncBackoffOptions;
|
|
36
|
+
private readonly chains;
|
|
37
|
+
constructor(options?: ChatSyncPlanOptions);
|
|
38
|
+
supports: (target: SyncTargetDescriptor) => target is ChatSyncTarget;
|
|
39
|
+
getKey: (target: ChatSyncTarget) => string;
|
|
40
|
+
run: () => Promise<void>;
|
|
41
|
+
onConnected: (target: ChatSyncTarget, ctx: DomainSyncContext) => Promise<void>;
|
|
42
|
+
onTrigger: (target: ChatSyncTarget, message: SocketMessage<any>, ctx: DomainSyncContext) => Promise<void>;
|
|
43
|
+
onStopped: (target: ChatSyncTarget, _info: SyncFailureInfo, ctx: DomainSyncContext) => void;
|
|
44
|
+
updateLocalState: (target: ChatSyncTarget, snapshot: unknown, ctx: DomainSyncContext) => void;
|
|
45
|
+
/** Serialize read-modify-write per channel; the scheduler does not serialize onTrigger. */
|
|
46
|
+
private serialize;
|
|
47
|
+
private readSnap;
|
|
48
|
+
/** Append the contiguous `lastNo + 1 ..` run to the top of the window; gaps and duplicates are skipped. */
|
|
49
|
+
private appendContiguous;
|
|
50
|
+
/** Trim the window to `maxMessages`, dropping the oldest and advancing `minNo`. */
|
|
51
|
+
private clampWindow;
|
|
52
|
+
/** Reconnect/gap fill: collect newest-first, bound by `cap`, apply ascending, then set `lastNo` to `total`. */
|
|
53
|
+
private catchUp;
|
|
54
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.ChatSyncPlan = void 0;
|
|
13
|
+
const num = (v, d = 0) => (typeof v === 'number' && Number.isFinite(v) ? v : d);
|
|
14
|
+
/**
|
|
15
|
+
* Per-channel chat message sync (append-only events).
|
|
16
|
+
* - `onTrigger` (chat.sync): applies the message payload directly, with no read round-trip on the normal path.
|
|
17
|
+
* - `onConnected`: catches up from `lastNo` to `channel.chatNo` (bounded by `cap`) after a reconnect.
|
|
18
|
+
* - `run`: no-op (event-driven, no polling).
|
|
19
|
+
*/
|
|
20
|
+
class ChatSyncPlan {
|
|
21
|
+
constructor(options = {}) {
|
|
22
|
+
var _a;
|
|
23
|
+
this.options = options;
|
|
24
|
+
this.domain = 'chat';
|
|
25
|
+
this.chains = new Map();
|
|
26
|
+
this.supports = (target) => (target === null || target === void 0 ? void 0 : target.type) === 'chat';
|
|
27
|
+
this.getKey = (target) => { var _a; return `chat:${(_a = target === null || target === void 0 ? void 0 : target.id) !== null && _a !== void 0 ? _a : ''}`; };
|
|
28
|
+
this.run = () => __awaiter(this, void 0, void 0, function* () { return undefined; });
|
|
29
|
+
this.onConnected = (target, ctx) => __awaiter(this, void 0, void 0, function* () {
|
|
30
|
+
if (!target.id)
|
|
31
|
+
return;
|
|
32
|
+
// Swallow errors so one channel's catch-up failure cannot break the scheduler's reconnect loop; recovered on the next message or reconnect.
|
|
33
|
+
yield this.serialize(target.id, () => this.catchUp(target, ctx)).catch(() => undefined);
|
|
34
|
+
});
|
|
35
|
+
this.onTrigger = (target, message, ctx) => __awaiter(this, void 0, void 0, function* () {
|
|
36
|
+
var _b;
|
|
37
|
+
if (!target.id)
|
|
38
|
+
return;
|
|
39
|
+
const data = ((message === null || message === void 0 ? void 0 : message.data) || {});
|
|
40
|
+
const channelId = `${(_b = data === null || data === void 0 ? void 0 : data.channelId) !== null && _b !== void 0 ? _b : ''}`;
|
|
41
|
+
if (!channelId || channelId !== target.id)
|
|
42
|
+
return; // ignore other channels
|
|
43
|
+
const no = num(data === null || data === void 0 ? void 0 : data.chatNo, 0);
|
|
44
|
+
if (no <= 0)
|
|
45
|
+
return;
|
|
46
|
+
yield this.serialize(target.id, () => __awaiter(this, void 0, void 0, function* () {
|
|
47
|
+
const snap = this.readSnap(target, ctx);
|
|
48
|
+
if (no <= snap.lastNo)
|
|
49
|
+
return; // duplicate or old
|
|
50
|
+
if (no === snap.lastNo + 1) {
|
|
51
|
+
this.appendContiguous(target, ctx, snap, [data]); // apply payload directly, no feed
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
yield this.catchUp(target, ctx, snap); // gap: fill from the server
|
|
55
|
+
}
|
|
56
|
+
}));
|
|
57
|
+
});
|
|
58
|
+
this.onStopped = (target, _info, ctx) => {
|
|
59
|
+
var _a, _b;
|
|
60
|
+
const prev = ctx.readSnapshot(target);
|
|
61
|
+
if (target.id)
|
|
62
|
+
this.chains.delete(target.id);
|
|
63
|
+
(_b = (_a = this.options).onRemove) === null || _b === void 0 ? void 0 : _b.call(_a, target, prev);
|
|
64
|
+
};
|
|
65
|
+
this.updateLocalState = (target, snapshot, ctx) => {
|
|
66
|
+
const prev = this.readSnap(target, ctx);
|
|
67
|
+
const patch = (snapshot || {});
|
|
68
|
+
ctx.writeSnapshot(target, Object.assign(Object.assign({}, prev), patch));
|
|
69
|
+
};
|
|
70
|
+
/** Reconnect/gap fill: collect newest-first, bound by `cap`, apply ascending, then set `lastNo` to `total`. */
|
|
71
|
+
this.catchUp = (target, ctx, snapIn) => __awaiter(this, void 0, void 0, function* () {
|
|
72
|
+
var _c, _d, _e;
|
|
73
|
+
if (!target.id)
|
|
74
|
+
return;
|
|
75
|
+
const snap = snapIn !== null && snapIn !== void 0 ? snapIn : this.readSnap(target, ctx);
|
|
76
|
+
const input = { id: target.id };
|
|
77
|
+
const channel = yield ctx.client.request('channel.get', input);
|
|
78
|
+
const total = num(channel === null || channel === void 0 ? void 0 : channel.chatNo, 0);
|
|
79
|
+
if (total <= snap.lastNo)
|
|
80
|
+
return; // already latest
|
|
81
|
+
const cap = num(this.options.cap, 50) || 50;
|
|
82
|
+
const floor = Math.max(snap.lastNo, total - cap); // below this is left for lazy-load
|
|
83
|
+
const acc = [];
|
|
84
|
+
let cursor;
|
|
85
|
+
for (let page = 0; page < 64; page += 1) {
|
|
86
|
+
const res = (yield ctx.client.request('chat.feed', Object.assign({ channelId: target.id }, (cursor ? { cursorNo: cursor } : {}))));
|
|
87
|
+
const list = ((_c = res === null || res === void 0 ? void 0 : res.list) !== null && _c !== void 0 ? _c : []);
|
|
88
|
+
let stop = false;
|
|
89
|
+
for (const m of list) {
|
|
90
|
+
const mno = num(m.chatNo, 0);
|
|
91
|
+
if (mno <= floor) {
|
|
92
|
+
stop = true;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
acc.push(m);
|
|
96
|
+
}
|
|
97
|
+
const cn = num(res === null || res === void 0 ? void 0 : res.cursorNo, 0);
|
|
98
|
+
if (stop || cn <= 0 || !list.length)
|
|
99
|
+
break;
|
|
100
|
+
cursor = cn;
|
|
101
|
+
}
|
|
102
|
+
acc.sort((a, b) => num(a.chatNo, 0) - num(b.chatNo, 0));
|
|
103
|
+
if (floor === snap.lastNo) {
|
|
104
|
+
this.appendContiguous(target, ctx, snap, acc); // gap within cap: contiguous extend
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
// Large gap: reset to the newest window and set lastNo to total, which avoids a re-fetch loop.
|
|
108
|
+
const win = this.clampWindow(acc, floor + 1);
|
|
109
|
+
const next = { id: snap.id, lastNo: total, minNo: win.minNo, messages: win.messages };
|
|
110
|
+
ctx.writeSnapshot(target, next);
|
|
111
|
+
(_e = (_d = this.options).onApply) === null || _e === void 0 ? void 0 : _e.call(_d, target, acc, next);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
this.idleBackoff = (_a = options.idleBackoff) !== null && _a !== void 0 ? _a : { factor: 2, maxMs: 60000 };
|
|
115
|
+
}
|
|
116
|
+
// --- internals ---
|
|
117
|
+
/** Serialize read-modify-write per channel; the scheduler does not serialize onTrigger. */
|
|
118
|
+
serialize(key, task) {
|
|
119
|
+
var _a;
|
|
120
|
+
const prev = (_a = this.chains.get(key)) !== null && _a !== void 0 ? _a : Promise.resolve();
|
|
121
|
+
const next = prev.then(task, task);
|
|
122
|
+
this.chains.set(key, next.then(() => undefined, () => undefined));
|
|
123
|
+
return next;
|
|
124
|
+
}
|
|
125
|
+
readSnap(target, ctx) {
|
|
126
|
+
var _a;
|
|
127
|
+
const prev = ctx.readSnapshot(target);
|
|
128
|
+
if (prev)
|
|
129
|
+
return prev;
|
|
130
|
+
return { id: `${(_a = target.id) !== null && _a !== void 0 ? _a : ''}`, lastNo: 0, minNo: 0, messages: [] };
|
|
131
|
+
}
|
|
132
|
+
/** Append the contiguous `lastNo + 1 ..` run to the top of the window; gaps and duplicates are skipped. */
|
|
133
|
+
appendContiguous(target, ctx, snap, ascending) {
|
|
134
|
+
var _a, _b;
|
|
135
|
+
const applied = [];
|
|
136
|
+
const messages = snap.messages.slice();
|
|
137
|
+
let lastNo = snap.lastNo;
|
|
138
|
+
let minNo = snap.minNo;
|
|
139
|
+
for (const m of ascending) {
|
|
140
|
+
const mno = num(m.chatNo, 0);
|
|
141
|
+
if (mno !== lastNo + 1)
|
|
142
|
+
continue;
|
|
143
|
+
messages.push(m);
|
|
144
|
+
lastNo = mno;
|
|
145
|
+
if (minNo === 0)
|
|
146
|
+
minNo = mno;
|
|
147
|
+
applied.push(m);
|
|
148
|
+
}
|
|
149
|
+
if (!applied.length)
|
|
150
|
+
return;
|
|
151
|
+
const win = this.clampWindow(messages, minNo);
|
|
152
|
+
const next = { id: snap.id, lastNo, minNo: win.minNo, messages: win.messages };
|
|
153
|
+
ctx.writeSnapshot(target, next);
|
|
154
|
+
(_b = (_a = this.options).onApply) === null || _b === void 0 ? void 0 : _b.call(_a, target, applied, next);
|
|
155
|
+
}
|
|
156
|
+
/** Trim the window to `maxMessages`, dropping the oldest and advancing `minNo`. */
|
|
157
|
+
clampWindow(messages, minNo) {
|
|
158
|
+
var _a;
|
|
159
|
+
const max = num(this.options.maxMessages, 500) || 500;
|
|
160
|
+
if (messages.length <= max)
|
|
161
|
+
return { messages, minNo };
|
|
162
|
+
const trimmed = messages.slice(messages.length - max);
|
|
163
|
+
return { messages: trimmed, minNo: num((_a = trimmed[0]) === null || _a === void 0 ? void 0 : _a.chatNo, minNo) };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
exports.ChatSyncPlan = ChatSyncPlan;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { InferSocketRequest, SocketRequestMessage } from '../types';
|
|
2
|
-
import type { ChannelStereo } from '
|
|
3
|
-
import type { ChannelView } from '../../modules/chat/views';
|
|
2
|
+
import type { ChannelStereo, ChannelView } from '../chat/views';
|
|
4
3
|
export interface ChannelCreateRequestData {
|
|
5
4
|
stereo: ChannelStereo;
|
|
6
5
|
name?: string;
|
package/dist/lib/chat/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { InferSocketRequest, SocketRequestMessage } from '../types';
|
|
1
|
+
import type { InferSocketRequest, SocketMessage, SocketRequestMessage } from '../types';
|
|
2
|
+
import type { ChatView } from './views';
|
|
2
3
|
export interface ChatSendRequestData {
|
|
3
4
|
channelId: string;
|
|
4
5
|
content: string;
|
|
@@ -77,3 +78,7 @@ export declare type ChatDeleteRequestMessage = SocketRequestMessage<ChatDeleteTy
|
|
|
77
78
|
export declare type ChatGetType = 'chat.get';
|
|
78
79
|
export declare type ChatGetInput = InferSocketRequest<ChatGetType>;
|
|
79
80
|
export declare type ChatGetRequestMessage = SocketRequestMessage<ChatGetType>;
|
|
81
|
+
/** chat.sync — 서버→클라 push(broadcast). data 자체가 append된 메시지(fat payload). nudge 아님. */
|
|
82
|
+
export declare type ChatSyncType = 'chat.sync';
|
|
83
|
+
export declare type ChatSyncData = ChatView;
|
|
84
|
+
export declare type ChatSyncMessage = SocketMessage<ChatSyncData>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `lib/chat/views.ts`
|
|
3
|
+
* - client-safe shared chat-domain views (channel/chat/join).
|
|
4
|
+
* - keep this file free from server-only deps (`modules/*`, `cores`) so the published
|
|
5
|
+
* client SDK declaration build does not pull the chat model graph into its `.d.ts`.
|
|
6
|
+
* - mirrors the model-decoupled `DeviceView` pattern in `lib/device/contracts.ts`.
|
|
7
|
+
*/
|
|
8
|
+
import type { DeviceView } from '../device/contracts';
|
|
9
|
+
export declare type ChannelStereo = '' | 'dm' | 'self' | 'public' | 'private';
|
|
10
|
+
export declare type ChatStereo = 'text' | 'join' | 'leave' | 'system';
|
|
11
|
+
export declare type JoinStereo = '';
|
|
12
|
+
/** chat room state shared across websocket client/server contracts. */
|
|
13
|
+
export interface ChannelView {
|
|
14
|
+
id?: string;
|
|
15
|
+
name?: string;
|
|
16
|
+
stereo?: ChannelStereo;
|
|
17
|
+
desc?: string;
|
|
18
|
+
ownerId?: string;
|
|
19
|
+
/** last chat sequence in this channel */
|
|
20
|
+
chatNo?: number;
|
|
21
|
+
/** joined device ids */
|
|
22
|
+
memberIds?: string[];
|
|
23
|
+
createdAt?: number;
|
|
24
|
+
updatedAt?: number;
|
|
25
|
+
deletedAt?: number;
|
|
26
|
+
/** (linked) owner info */
|
|
27
|
+
readonly owner$?: DeviceView;
|
|
28
|
+
/** (linked) last chat info */
|
|
29
|
+
readonly lastChat$?: ChatView;
|
|
30
|
+
/** (linked) device's channel connection view */
|
|
31
|
+
readonly $join?: JoinView;
|
|
32
|
+
}
|
|
33
|
+
/** message or channel event. */
|
|
34
|
+
export interface ChatView {
|
|
35
|
+
/** id = `${channelId}:${chatNo}` */
|
|
36
|
+
id?: string;
|
|
37
|
+
stereo?: ChatStereo;
|
|
38
|
+
/** channel-local sequence */
|
|
39
|
+
chatNo?: number;
|
|
40
|
+
content?: string;
|
|
41
|
+
contentType?: string;
|
|
42
|
+
channelId?: string;
|
|
43
|
+
ownerId?: string;
|
|
44
|
+
createdAt?: number;
|
|
45
|
+
updatedAt?: number;
|
|
46
|
+
deletedAt?: number;
|
|
47
|
+
}
|
|
48
|
+
/** channel membership and read cursor. */
|
|
49
|
+
export interface JoinView {
|
|
50
|
+
/** id = `${channelId}:${ownerId}` */
|
|
51
|
+
id?: string;
|
|
52
|
+
stereo?: JoinStereo;
|
|
53
|
+
channelId?: string;
|
|
54
|
+
ownerId?: string;
|
|
55
|
+
/** last read chat sequence */
|
|
56
|
+
chatNo?: number;
|
|
57
|
+
/** current joined state for API/view consumers. */
|
|
58
|
+
readonly joined?: boolean;
|
|
59
|
+
createdAt?: number;
|
|
60
|
+
updatedAt?: number;
|
|
61
|
+
deletedAt?: number;
|
|
62
|
+
}
|
package/package.json
CHANGED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `model.ts`
|
|
3
|
-
* - model definitions for chat module.
|
|
4
|
-
*/
|
|
5
|
-
import { CoreModel } from 'lemon-model';
|
|
6
|
-
import $LUT, { ChannelStereo, ChatStereo, JoinStereo } from './types';
|
|
7
|
-
/**
|
|
8
|
-
* type: `ModelType`
|
|
9
|
-
*/
|
|
10
|
-
export declare type ModelType = keyof typeof $LUT.ModelType;
|
|
11
|
-
/**
|
|
12
|
-
* type: `Model`: common model
|
|
13
|
-
*/
|
|
14
|
-
export declare type Model = CoreModel<ModelType>;
|
|
15
|
-
/**
|
|
16
|
-
* interface: `ChannelHead`
|
|
17
|
-
*/
|
|
18
|
-
export interface ChannelHead {
|
|
19
|
-
/** id of channel */
|
|
20
|
-
id?: string;
|
|
21
|
-
/** name of channel */
|
|
22
|
-
name?: string;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* interface: `ChannelModel`
|
|
26
|
-
* - chat room state.
|
|
27
|
-
*/
|
|
28
|
-
export interface ChannelModel extends Model, ChannelHead {
|
|
29
|
-
/** id of model */
|
|
30
|
-
id?: string;
|
|
31
|
-
/** name of channel */
|
|
32
|
-
name?: string;
|
|
33
|
-
/** channel stereo */
|
|
34
|
-
stereo?: ChannelStereo;
|
|
35
|
-
/** optional description */
|
|
36
|
-
desc?: string;
|
|
37
|
-
/** owner id (P1 uses deviceId) */
|
|
38
|
-
ownerId?: string;
|
|
39
|
-
/** last chat sequence in this channel */
|
|
40
|
-
chatNo?: number;
|
|
41
|
-
/** joined device ids */
|
|
42
|
-
memberIds?: string[];
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* interface: `ChatModel`
|
|
46
|
-
* - message or channel event.
|
|
47
|
-
*/
|
|
48
|
-
export interface ChatModel extends Model {
|
|
49
|
-
/** id = `${channelId}:${chatNo}` */
|
|
50
|
-
id?: string;
|
|
51
|
-
/** chat event kind */
|
|
52
|
-
stereo?: ChatStereo;
|
|
53
|
-
/** channel-local sequence */
|
|
54
|
-
chatNo?: number;
|
|
55
|
-
/** message content */
|
|
56
|
-
content?: string;
|
|
57
|
-
/** message content type. v1 only uses text. */
|
|
58
|
-
contentType?: string;
|
|
59
|
-
/** parent channel id */
|
|
60
|
-
channelId?: string;
|
|
61
|
-
/** owner id. v1 uses deviceId. */
|
|
62
|
-
ownerId?: string;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* interface: `JoinModel`
|
|
66
|
-
* - channel membership and read cursor.
|
|
67
|
-
*/
|
|
68
|
-
export interface JoinModel extends Model {
|
|
69
|
-
/** id = `${channelId}:${ownerId}` */
|
|
70
|
-
id?: string;
|
|
71
|
-
/** join stereo. v1 only uses empty string. */
|
|
72
|
-
stereo?: JoinStereo;
|
|
73
|
-
/** joined channel id */
|
|
74
|
-
channelId?: string;
|
|
75
|
-
/** owner id. v1 uses deviceId. */
|
|
76
|
-
ownerId?: string;
|
|
77
|
-
/** last read chat sequence */
|
|
78
|
-
chatNo?: number;
|
|
79
|
-
/** current joined state. 1 = joined, 0 = left. */
|
|
80
|
-
joined?: number;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* extract field names from models
|
|
84
|
-
* - only fields start with lowercase, or all upper.
|
|
85
|
-
*/
|
|
86
|
-
export declare const filterFields: (fields: string[], base?: string[]) => string[];
|
|
87
|
-
/** field names from head */
|
|
88
|
-
export declare const $HEAD: {
|
|
89
|
-
channel: string[];
|
|
90
|
-
};
|
|
91
|
-
export declare const $FIELD: {
|
|
92
|
-
channel: string[];
|
|
93
|
-
chat: string[];
|
|
94
|
-
join: string[];
|
|
95
|
-
};
|
|
96
|
-
/** must export default as below */
|
|
97
|
-
declare const _default: {
|
|
98
|
-
$HEAD: {
|
|
99
|
-
channel: string[];
|
|
100
|
-
};
|
|
101
|
-
$FIELD: {
|
|
102
|
-
channel: string[];
|
|
103
|
-
chat: string[];
|
|
104
|
-
join: string[];
|
|
105
|
-
};
|
|
106
|
-
};
|
|
107
|
-
export default _default;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.$FIELD = exports.$HEAD = exports.filterFields = void 0;
|
|
4
|
-
const field_registry_1 = require("../../generated/field-registry");
|
|
5
|
-
/**
|
|
6
|
-
* extract field names from models
|
|
7
|
-
* - only fields start with lowercase, or all upper.
|
|
8
|
-
*/
|
|
9
|
-
const filterFields = (fields, base = []) => fields
|
|
10
|
-
.filter(field => field !== '_id' && /^[a-z_][a-zA-Z_]+/.test(field))
|
|
11
|
-
.reduce((L, k) => {
|
|
12
|
-
if (k && !L.includes(k))
|
|
13
|
-
L.push(k);
|
|
14
|
-
return L;
|
|
15
|
-
}, [...base]);
|
|
16
|
-
exports.filterFields = filterFields;
|
|
17
|
-
/** field names from head */
|
|
18
|
-
exports.$HEAD = {
|
|
19
|
-
channel: (0, exports.filterFields)(field_registry_1.fieldKeys.channelHead()),
|
|
20
|
-
};
|
|
21
|
-
// extract field names from models
|
|
22
|
-
exports.$FIELD = {
|
|
23
|
-
channel: (0, exports.filterFields)(field_registry_1.fieldKeys.channelModel(), ['meta']),
|
|
24
|
-
chat: (0, exports.filterFields)(field_registry_1.fieldKeys.chatModel(), ['meta']),
|
|
25
|
-
join: (0, exports.filterFields)(field_registry_1.fieldKeys.joinModel(), ['meta']),
|
|
26
|
-
};
|
|
27
|
-
/** must export default as below */
|
|
28
|
-
exports.default = { $HEAD: exports.$HEAD, $FIELD: exports.$FIELD };
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `types.ts`
|
|
3
|
-
* - basic types for chat module.
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Lookup Table
|
|
7
|
-
*
|
|
8
|
-
* WARN! DO NOT EXPORT AS `$LUT`. use default export instead.
|
|
9
|
-
*/
|
|
10
|
-
declare const $LUT: {
|
|
11
|
-
/**
|
|
12
|
-
* Possible type of model.
|
|
13
|
-
*/
|
|
14
|
-
ModelType: {
|
|
15
|
-
/** channel model */
|
|
16
|
-
channel: string;
|
|
17
|
-
/** chat model */
|
|
18
|
-
chat: string;
|
|
19
|
-
/** join model */
|
|
20
|
-
join: string;
|
|
21
|
-
};
|
|
22
|
-
/**
|
|
23
|
-
* ChannelStereo
|
|
24
|
-
*/
|
|
25
|
-
ChannelStereo: {
|
|
26
|
-
'': string;
|
|
27
|
-
/** direct message (1:1) */
|
|
28
|
-
dm: string;
|
|
29
|
-
/** self memo channel */
|
|
30
|
-
self: string;
|
|
31
|
-
/** open channel */
|
|
32
|
-
public: string;
|
|
33
|
-
/** invite-only channel */
|
|
34
|
-
private: string;
|
|
35
|
-
};
|
|
36
|
-
/**
|
|
37
|
-
* ChatStereo
|
|
38
|
-
*/
|
|
39
|
-
ChatStereo: {
|
|
40
|
-
text: string;
|
|
41
|
-
join: string;
|
|
42
|
-
leave: string;
|
|
43
|
-
system: string;
|
|
44
|
-
};
|
|
45
|
-
/**
|
|
46
|
-
* JoinStereo
|
|
47
|
-
*/
|
|
48
|
-
JoinStereo: {
|
|
49
|
-
'': string;
|
|
50
|
-
};
|
|
51
|
-
};
|
|
52
|
-
/**
|
|
53
|
-
* type: `ChannelStereo`
|
|
54
|
-
*/
|
|
55
|
-
export declare type ChannelStereo = keyof typeof $LUT.ChannelStereo;
|
|
56
|
-
/**
|
|
57
|
-
* type: `ChatStereo`
|
|
58
|
-
*/
|
|
59
|
-
export declare type ChatStereo = keyof typeof $LUT.ChatStereo;
|
|
60
|
-
/**
|
|
61
|
-
* type: `JoinStereo`
|
|
62
|
-
*/
|
|
63
|
-
export declare type JoinStereo = keyof typeof $LUT.JoinStereo;
|
|
64
|
-
/** must export $LUT as default */
|
|
65
|
-
export default $LUT;
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* `types.ts`
|
|
4
|
-
* - basic types for chat module.
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
/**
|
|
8
|
-
* Lookup Table
|
|
9
|
-
*
|
|
10
|
-
* WARN! DO NOT EXPORT AS `$LUT`. use default export instead.
|
|
11
|
-
*/
|
|
12
|
-
const $LUT = {
|
|
13
|
-
/**
|
|
14
|
-
* Possible type of model.
|
|
15
|
-
*/
|
|
16
|
-
ModelType: {
|
|
17
|
-
/** channel model */
|
|
18
|
-
channel: 'channel',
|
|
19
|
-
/** chat model */
|
|
20
|
-
chat: 'chat',
|
|
21
|
-
/** join model */
|
|
22
|
-
join: 'join',
|
|
23
|
-
},
|
|
24
|
-
/**
|
|
25
|
-
* ChannelStereo
|
|
26
|
-
*/
|
|
27
|
-
ChannelStereo: {
|
|
28
|
-
'': '',
|
|
29
|
-
/** direct message (1:1) */
|
|
30
|
-
dm: 'dm',
|
|
31
|
-
/** self memo channel */
|
|
32
|
-
self: 'self',
|
|
33
|
-
/** open channel */
|
|
34
|
-
public: 'public',
|
|
35
|
-
/** invite-only channel */
|
|
36
|
-
private: 'private',
|
|
37
|
-
},
|
|
38
|
-
/**
|
|
39
|
-
* ChatStereo
|
|
40
|
-
*/
|
|
41
|
-
ChatStereo: {
|
|
42
|
-
text: 'text',
|
|
43
|
-
join: 'join',
|
|
44
|
-
leave: 'leave',
|
|
45
|
-
system: 'system',
|
|
46
|
-
},
|
|
47
|
-
/**
|
|
48
|
-
* JoinStereo
|
|
49
|
-
*/
|
|
50
|
-
JoinStereo: {
|
|
51
|
-
'': '',
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
/** must export $LUT as default */
|
|
55
|
-
exports.default = $LUT;
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `views.ts`
|
|
3
|
-
* - type of views used in chat module.
|
|
4
|
-
*/
|
|
5
|
-
import { View, Body } from 'lemon-model';
|
|
6
|
-
import { ChannelModel, ChatModel, JoinModel } from './model';
|
|
7
|
-
import $LUT from './types';
|
|
8
|
-
import type { DeviceView } from '../sockets/views';
|
|
9
|
-
export * from './types';
|
|
10
|
-
export default $LUT;
|
|
11
|
-
/**
|
|
12
|
-
* type: `ChannelView`
|
|
13
|
-
*/
|
|
14
|
-
export interface ChannelView extends View, Partial<ChannelModel> {
|
|
15
|
-
/** (linked) owner info */
|
|
16
|
-
readonly owner$?: DeviceView;
|
|
17
|
-
/** (linked) last chat info */
|
|
18
|
-
readonly lastChat$?: ChatView;
|
|
19
|
-
/** (readonly) device's channel connection view */
|
|
20
|
-
readonly $join?: JoinView;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Type `ChannelBody`
|
|
24
|
-
*/
|
|
25
|
-
export interface ChannelBody extends Body, Partial<ChannelView> {
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* type: `ChatView`
|
|
29
|
-
*/
|
|
30
|
-
export interface ChatView extends View, Partial<ChatModel> {
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Type `ChatBody`
|
|
34
|
-
*/
|
|
35
|
-
export interface ChatBody extends Body, Partial<ChatView> {
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* type: `JoinView`
|
|
39
|
-
*/
|
|
40
|
-
export interface JoinView extends Omit<View, 'joined'>, Omit<Partial<JoinModel>, 'joined'> {
|
|
41
|
-
/**
|
|
42
|
-
* current joined state for API/view consumers.
|
|
43
|
-
*/
|
|
44
|
-
readonly joined?: boolean;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Type `JoinBody`
|
|
48
|
-
*/
|
|
49
|
-
export interface JoinBody extends Body, Partial<JoinView> {
|
|
50
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
17
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
|
-
};
|
|
19
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
const types_1 = __importDefault(require("./types"));
|
|
21
|
-
//! export all internal types
|
|
22
|
-
__exportStar(require("./types"), exports);
|
|
23
|
-
exports.default = types_1.default;
|
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `model.ts`
|
|
3
|
-
* - model definitions per account data
|
|
4
|
-
*
|
|
5
|
-
* @author Steve <steve@lemoncloud.io>
|
|
6
|
-
* @date 2022-08-29 initial version.
|
|
7
|
-
* @author Aiden <aiden@lemocloud.io>
|
|
8
|
-
* @date 2025-07-23 refactored for sockets service
|
|
9
|
-
*
|
|
10
|
-
* Copyright (C) 2022 LemonCloud Co Ltd. - All Rights Reserved.
|
|
11
|
-
*/
|
|
12
|
-
import { CoreModel } from 'lemon-model';
|
|
13
|
-
import $LUT, { DevicePlatform, DeviceStatus, ViewingType } from './types';
|
|
14
|
-
import type { ChannelHead } from '../chat/model';
|
|
15
|
-
/**
|
|
16
|
-
* type: `ModelType`
|
|
17
|
-
*/
|
|
18
|
-
export declare type ModelType = keyof typeof $LUT.ModelType;
|
|
19
|
-
/**
|
|
20
|
-
* type: `Model`: common model
|
|
21
|
-
*/
|
|
22
|
-
export declare type Model = CoreModel<ModelType>;
|
|
23
|
-
/**
|
|
24
|
-
* interface: `SocketModel`
|
|
25
|
-
*/
|
|
26
|
-
export interface SocketModel extends Model {
|
|
27
|
-
/** id of model */
|
|
28
|
-
id?: string;
|
|
29
|
-
/** name of model */
|
|
30
|
-
name?: string;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* interface: `ConnectionModel`
|
|
34
|
-
* - a model for each connection to websocket.
|
|
35
|
-
* - 웹소켓 연결 정보를 저장하는 모델
|
|
36
|
-
*/
|
|
37
|
-
export interface ConnectionModel extends Model {
|
|
38
|
-
/**
|
|
39
|
-
* as `conn-id`
|
|
40
|
-
*/
|
|
41
|
-
id?: string;
|
|
42
|
-
/**
|
|
43
|
-
* stereo type as initial `role`.
|
|
44
|
-
*/
|
|
45
|
-
stereo?: string;
|
|
46
|
-
/**
|
|
47
|
-
* (required) The deployment stage of the API (e.g., 'dev', 'prod').
|
|
48
|
-
*/
|
|
49
|
-
stage?: string;
|
|
50
|
-
/**
|
|
51
|
-
* (required) The domain name of the WebSocket API.
|
|
52
|
-
*/
|
|
53
|
-
domain?: string;
|
|
54
|
-
/**
|
|
55
|
-
* (required) The API Gateway ID for Management API endpoint.
|
|
56
|
-
*/
|
|
57
|
-
apiId?: string;
|
|
58
|
-
/**
|
|
59
|
-
* (required) The unique identifier for the WebSocket connection.
|
|
60
|
-
*/
|
|
61
|
-
connectionId?: string;
|
|
62
|
-
/** (optional) if it has valid session infor. */
|
|
63
|
-
hasSession?: number;
|
|
64
|
-
/** (internal) Timestamp when the connection was established. */
|
|
65
|
-
connectedAt?: number;
|
|
66
|
-
/** (internal) Timestamp when the connection was terminated. */
|
|
67
|
-
disConnectedAt?: number;
|
|
68
|
-
/** (internal) version no */
|
|
69
|
-
versionNo?: number;
|
|
70
|
-
/** (internal) tracking no */
|
|
71
|
-
no?: number;
|
|
72
|
-
/**
|
|
73
|
-
* (extended) The origin of the request.
|
|
74
|
-
*/
|
|
75
|
-
origin?: string;
|
|
76
|
-
/**
|
|
77
|
-
* (extended) The remote IP address of the client.
|
|
78
|
-
*/
|
|
79
|
-
remote?: string;
|
|
80
|
-
/**
|
|
81
|
-
* (extended) The User-Agent string of the client.
|
|
82
|
-
*/
|
|
83
|
-
agent?: string;
|
|
84
|
-
/**
|
|
85
|
-
* (extended) The reason for disconnection, if applicable.
|
|
86
|
-
*/
|
|
87
|
-
reason?: string;
|
|
88
|
-
/**
|
|
89
|
-
* (extended) The code of disconnection.
|
|
90
|
-
*/
|
|
91
|
-
disconnectCode?: number;
|
|
92
|
-
/**
|
|
93
|
-
* (extended) TTL for auto-deletion (ts)
|
|
94
|
-
*/
|
|
95
|
-
ttl?: number;
|
|
96
|
-
/**
|
|
97
|
-
* (internal) ping-pong count
|
|
98
|
-
*/
|
|
99
|
-
readonly count?: number;
|
|
100
|
-
/**
|
|
101
|
-
* (linked) 현재 연결이 구독 중인 채널(토픽) ID 목록
|
|
102
|
-
*
|
|
103
|
-
* @deprecated no more supported (see `chatic-socials-api`)
|
|
104
|
-
*/
|
|
105
|
-
channels?: string[];
|
|
106
|
-
/**
|
|
107
|
-
* @deprecated no longer in use (Channel management has been delegated to chatic-socials-api)
|
|
108
|
-
*/
|
|
109
|
-
channel$$?: ChannelHead[];
|
|
110
|
-
/**
|
|
111
|
-
* (linked) device id for state sync
|
|
112
|
-
* NOTE it must be 1:1 matching with device.
|
|
113
|
-
* - `Device` has the major one connection.
|
|
114
|
-
* - `Connection` is belong to single `Device`.
|
|
115
|
-
*/
|
|
116
|
-
deviceId?: string;
|
|
117
|
-
/** (internal) identity-id */
|
|
118
|
-
identityId?: string;
|
|
119
|
-
/** (internal) verified roles */
|
|
120
|
-
roles?: string[];
|
|
121
|
-
/** (internal) delegator-id — 소셜 로그인 시 게스트유저 uid */
|
|
122
|
-
did?: string;
|
|
123
|
-
/**
|
|
124
|
-
* (internal) connected device-info
|
|
125
|
-
*/
|
|
126
|
-
readonly $device?: DeviceModel;
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* interface: `DeviceHead`
|
|
130
|
-
*/
|
|
131
|
-
export interface DeviceHead {
|
|
132
|
-
/** id of model */
|
|
133
|
-
id?: string;
|
|
134
|
-
/** name of model */
|
|
135
|
-
name?: string;
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* interface: `DeviceModel` (종단 기기)ㅊ
|
|
139
|
-
* - 디바이스 정보 관리 모델
|
|
140
|
-
* - 그럼, 여기에서는 ENDPOINT 간의 상태 동기화
|
|
141
|
-
*
|
|
142
|
-
* ex) 브라우저 창, 네이티브 앱, 노드기반 클라이언트.
|
|
143
|
-
*/
|
|
144
|
-
export interface DeviceModel extends Model, DeviceHead {
|
|
145
|
-
/** device-id (클라이언트에서 생성된 UUID) */
|
|
146
|
-
id?: string;
|
|
147
|
-
/** name of model */
|
|
148
|
-
name?: string;
|
|
149
|
-
/** device platform */
|
|
150
|
-
platform?: DevicePlatform;
|
|
151
|
-
/** status of device (for sync) */
|
|
152
|
-
status?: DeviceStatus;
|
|
153
|
-
/** tick count (for sync) */
|
|
154
|
-
tick?: number;
|
|
155
|
-
/** x position (for sync) */
|
|
156
|
-
posX?: number;
|
|
157
|
-
/** y position (for sync) */
|
|
158
|
-
posY?: number;
|
|
159
|
-
/** 현재 보고 있는 대상 종류 (예: 'channel') */
|
|
160
|
-
viewingType?: ViewingType;
|
|
161
|
-
/** 현재 보고 있는 대상 id */
|
|
162
|
-
viewingId?: string;
|
|
163
|
-
/** 현재 대상 진입 시각(ms) */
|
|
164
|
-
viewingSince?: number;
|
|
165
|
-
/** last activity timestamp */
|
|
166
|
-
lastActiveAt?: number;
|
|
167
|
-
/** connection start timestamp */
|
|
168
|
-
connectedAt?: number;
|
|
169
|
-
/** last disconnection timestamp */
|
|
170
|
-
disconnectedAt?: number;
|
|
171
|
-
/** (internal) connection-id */
|
|
172
|
-
connId?: string;
|
|
173
|
-
/** joined channel ids */
|
|
174
|
-
channelIds?: string[];
|
|
175
|
-
/**
|
|
176
|
-
* (internal) owner user-id
|
|
177
|
-
* - 푸시 전송 시, 타겟 유저 ID 매핑을 위해 이용됨.
|
|
178
|
-
* */
|
|
179
|
-
readonly userId?: string;
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* extract field names from models
|
|
183
|
-
* - only fields start with lowercase, or all upper.
|
|
184
|
-
*/
|
|
185
|
-
export declare const filterFields: (fields: string[], base?: string[]) => string[];
|
|
186
|
-
/** field names from head */
|
|
187
|
-
export declare const $HEAD: {
|
|
188
|
-
device: string[];
|
|
189
|
-
};
|
|
190
|
-
export declare const $FIELD: {
|
|
191
|
-
socket: string[];
|
|
192
|
-
connection: string[];
|
|
193
|
-
device: string[];
|
|
194
|
-
};
|
|
195
|
-
/** must export default as below */
|
|
196
|
-
declare const _default: {
|
|
197
|
-
$HEAD: {
|
|
198
|
-
device: string[];
|
|
199
|
-
};
|
|
200
|
-
$FIELD: {
|
|
201
|
-
socket: string[];
|
|
202
|
-
connection: string[];
|
|
203
|
-
device: string[];
|
|
204
|
-
};
|
|
205
|
-
};
|
|
206
|
-
export default _default;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.$FIELD = exports.$HEAD = exports.filterFields = void 0;
|
|
4
|
-
const field_registry_1 = require("../../generated/field-registry");
|
|
5
|
-
/**
|
|
6
|
-
* extract field names from models
|
|
7
|
-
* - only fields start with lowercase, or all upper.
|
|
8
|
-
*/
|
|
9
|
-
const filterFields = (fields, base = []) => fields
|
|
10
|
-
.filter(field => field !== '_id' && /^[a-z_][a-zA-Z_]+/.test(field))
|
|
11
|
-
.reduce((L, k) => {
|
|
12
|
-
if (k && !L.includes(k))
|
|
13
|
-
L.push(k);
|
|
14
|
-
return L;
|
|
15
|
-
}, [...base]);
|
|
16
|
-
exports.filterFields = filterFields;
|
|
17
|
-
/** field names from head */
|
|
18
|
-
exports.$HEAD = {
|
|
19
|
-
device: (0, exports.filterFields)(field_registry_1.fieldKeys.deviceHead()),
|
|
20
|
-
};
|
|
21
|
-
// extract field names from models
|
|
22
|
-
exports.$FIELD = {
|
|
23
|
-
socket: (0, exports.filterFields)(field_registry_1.fieldKeys.socketModel(), ['meta']),
|
|
24
|
-
connection: (0, exports.filterFields)(field_registry_1.fieldKeys.connectionModel(), ['meta']),
|
|
25
|
-
device: (0, exports.filterFields)(field_registry_1.fieldKeys.deviceModel(), ['meta']),
|
|
26
|
-
};
|
|
27
|
-
/** must export default as below */
|
|
28
|
-
exports.default = { $HEAD: exports.$HEAD, $FIELD: exports.$FIELD };
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `types.ts`
|
|
3
|
-
* - 기본 types used in `backend-proxy`
|
|
4
|
-
*
|
|
5
|
-
* **[중요! exports 순서]**
|
|
6
|
-
* 1. define data type in `types.ts` w/ internal types.
|
|
7
|
-
* 2. define Model in `model.ts`
|
|
8
|
-
* 3. define View/Body in `view.ts`, and external types.
|
|
9
|
-
*
|
|
10
|
-
* @author Steve <steve@lemoncloud.io>
|
|
11
|
-
* @date 2022-08-29 initial version.
|
|
12
|
-
* @author Aiden <aiden@lemocloud.io>
|
|
13
|
-
* @date 2025-07-23 refactored for sockets service
|
|
14
|
-
*
|
|
15
|
-
* Copyright (C) 2022 LemonCloud Co Ltd. - All Rights Reserved.
|
|
16
|
-
*/
|
|
17
|
-
/**
|
|
18
|
-
* Lookup Table
|
|
19
|
-
*
|
|
20
|
-
* WARN! DO NOT EXPORT AS `$LUT`. use default export instead.
|
|
21
|
-
*/
|
|
22
|
-
declare const $LUT: {
|
|
23
|
-
/**
|
|
24
|
-
* Possible type of model.
|
|
25
|
-
*/
|
|
26
|
-
ModelType: {
|
|
27
|
-
/** socket model */
|
|
28
|
-
socket: string;
|
|
29
|
-
/** connection model */
|
|
30
|
-
connection: string;
|
|
31
|
-
/** device model */
|
|
32
|
-
device: string;
|
|
33
|
-
};
|
|
34
|
-
/**
|
|
35
|
-
* DeviceStatus
|
|
36
|
-
*/
|
|
37
|
-
DeviceStatus: {
|
|
38
|
-
'': string;
|
|
39
|
-
/** green - online */
|
|
40
|
-
green: string;
|
|
41
|
-
/** red - offline */
|
|
42
|
-
red: string;
|
|
43
|
-
/** yellow - away/idle */
|
|
44
|
-
yellow: string;
|
|
45
|
-
};
|
|
46
|
-
/**
|
|
47
|
-
* DeviceEventType
|
|
48
|
-
*/
|
|
49
|
-
DeviceEventType: {
|
|
50
|
-
'': string;
|
|
51
|
-
/** ping - heartbeat */
|
|
52
|
-
ping: string;
|
|
53
|
-
/** status - status change */
|
|
54
|
-
status: string;
|
|
55
|
-
};
|
|
56
|
-
/**
|
|
57
|
-
* ViewingType — 현재 보고 있는 대상 종류
|
|
58
|
-
*/
|
|
59
|
-
ViewingType: {
|
|
60
|
-
'': string;
|
|
61
|
-
/** channel */
|
|
62
|
-
channel: string;
|
|
63
|
-
};
|
|
64
|
-
/**
|
|
65
|
-
* DevicePlatform
|
|
66
|
-
*/
|
|
67
|
-
DevicePlatform: {
|
|
68
|
-
'': string;
|
|
69
|
-
/** iOS */
|
|
70
|
-
ios: string;
|
|
71
|
-
/** Android */
|
|
72
|
-
android: string;
|
|
73
|
-
/** Web browser */
|
|
74
|
-
web: string;
|
|
75
|
-
/** macOS */
|
|
76
|
-
macos: string;
|
|
77
|
-
/** Windows */
|
|
78
|
-
windows: string;
|
|
79
|
-
/** Linux */
|
|
80
|
-
linux: string;
|
|
81
|
-
};
|
|
82
|
-
};
|
|
83
|
-
/**
|
|
84
|
-
* type: `DeviceStatus`
|
|
85
|
-
*/
|
|
86
|
-
export declare type DeviceStatus = keyof typeof $LUT.DeviceStatus;
|
|
87
|
-
/**
|
|
88
|
-
* type: `DeviceEventType`
|
|
89
|
-
*/
|
|
90
|
-
export declare type DeviceEventType = keyof typeof $LUT.DeviceEventType;
|
|
91
|
-
/**
|
|
92
|
-
* type: `ViewingType`
|
|
93
|
-
*/
|
|
94
|
-
export declare type ViewingType = keyof typeof $LUT.ViewingType;
|
|
95
|
-
/**
|
|
96
|
-
* type: `DevicePlatform`
|
|
97
|
-
*/
|
|
98
|
-
export declare type DevicePlatform = keyof typeof $LUT.DevicePlatform;
|
|
99
|
-
/** must export $LUT as default */
|
|
100
|
-
export default $LUT;
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* `types.ts`
|
|
4
|
-
* - 기본 types used in `backend-proxy`
|
|
5
|
-
*
|
|
6
|
-
* **[중요! exports 순서]**
|
|
7
|
-
* 1. define data type in `types.ts` w/ internal types.
|
|
8
|
-
* 2. define Model in `model.ts`
|
|
9
|
-
* 3. define View/Body in `view.ts`, and external types.
|
|
10
|
-
*
|
|
11
|
-
* @author Steve <steve@lemoncloud.io>
|
|
12
|
-
* @date 2022-08-29 initial version.
|
|
13
|
-
* @author Aiden <aiden@lemocloud.io>
|
|
14
|
-
* @date 2025-07-23 refactored for sockets service
|
|
15
|
-
*
|
|
16
|
-
* Copyright (C) 2022 LemonCloud Co Ltd. - All Rights Reserved.
|
|
17
|
-
*/
|
|
18
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
/**
|
|
20
|
-
* Lookup Table
|
|
21
|
-
*
|
|
22
|
-
* WARN! DO NOT EXPORT AS `$LUT`. use default export instead.
|
|
23
|
-
*/
|
|
24
|
-
const $LUT = {
|
|
25
|
-
/**
|
|
26
|
-
* Possible type of model.
|
|
27
|
-
*/
|
|
28
|
-
ModelType: {
|
|
29
|
-
/** socket model */
|
|
30
|
-
socket: 'socket',
|
|
31
|
-
/** connection model */
|
|
32
|
-
connection: 'connection',
|
|
33
|
-
/** device model */
|
|
34
|
-
device: 'device',
|
|
35
|
-
},
|
|
36
|
-
/**
|
|
37
|
-
* DeviceStatus
|
|
38
|
-
*/
|
|
39
|
-
DeviceStatus: {
|
|
40
|
-
'': '',
|
|
41
|
-
/** green - online */
|
|
42
|
-
green: 'green',
|
|
43
|
-
/** red - offline */
|
|
44
|
-
red: 'red',
|
|
45
|
-
/** yellow - away/idle */
|
|
46
|
-
yellow: 'yellow',
|
|
47
|
-
},
|
|
48
|
-
/**
|
|
49
|
-
* DeviceEventType
|
|
50
|
-
*/
|
|
51
|
-
DeviceEventType: {
|
|
52
|
-
'': '',
|
|
53
|
-
/** ping - heartbeat */
|
|
54
|
-
ping: 'ping',
|
|
55
|
-
/** status - status change */
|
|
56
|
-
status: 'status',
|
|
57
|
-
},
|
|
58
|
-
/**
|
|
59
|
-
* ViewingType — 현재 보고 있는 대상 종류
|
|
60
|
-
*/
|
|
61
|
-
ViewingType: {
|
|
62
|
-
'': '',
|
|
63
|
-
/** channel */
|
|
64
|
-
channel: 'channel',
|
|
65
|
-
},
|
|
66
|
-
/**
|
|
67
|
-
* DevicePlatform
|
|
68
|
-
*/
|
|
69
|
-
DevicePlatform: {
|
|
70
|
-
'': '',
|
|
71
|
-
/** iOS */
|
|
72
|
-
ios: 'ios',
|
|
73
|
-
/** Android */
|
|
74
|
-
android: 'android',
|
|
75
|
-
/** Web browser */
|
|
76
|
-
web: 'web',
|
|
77
|
-
/** macOS */
|
|
78
|
-
macos: 'macos',
|
|
79
|
-
/** Windows */
|
|
80
|
-
windows: 'windows',
|
|
81
|
-
/** Linux */
|
|
82
|
-
linux: 'linux',
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
/** must export $LUT as default */
|
|
86
|
-
exports.default = $LUT;
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `views.ts`
|
|
3
|
-
* - type of views used in `backend-proxy`
|
|
4
|
-
*
|
|
5
|
-
* @author Steve <steve@lemoncloud.io>
|
|
6
|
-
* @date 2022-08-29 initial version.
|
|
7
|
-
* @author Aiden <aiden@lemoncloud.io>
|
|
8
|
-
* @date 2024-07-23 refactored for sockets service
|
|
9
|
-
*
|
|
10
|
-
* Copyright (C) 2022 LemonCloud Co Ltd. - All Rights Reserved.
|
|
11
|
-
*/
|
|
12
|
-
import { View, Body } from 'lemon-model';
|
|
13
|
-
import { ConnectionModel, DeviceModel, SocketModel } from './model';
|
|
14
|
-
import $LUT from './types';
|
|
15
|
-
export * from './types';
|
|
16
|
-
export default $LUT;
|
|
17
|
-
/**!SECTION */
|
|
18
|
-
/**
|
|
19
|
-
* type: `SocketView`
|
|
20
|
-
* - usually same as post's body.
|
|
21
|
-
*/
|
|
22
|
-
export interface SocketView extends View, Partial<SocketModel> {
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Type `SocketBody`
|
|
26
|
-
*/
|
|
27
|
-
export interface SocketBody extends Body, Partial<SocketView> {
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* type: `ConnectionView`
|
|
31
|
-
* - usually same as post's body.
|
|
32
|
-
*/
|
|
33
|
-
export interface ConnectionView extends View, Omit<Partial<ConnectionModel>, '$device'> {
|
|
34
|
-
/** (internal) connected device info */
|
|
35
|
-
readonly $device?: DeviceView;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Type `ConnectionBody`
|
|
39
|
-
*/
|
|
40
|
-
export interface ConnectionBody extends Body, Partial<ConnectionView> {
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* type: `DeviceView`
|
|
44
|
-
*/
|
|
45
|
-
export interface DeviceView extends View, Partial<DeviceModel> {
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Type `DeviceBody`
|
|
49
|
-
*/
|
|
50
|
-
export interface DeviceBody extends Body, Partial<DeviceView> {
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* type: `ServerPingResultView`
|
|
54
|
-
* - 서버에서 커넥션 ping 테스트 결과
|
|
55
|
-
*/
|
|
56
|
-
export interface ServerPingResultView {
|
|
57
|
-
/** 대상 connectionId */
|
|
58
|
-
connId: string;
|
|
59
|
-
/** ping 시도 시간 (timestamp) */
|
|
60
|
-
pingedAt: number;
|
|
61
|
-
/** 최종 활성 상태 */
|
|
62
|
-
isActive: boolean;
|
|
63
|
-
/** cleanup 수행 여부 */
|
|
64
|
-
isCleaned?: boolean;
|
|
65
|
-
/** 현재 connection 상태 */
|
|
66
|
-
$conn?: ConnectionView;
|
|
67
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
17
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
|
-
};
|
|
19
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
const types_1 = __importDefault(require("./types"));
|
|
21
|
-
//! export all internal types
|
|
22
|
-
__exportStar(require("./types"), exports);
|
|
23
|
-
exports.default = types_1.default;
|