@lemoncloud/chatic-sockets-lib 0.3.2 → 0.3.4
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/gateways/channel-gateway.d.ts +1 -1
- package/dist/client-socket-v2/gateways/join-gateway.d.ts +15 -0
- package/dist/client-socket-v2/gateways/join-gateway.js +12 -0
- package/dist/client-socket-v2/index.d.ts +2 -0
- package/dist/client-socket-v2/index.js +2 -0
- package/dist/client-socket-v2/plans/channel-sync-plan.d.ts +14 -10
- package/dist/client-socket-v2/plans/channel-sync-plan.js +6 -2
- package/dist/client-socket-v2/plans/chat-sync-plan.d.ts +18 -9
- package/dist/client-socket-v2/plans/chat-sync-plan.js +1 -1
- package/dist/client-socket-v2/plans/join-sync-plan.d.ts +37 -0
- package/dist/client-socket-v2/plans/join-sync-plan.js +71 -0
- package/dist/client-socket-v2/plans/place-sync-plan.d.ts +14 -10
- package/dist/client-socket-v2/plans/place-sync-plan.js +5 -2
- package/dist/client-socket-v2/plans/profile-sync-plan.d.ts +14 -10
- package/dist/client-socket-v2/plans/profile-sync-plan.js +5 -2
- package/dist/client-socket-v2/types.d.ts +12 -0
- package/dist/lib/join/contracts.d.ts +32 -0
- package/dist/lib/join/contracts.js +7 -0
- package/dist/lib/join/types.d.ts +31 -0
- package/dist/lib/join/types.js +2 -0
- package/dist/lib/socket-actions.d.ts +19 -1
- package/dist/lib/socket-actions.js +13 -0
- package/dist/lib/socket-inputs.d.ts +1 -0
- package/package.json +1 -1
|
@@ -24,7 +24,7 @@ export interface ChannelGateway {
|
|
|
24
24
|
listUser<T = unknown>(data: ChannelListUserInput): Promise<T>;
|
|
25
25
|
/** $socials.ChannelView */
|
|
26
26
|
invite<T = unknown>(data: ChannelInviteInput): Promise<T>;
|
|
27
|
-
/**
|
|
27
|
+
/** @deprecated moved to the join domain. Use `createJoinGateway(client).update()`. */
|
|
28
28
|
updateJoin<T = unknown>(data: ChannelUpdateJoinInput): Promise<T>;
|
|
29
29
|
/** $socials.UnreadsSummaryView */
|
|
30
30
|
unreads<T = unknown>(data?: ChannelUnreadsInput | null): Promise<T>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { JoinGetInput, JoinUpdateInput } from '../../lib/join/types';
|
|
2
|
+
import type { ClientSocketV2 } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* join 도메인 게이트웨이.
|
|
5
|
+
* - 응답은 @lemoncloud/chatic-socials-api 소유(pass-through)이므로 제네릭 T로 호출부에서 주입한다.
|
|
6
|
+
* - 미주입 시 unknown. 각 메서드 주석의 $socials.<View> 가 실제 응답 타입.
|
|
7
|
+
* - 입력의 `id` 는 Join.id이며 클라이언트가 보관한 값을 그대로 전달한다.
|
|
8
|
+
*/
|
|
9
|
+
export interface JoinGateway {
|
|
10
|
+
/** $socials.JoinView */
|
|
11
|
+
get<T = unknown>(data: JoinGetInput): Promise<T>;
|
|
12
|
+
/** $socials.JoinView */
|
|
13
|
+
update<T = unknown>(data: JoinUpdateInput): Promise<T>;
|
|
14
|
+
}
|
|
15
|
+
export declare const createJoinGateway: (client: ClientSocketV2) => JoinGateway;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createJoinGateway = void 0;
|
|
4
|
+
const create_domain_gateway_1 = require("./create-domain-gateway");
|
|
5
|
+
const createJoinGateway = (client) => {
|
|
6
|
+
const gateway = (0, create_domain_gateway_1.createDomainGateway)('join', client);
|
|
7
|
+
return {
|
|
8
|
+
get: (data) => gateway.request('get', data),
|
|
9
|
+
update: (data) => gateway.request('update', data),
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
exports.createJoinGateway = createJoinGateway;
|
|
@@ -21,12 +21,14 @@ export * from './plans/channel-sync-plan';
|
|
|
21
21
|
export * from './plans/chat-sync-plan';
|
|
22
22
|
export type { ChatSyncType, ChatSyncData, ChatSyncMessage } from '../lib/chat/types';
|
|
23
23
|
export * from './plans/place-sync-plan';
|
|
24
|
+
export * from './plans/join-sync-plan';
|
|
24
25
|
export * from './plans/profile-sync-plan';
|
|
25
26
|
export * from './gateways/create-domain-gateway';
|
|
26
27
|
export * from './gateways/device-gateway';
|
|
27
28
|
export * from './gateways/channel-gateway';
|
|
28
29
|
export * from './gateways/auth-gateway';
|
|
29
30
|
export * from './gateways/chat-gateway';
|
|
31
|
+
export * from './gateways/join-gateway';
|
|
30
32
|
export * from './gateways/cloud-gateway';
|
|
31
33
|
export * from './gateways/user-gateway';
|
|
32
34
|
export * from './gateways/place-gateway';
|
|
@@ -38,12 +38,14 @@ __exportStar(require("./plans/device-sync-plan"), exports);
|
|
|
38
38
|
__exportStar(require("./plans/channel-sync-plan"), exports);
|
|
39
39
|
__exportStar(require("./plans/chat-sync-plan"), exports);
|
|
40
40
|
__exportStar(require("./plans/place-sync-plan"), exports);
|
|
41
|
+
__exportStar(require("./plans/join-sync-plan"), exports);
|
|
41
42
|
__exportStar(require("./plans/profile-sync-plan"), exports);
|
|
42
43
|
__exportStar(require("./gateways/create-domain-gateway"), exports);
|
|
43
44
|
__exportStar(require("./gateways/device-gateway"), exports);
|
|
44
45
|
__exportStar(require("./gateways/channel-gateway"), exports);
|
|
45
46
|
__exportStar(require("./gateways/auth-gateway"), exports);
|
|
46
47
|
__exportStar(require("./gateways/chat-gateway"), exports);
|
|
48
|
+
__exportStar(require("./gateways/join-gateway"), exports);
|
|
47
49
|
__exportStar(require("./gateways/cloud-gateway"), exports);
|
|
48
50
|
__exportStar(require("./gateways/user-gateway"), exports);
|
|
49
51
|
__exportStar(require("./gateways/place-gateway"), exports);
|
|
@@ -1,27 +1,31 @@
|
|
|
1
|
-
import type { ChannelView } from '../../lib/chat/views';
|
|
2
1
|
import type { SocketMessage } from '../../lib/types';
|
|
3
|
-
import type { DomainSyncContext, DomainSyncPlan
|
|
2
|
+
import type { DomainSyncContext, DomainSyncPlan } from '../types';
|
|
3
|
+
import type { SyncableView, SyncBackoffOptions, SyncFailureInfo, SyncTargetDescriptor } from '../types';
|
|
4
4
|
export interface ChannelSyncTarget extends SyncTargetDescriptor {
|
|
5
5
|
type: 'channel';
|
|
6
6
|
}
|
|
7
|
-
export interface ChannelSyncSnapshot {
|
|
7
|
+
export interface ChannelSyncSnapshot<TView extends SyncableView = SyncableView> {
|
|
8
8
|
id?: string;
|
|
9
9
|
updatedAt?: number;
|
|
10
|
-
view?:
|
|
10
|
+
view?: TView;
|
|
11
11
|
}
|
|
12
|
-
export interface ChannelSyncPlanOptions {
|
|
12
|
+
export interface ChannelSyncPlanOptions<TView extends SyncableView = SyncableView> {
|
|
13
13
|
intervalMs?: number;
|
|
14
14
|
idleBackoff?: SyncBackoffOptions;
|
|
15
15
|
resetSnapshotOnConnected?: boolean;
|
|
16
|
-
onUpdate?: (target: ChannelSyncTarget, view:
|
|
17
|
-
onRemove?: (target: ChannelSyncTarget, previous?: ChannelSyncSnapshot) => void;
|
|
16
|
+
onUpdate?: (target: ChannelSyncTarget, view: TView, previous?: ChannelSyncSnapshot<TView>) => void;
|
|
17
|
+
onRemove?: (target: ChannelSyncTarget, previous?: ChannelSyncSnapshot<TView>) => void;
|
|
18
18
|
}
|
|
19
|
-
/**
|
|
20
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Single-channel sync: polls `channel.get`, applies on `updatedAt` change, re-pulls on a `channel.sync` nudge.
|
|
21
|
+
* - Generic over the view type: inject the concrete view at the call site,
|
|
22
|
+
* e.g. `new ChannelSyncPlan<$socials.ChannelView>({ onUpdate })`.
|
|
23
|
+
*/
|
|
24
|
+
export declare class ChannelSyncPlan<TView extends SyncableView = SyncableView> implements DomainSyncPlan<ChannelSyncTarget> {
|
|
21
25
|
private readonly options;
|
|
22
26
|
readonly domain = "channel";
|
|
23
27
|
readonly idleBackoff: SyncBackoffOptions;
|
|
24
|
-
constructor(options?: ChannelSyncPlanOptions);
|
|
28
|
+
constructor(options?: ChannelSyncPlanOptions<TView>);
|
|
25
29
|
supports: (target: SyncTargetDescriptor) => target is ChannelSyncTarget;
|
|
26
30
|
getKey: (target: ChannelSyncTarget) => string;
|
|
27
31
|
getIntervalMs: (target: ChannelSyncTarget) => number;
|
|
@@ -10,7 +10,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.ChannelSyncPlan = void 0;
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* Single-channel sync: polls `channel.get`, applies on `updatedAt` change, re-pulls on a `channel.sync` nudge.
|
|
15
|
+
* - Generic over the view type: inject the concrete view at the call site,
|
|
16
|
+
* e.g. `new ChannelSyncPlan<$socials.ChannelView>({ onUpdate })`.
|
|
17
|
+
*/
|
|
14
18
|
class ChannelSyncPlan {
|
|
15
19
|
constructor(options = {}) {
|
|
16
20
|
var _a;
|
|
@@ -30,7 +34,7 @@ class ChannelSyncPlan {
|
|
|
30
34
|
return;
|
|
31
35
|
const prev = ctx.readSnapshot(target);
|
|
32
36
|
const input = { id: target.id };
|
|
33
|
-
const view = yield ctx.client.request('channel.get', input);
|
|
37
|
+
const view = (yield ctx.client.request('channel.get', input));
|
|
34
38
|
const nextUpdatedAt = typeof (view === null || view === void 0 ? void 0 : view.updatedAt) === 'number' ? view.updatedAt : undefined;
|
|
35
39
|
const prevUpdatedAt = typeof (prev === null || prev === void 0 ? void 0 : prev.updatedAt) === 'number' ? prev.updatedAt : undefined;
|
|
36
40
|
if (prevUpdatedAt === nextUpdatedAt && (prev === null || prev === void 0 ? void 0 : prev.view))
|
|
@@ -1,27 +1,36 @@
|
|
|
1
|
-
import type { ChatView } from '../../lib/chat/views';
|
|
2
1
|
import type { SocketMessage } from '../../lib/types';
|
|
3
|
-
import type { DomainSyncContext, DomainSyncPlan
|
|
2
|
+
import type { DomainSyncContext, DomainSyncPlan } from '../types';
|
|
3
|
+
import type { SyncBackoffOptions, SyncFailureInfo, SyncTargetDescriptor } from '../types';
|
|
4
|
+
/**
|
|
5
|
+
* Minimal message shape the chat window requires: ordering key (`chatNo`) + channel scope (`channelId`).
|
|
6
|
+
* - The plan is generic over the message type; inject the concrete view at the call site,
|
|
7
|
+
* e.g. `new ChatSyncPlan<$socials.ChatView>({ onApply })`.
|
|
8
|
+
*/
|
|
9
|
+
export interface ChatMessageLike {
|
|
10
|
+
chatNo?: number;
|
|
11
|
+
channelId?: string;
|
|
12
|
+
}
|
|
4
13
|
/** Sync target for one channel's chat messages. */
|
|
5
14
|
export interface ChatSyncTarget extends SyncTargetDescriptor {
|
|
6
15
|
type: 'chat';
|
|
7
16
|
}
|
|
8
17
|
/** 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 {
|
|
18
|
+
export interface ChatSyncSnapshot<TMessage extends ChatMessageLike = ChatMessageLike> {
|
|
10
19
|
id: string;
|
|
11
20
|
lastNo: number;
|
|
12
21
|
minNo: number;
|
|
13
|
-
messages:
|
|
22
|
+
messages: TMessage[];
|
|
14
23
|
}
|
|
15
|
-
export interface ChatSyncPlanOptions {
|
|
24
|
+
export interface ChatSyncPlanOptions<TMessage extends ChatMessageLike = ChatMessageLike> {
|
|
16
25
|
/** Max messages fetched in one catch-up; anything older is left for the app to lazy-load. Default 50. */
|
|
17
26
|
cap?: number;
|
|
18
27
|
/** Max messages kept in the snapshot window to bound memory; the app holds full history via `onApply`. Default 500. */
|
|
19
28
|
maxMessages?: number;
|
|
20
29
|
idleBackoff?: SyncBackoffOptions;
|
|
21
30
|
/** Called after messages are applied, with the applied delta (ascending) and the new snapshot. */
|
|
22
|
-
onApply?: (target: ChatSyncTarget, applied:
|
|
31
|
+
onApply?: (target: ChatSyncTarget, applied: TMessage[], snapshot: ChatSyncSnapshot<TMessage>) => void;
|
|
23
32
|
/** Called when the engine stops the target. */
|
|
24
|
-
onRemove?: (target: ChatSyncTarget, previous?: ChatSyncSnapshot) => void;
|
|
33
|
+
onRemove?: (target: ChatSyncTarget, previous?: ChatSyncSnapshot<TMessage>) => void;
|
|
25
34
|
}
|
|
26
35
|
/**
|
|
27
36
|
* Per-channel chat message sync (append-only events).
|
|
@@ -29,12 +38,12 @@ export interface ChatSyncPlanOptions {
|
|
|
29
38
|
* - `onConnected`: catches up from `lastNo` to `channel.chatNo` (bounded by `cap`) after a reconnect.
|
|
30
39
|
* - `run`: no-op (event-driven, no polling).
|
|
31
40
|
*/
|
|
32
|
-
export declare class ChatSyncPlan implements DomainSyncPlan<ChatSyncTarget> {
|
|
41
|
+
export declare class ChatSyncPlan<TMessage extends ChatMessageLike = ChatMessageLike> implements DomainSyncPlan<ChatSyncTarget> {
|
|
33
42
|
private readonly options;
|
|
34
43
|
readonly domain = "chat";
|
|
35
44
|
readonly idleBackoff: SyncBackoffOptions;
|
|
36
45
|
private readonly chains;
|
|
37
|
-
constructor(options?: ChatSyncPlanOptions);
|
|
46
|
+
constructor(options?: ChatSyncPlanOptions<TMessage>);
|
|
38
47
|
supports: (target: SyncTargetDescriptor) => target is ChatSyncTarget;
|
|
39
48
|
getKey: (target: ChatSyncTarget) => string;
|
|
40
49
|
run: () => Promise<void>;
|
|
@@ -74,7 +74,7 @@ class ChatSyncPlan {
|
|
|
74
74
|
return;
|
|
75
75
|
const snap = snapIn !== null && snapIn !== void 0 ? snapIn : this.readSnap(target, ctx);
|
|
76
76
|
const input = { id: target.id };
|
|
77
|
-
const channel = yield ctx.client.request('channel.get', input);
|
|
77
|
+
const channel = (yield ctx.client.request('channel.get', input));
|
|
78
78
|
const total = num(channel === null || channel === void 0 ? void 0 : channel.chatNo, 0);
|
|
79
79
|
if (total <= snap.lastNo)
|
|
80
80
|
return; // already latest
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { SocketMessage } from '../../lib/types';
|
|
2
|
+
import type { DomainSyncContext, DomainSyncPlan } from '../types';
|
|
3
|
+
import type { SyncableView, SyncBackoffOptions, SyncFailureInfo, SyncTargetDescriptor } from '../types';
|
|
4
|
+
export interface JoinSyncTarget extends SyncTargetDescriptor {
|
|
5
|
+
type: 'join';
|
|
6
|
+
}
|
|
7
|
+
export interface JoinSyncSnapshot<TView extends SyncableView = SyncableView> {
|
|
8
|
+
id?: string;
|
|
9
|
+
updatedAt?: number;
|
|
10
|
+
view?: TView;
|
|
11
|
+
}
|
|
12
|
+
export interface JoinSyncPlanOptions<TView extends SyncableView = SyncableView> {
|
|
13
|
+
intervalMs?: number;
|
|
14
|
+
idleBackoff?: SyncBackoffOptions;
|
|
15
|
+
resetSnapshotOnConnected?: boolean;
|
|
16
|
+
onUpdate?: (target: JoinSyncTarget, view: TView, previous?: JoinSyncSnapshot<TView>) => void;
|
|
17
|
+
onRemove?: (target: JoinSyncTarget, previous?: JoinSyncSnapshot<TView>) => void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Single-join sync: polls `join.get`, applies on `updatedAt` change, re-pulls on a `join.sync` nudge.
|
|
21
|
+
* - Generic over the view type: inject the concrete view at the call site,
|
|
22
|
+
* e.g. `new JoinSyncPlan<$socials.JoinView>({ onUpdate })`.
|
|
23
|
+
*/
|
|
24
|
+
export declare class JoinSyncPlan<TView extends SyncableView = SyncableView> implements DomainSyncPlan<JoinSyncTarget> {
|
|
25
|
+
private readonly options;
|
|
26
|
+
readonly domain = "join";
|
|
27
|
+
readonly idleBackoff: SyncBackoffOptions;
|
|
28
|
+
constructor(options?: JoinSyncPlanOptions<TView>);
|
|
29
|
+
supports: (target: SyncTargetDescriptor) => target is JoinSyncTarget;
|
|
30
|
+
getKey: (target: JoinSyncTarget) => string;
|
|
31
|
+
getIntervalMs: (target: JoinSyncTarget) => number;
|
|
32
|
+
onConnected: (target: JoinSyncTarget, ctx: DomainSyncContext) => void;
|
|
33
|
+
run: (target: JoinSyncTarget, ctx: DomainSyncContext) => Promise<void>;
|
|
34
|
+
onTrigger: (target: JoinSyncTarget, message: SocketMessage<any>, ctx: DomainSyncContext) => Promise<void>;
|
|
35
|
+
onStopped: (target: JoinSyncTarget, _info: SyncFailureInfo, ctx: DomainSyncContext) => void;
|
|
36
|
+
updateLocalState: (target: JoinSyncTarget, snapshot: unknown, ctx: DomainSyncContext) => void;
|
|
37
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
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.JoinSyncPlan = void 0;
|
|
13
|
+
/**
|
|
14
|
+
* Single-join sync: polls `join.get`, applies on `updatedAt` change, re-pulls on a `join.sync` nudge.
|
|
15
|
+
* - Generic over the view type: inject the concrete view at the call site,
|
|
16
|
+
* e.g. `new JoinSyncPlan<$socials.JoinView>({ onUpdate })`.
|
|
17
|
+
*/
|
|
18
|
+
class JoinSyncPlan {
|
|
19
|
+
constructor(options = {}) {
|
|
20
|
+
var _a;
|
|
21
|
+
this.options = options;
|
|
22
|
+
this.domain = 'join';
|
|
23
|
+
this.supports = (target) => (target === null || target === void 0 ? void 0 : target.type) === 'join';
|
|
24
|
+
this.getKey = (target) => { var _a; return `join:${(_a = target === null || target === void 0 ? void 0 : target.id) !== null && _a !== void 0 ? _a : ''}`; };
|
|
25
|
+
// Default poll interval (10s); the scheduler backs this off x2 up to 60s while idle.
|
|
26
|
+
this.getIntervalMs = (target) => { var _a, _b; return (_b = (_a = target.intervalMs) !== null && _a !== void 0 ? _a : this.options.intervalMs) !== null && _b !== void 0 ? _b : 10000; };
|
|
27
|
+
this.onConnected = (target, ctx) => {
|
|
28
|
+
if (this.options.resetSnapshotOnConnected === false)
|
|
29
|
+
return;
|
|
30
|
+
ctx.writeSnapshot(target, undefined);
|
|
31
|
+
};
|
|
32
|
+
this.run = (target, ctx) => __awaiter(this, void 0, void 0, function* () {
|
|
33
|
+
var _b, _c, _d, _e;
|
|
34
|
+
if (!target.id)
|
|
35
|
+
return;
|
|
36
|
+
const prev = ctx.readSnapshot(target);
|
|
37
|
+
const input = { id: target.id };
|
|
38
|
+
const view = (yield ctx.client.request('join.get', input));
|
|
39
|
+
const nextUpdatedAt = typeof (view === null || view === void 0 ? void 0 : view.updatedAt) === 'number' ? view.updatedAt : undefined;
|
|
40
|
+
const prevUpdatedAt = typeof (prev === null || prev === void 0 ? void 0 : prev.updatedAt) === 'number' ? prev.updatedAt : undefined;
|
|
41
|
+
if (prevUpdatedAt === nextUpdatedAt && (prev === null || prev === void 0 ? void 0 : prev.view))
|
|
42
|
+
return;
|
|
43
|
+
const next = {
|
|
44
|
+
id: `${(_c = (_b = view === null || view === void 0 ? void 0 : view.id) !== null && _b !== void 0 ? _b : target.id) !== null && _c !== void 0 ? _c : ''}` || undefined,
|
|
45
|
+
updatedAt: nextUpdatedAt,
|
|
46
|
+
view,
|
|
47
|
+
};
|
|
48
|
+
ctx.writeSnapshot(target, next);
|
|
49
|
+
(_e = (_d = this.options).onUpdate) === null || _e === void 0 ? void 0 : _e.call(_d, target, view, prev);
|
|
50
|
+
});
|
|
51
|
+
this.onTrigger = (target, message, ctx) => __awaiter(this, void 0, void 0, function* () {
|
|
52
|
+
const data = ((message === null || message === void 0 ? void 0 : message.data) || {});
|
|
53
|
+
if (target.id && (data === null || data === void 0 ? void 0 : data.id) && target.id !== data.id)
|
|
54
|
+
return;
|
|
55
|
+
yield this.run(target, ctx);
|
|
56
|
+
});
|
|
57
|
+
this.onStopped = (target, _info, ctx) => {
|
|
58
|
+
var _a, _b;
|
|
59
|
+
const prev = ctx.readSnapshot(target);
|
|
60
|
+
(_b = (_a = this.options).onRemove) === null || _b === void 0 ? void 0 : _b.call(_a, target, prev);
|
|
61
|
+
};
|
|
62
|
+
this.updateLocalState = (target, snapshot, ctx) => {
|
|
63
|
+
var _a, _b;
|
|
64
|
+
const prev = ctx.readSnapshot(target);
|
|
65
|
+
const patch = (snapshot || {});
|
|
66
|
+
ctx.writeSnapshot(target, Object.assign(Object.assign(Object.assign({}, prev), patch), { view: (_a = patch.view) !== null && _a !== void 0 ? _a : prev === null || prev === void 0 ? void 0 : prev.view, updatedAt: (_b = patch.updatedAt) !== null && _b !== void 0 ? _b : prev === null || prev === void 0 ? void 0 : prev.updatedAt }));
|
|
67
|
+
};
|
|
68
|
+
this.idleBackoff = (_a = options.idleBackoff) !== null && _a !== void 0 ? _a : { factor: 2, maxMs: 60000 };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.JoinSyncPlan = JoinSyncPlan;
|
|
@@ -1,27 +1,31 @@
|
|
|
1
|
-
import type * as $backend from '@lemoncloud/chatic-backend-api';
|
|
2
1
|
import type { SocketMessage } from '../../lib/types';
|
|
3
|
-
import type { DomainSyncContext, DomainSyncPlan
|
|
2
|
+
import type { DomainSyncContext, DomainSyncPlan } from '../types';
|
|
3
|
+
import type { SyncableView, SyncBackoffOptions, SyncFailureInfo, SyncTargetDescriptor } from '../types';
|
|
4
4
|
export interface PlaceSyncTarget extends SyncTargetDescriptor {
|
|
5
5
|
type: 'place';
|
|
6
6
|
}
|
|
7
|
-
export interface PlaceSyncSnapshot {
|
|
7
|
+
export interface PlaceSyncSnapshot<TView extends SyncableView = SyncableView> {
|
|
8
8
|
id?: string;
|
|
9
9
|
updatedAt?: number;
|
|
10
|
-
view?:
|
|
10
|
+
view?: TView;
|
|
11
11
|
}
|
|
12
|
-
export interface PlaceSyncPlanOptions {
|
|
12
|
+
export interface PlaceSyncPlanOptions<TView extends SyncableView = SyncableView> {
|
|
13
13
|
intervalMs?: number;
|
|
14
14
|
idleBackoff?: SyncBackoffOptions;
|
|
15
15
|
resetSnapshotOnConnected?: boolean;
|
|
16
|
-
onUpdate?: (target: PlaceSyncTarget, view:
|
|
17
|
-
onRemove?: (target: PlaceSyncTarget, previous?: PlaceSyncSnapshot) => void;
|
|
16
|
+
onUpdate?: (target: PlaceSyncTarget, view: TView, previous?: PlaceSyncSnapshot<TView>) => void;
|
|
17
|
+
onRemove?: (target: PlaceSyncTarget, previous?: PlaceSyncSnapshot<TView>) => void;
|
|
18
18
|
}
|
|
19
|
-
/**
|
|
20
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Single-place sync: polls `place.get`, applies on `updatedAt` change, re-pulls on a `place.sync` nudge.
|
|
21
|
+
* - Generic over the view type: inject the concrete view at the call site,
|
|
22
|
+
* e.g. `new PlaceSyncPlan<$backend.MySiteView>({ onUpdate })`.
|
|
23
|
+
*/
|
|
24
|
+
export declare class PlaceSyncPlan<TView extends SyncableView = SyncableView> implements DomainSyncPlan<PlaceSyncTarget> {
|
|
21
25
|
private readonly options;
|
|
22
26
|
readonly domain = "place";
|
|
23
27
|
readonly idleBackoff: SyncBackoffOptions;
|
|
24
|
-
constructor(options?: PlaceSyncPlanOptions);
|
|
28
|
+
constructor(options?: PlaceSyncPlanOptions<TView>);
|
|
25
29
|
supports: (target: SyncTargetDescriptor) => target is PlaceSyncTarget;
|
|
26
30
|
getKey: (target: PlaceSyncTarget) => string;
|
|
27
31
|
getIntervalMs: (target: PlaceSyncTarget) => number;
|
|
@@ -10,7 +10,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.PlaceSyncPlan = void 0;
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* Single-place sync: polls `place.get`, applies on `updatedAt` change, re-pulls on a `place.sync` nudge.
|
|
15
|
+
* - Generic over the view type: inject the concrete view at the call site,
|
|
16
|
+
* e.g. `new PlaceSyncPlan<$backend.MySiteView>({ onUpdate })`.
|
|
17
|
+
*/
|
|
14
18
|
class PlaceSyncPlan {
|
|
15
19
|
constructor(options = {}) {
|
|
16
20
|
var _a;
|
|
@@ -30,7 +34,6 @@ class PlaceSyncPlan {
|
|
|
30
34
|
return;
|
|
31
35
|
const prev = ctx.readSnapshot(target);
|
|
32
36
|
const input = { id: target.id };
|
|
33
|
-
// place.get 응답은 backend 소유(registry response=unknown) → MySiteView 로 단언
|
|
34
37
|
const view = (yield ctx.client.request('place.get', input));
|
|
35
38
|
const nextUpdatedAt = typeof (view === null || view === void 0 ? void 0 : view.updatedAt) === 'number' ? view.updatedAt : undefined;
|
|
36
39
|
const prevUpdatedAt = typeof (prev === null || prev === void 0 ? void 0 : prev.updatedAt) === 'number' ? prev.updatedAt : undefined;
|
|
@@ -1,27 +1,31 @@
|
|
|
1
|
-
import type { ProfileView } from '@lemoncloud/chatic-socials-api';
|
|
2
1
|
import type { SocketMessage } from '../../lib/types';
|
|
3
|
-
import type { DomainSyncContext, DomainSyncPlan
|
|
2
|
+
import type { DomainSyncContext, DomainSyncPlan } from '../types';
|
|
3
|
+
import type { SyncableView, SyncBackoffOptions, SyncFailureInfo, SyncTargetDescriptor } from '../types';
|
|
4
4
|
export interface ProfileSyncTarget extends SyncTargetDescriptor {
|
|
5
5
|
type: 'profile';
|
|
6
6
|
}
|
|
7
|
-
export interface ProfileSyncSnapshot {
|
|
7
|
+
export interface ProfileSyncSnapshot<TView extends SyncableView = SyncableView> {
|
|
8
8
|
id?: string;
|
|
9
9
|
updatedAt?: number;
|
|
10
|
-
view?:
|
|
10
|
+
view?: TView;
|
|
11
11
|
}
|
|
12
|
-
export interface ProfileSyncPlanOptions {
|
|
12
|
+
export interface ProfileSyncPlanOptions<TView extends SyncableView = SyncableView> {
|
|
13
13
|
intervalMs?: number;
|
|
14
14
|
idleBackoff?: SyncBackoffOptions;
|
|
15
15
|
resetSnapshotOnConnected?: boolean;
|
|
16
|
-
onUpdate?: (target: ProfileSyncTarget, view:
|
|
17
|
-
onRemove?: (target: ProfileSyncTarget, previous?: ProfileSyncSnapshot) => void;
|
|
16
|
+
onUpdate?: (target: ProfileSyncTarget, view: TView, previous?: ProfileSyncSnapshot<TView>) => void;
|
|
17
|
+
onRemove?: (target: ProfileSyncTarget, previous?: ProfileSyncSnapshot<TView>) => void;
|
|
18
18
|
}
|
|
19
|
-
/**
|
|
20
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Single-profile sync: polls `profile.get`, applies on `updatedAt` change, re-pulls on a `profile.sync` nudge.
|
|
21
|
+
* - Generic over the view type: inject the concrete view at the call site,
|
|
22
|
+
* e.g. `new ProfileSyncPlan<$socials.ProfileView>({ onUpdate })`.
|
|
23
|
+
*/
|
|
24
|
+
export declare class ProfileSyncPlan<TView extends SyncableView = SyncableView> implements DomainSyncPlan<ProfileSyncTarget> {
|
|
21
25
|
private readonly options;
|
|
22
26
|
readonly domain = "profile";
|
|
23
27
|
readonly idleBackoff: SyncBackoffOptions;
|
|
24
|
-
constructor(options?: ProfileSyncPlanOptions);
|
|
28
|
+
constructor(options?: ProfileSyncPlanOptions<TView>);
|
|
25
29
|
supports: (target: SyncTargetDescriptor) => target is ProfileSyncTarget;
|
|
26
30
|
getKey: (target: ProfileSyncTarget) => string;
|
|
27
31
|
getIntervalMs: (target: ProfileSyncTarget) => number;
|
|
@@ -10,7 +10,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.ProfileSyncPlan = void 0;
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* Single-profile sync: polls `profile.get`, applies on `updatedAt` change, re-pulls on a `profile.sync` nudge.
|
|
15
|
+
* - Generic over the view type: inject the concrete view at the call site,
|
|
16
|
+
* e.g. `new ProfileSyncPlan<$socials.ProfileView>({ onUpdate })`.
|
|
17
|
+
*/
|
|
14
18
|
class ProfileSyncPlan {
|
|
15
19
|
constructor(options = {}) {
|
|
16
20
|
var _a;
|
|
@@ -30,7 +34,6 @@ class ProfileSyncPlan {
|
|
|
30
34
|
return;
|
|
31
35
|
const prev = ctx.readSnapshot(target);
|
|
32
36
|
const input = { id: target.id };
|
|
33
|
-
// profile.get 응답은 socials 소유(registry response=unknown) → ProfileView 로 단언
|
|
34
37
|
const view = (yield ctx.client.request('profile.get', input));
|
|
35
38
|
const nextUpdatedAt = typeof (view === null || view === void 0 ? void 0 : view.updatedAt) === 'number' ? view.updatedAt : undefined;
|
|
36
39
|
const prevUpdatedAt = typeof (prev === null || prev === void 0 ? void 0 : prev.updatedAt) === 'number' ? prev.updatedAt : undefined;
|
|
@@ -117,6 +117,18 @@ export interface ClientSocketV2 {
|
|
|
117
117
|
destroy(): void;
|
|
118
118
|
}
|
|
119
119
|
export declare type SyncTargetType = string;
|
|
120
|
+
/**
|
|
121
|
+
* Minimal view shape a polling sync plan depends on — nothing else is read from the view.
|
|
122
|
+
* Concrete view types are owned by the external API, so plans stay generic over the view
|
|
123
|
+
* and the consumer injects the concrete type at the call site; this keeps the published
|
|
124
|
+
* `.d.ts` free of external-API dependencies.
|
|
125
|
+
*/
|
|
126
|
+
export interface SyncableView {
|
|
127
|
+
/** Stable identifier of the synced entity. */
|
|
128
|
+
id?: string;
|
|
129
|
+
/** Convergence axis — the plan re-applies the view only when this value changes. */
|
|
130
|
+
updatedAt?: number;
|
|
131
|
+
}
|
|
120
132
|
export interface SyncTargetDescriptor {
|
|
121
133
|
type: SyncTargetType;
|
|
122
134
|
id?: string;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `lib/join/contracts.ts`
|
|
3
|
+
* - client-safe join domain contracts.
|
|
4
|
+
* - keep this file free from server-only runtime dependencies.
|
|
5
|
+
*/
|
|
6
|
+
export declare type JoinNotify = '' | 'all' | 'mention' | 'none';
|
|
7
|
+
/**
|
|
8
|
+
* client-safe join view shared across websocket client/server contracts.
|
|
9
|
+
* - mirrors the v1 (demo) JoinModel projection; the server `modelAsView` output is assignable to it.
|
|
10
|
+
* - socials responses are a superset and are injected as a concrete view by the consumer where needed.
|
|
11
|
+
* - kept free of `modules/*` imports so the published client `.d.ts` carries no server models.
|
|
12
|
+
*/
|
|
13
|
+
export interface JoinView {
|
|
14
|
+
id?: string;
|
|
15
|
+
channelId?: string;
|
|
16
|
+
ownerId?: string;
|
|
17
|
+
stereo?: string;
|
|
18
|
+
chatNo?: number;
|
|
19
|
+
joined?: boolean;
|
|
20
|
+
updatedAt?: number;
|
|
21
|
+
}
|
|
22
|
+
/** `join.get` request input — composite join id, client-supplied. */
|
|
23
|
+
export interface JoinGetRequestBody {
|
|
24
|
+
id: string;
|
|
25
|
+
}
|
|
26
|
+
/** `join.update` request input — edit join metadata (nick/notify). */
|
|
27
|
+
export interface JoinUpdateRequestBody {
|
|
28
|
+
id: string;
|
|
29
|
+
nick?: string;
|
|
30
|
+
notify?: JoinNotify;
|
|
31
|
+
role?: 'owner' | 'admin' | 'member' | string;
|
|
32
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { InferSocketError, InferSocketRequest, InferSocketResponse, SocketErrorMessage, SocketRequestMessage, SocketResponseMessage } from '../types';
|
|
2
|
+
import type { JoinView, JoinGetRequestBody, JoinUpdateRequestBody } from './contracts';
|
|
3
|
+
declare module '../types' {
|
|
4
|
+
interface SocketPacketRegistry {
|
|
5
|
+
'join.get': {
|
|
6
|
+
request: JoinGetRequestBody;
|
|
7
|
+
response: JoinView;
|
|
8
|
+
error: null;
|
|
9
|
+
};
|
|
10
|
+
'join.update': {
|
|
11
|
+
request: JoinUpdateRequestBody;
|
|
12
|
+
response: JoinView;
|
|
13
|
+
error: null;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export declare type JoinGetType = 'join.get';
|
|
18
|
+
export declare type JoinGetResponseData = InferSocketResponse<JoinGetType>;
|
|
19
|
+
export declare type JoinGetErrorData = InferSocketError<JoinGetType>;
|
|
20
|
+
export declare type JoinGetInput = InferSocketRequest<JoinGetType>;
|
|
21
|
+
export declare type JoinGetRequestMessage = SocketRequestMessage<JoinGetType>;
|
|
22
|
+
export declare type JoinGetResponseMessage = SocketResponseMessage<JoinGetType>;
|
|
23
|
+
export declare type JoinGetErrorMessage = SocketErrorMessage<JoinGetType>;
|
|
24
|
+
export declare type JoinUpdateType = 'join.update';
|
|
25
|
+
export declare type JoinUpdateResponseData = InferSocketResponse<JoinUpdateType>;
|
|
26
|
+
export declare type JoinUpdateErrorData = InferSocketError<JoinUpdateType>;
|
|
27
|
+
export declare type JoinUpdateInput = InferSocketRequest<JoinUpdateType>;
|
|
28
|
+
export declare type JoinUpdateRequestMessage = SocketRequestMessage<JoinUpdateType>;
|
|
29
|
+
export declare type JoinUpdateResponseMessage = SocketResponseMessage<JoinUpdateType>;
|
|
30
|
+
export declare type JoinUpdateErrorMessage = SocketErrorMessage<JoinUpdateType>;
|
|
31
|
+
export type { JoinView };
|
|
@@ -36,6 +36,8 @@ export declare const SocketActionTypeLUT: {
|
|
|
36
36
|
readonly profile: "profile";
|
|
37
37
|
/** cloud - cloud profile operations */
|
|
38
38
|
readonly cloud: "cloud";
|
|
39
|
+
/** join - channel join/membership operations */
|
|
40
|
+
readonly join: "join";
|
|
39
41
|
};
|
|
40
42
|
/**
|
|
41
43
|
* SystemActionType
|
|
@@ -188,6 +190,17 @@ export declare const SocketActionTypeLUT: {
|
|
|
188
190
|
/** sync - synchronize site multi-profiles (delta since cursor) */
|
|
189
191
|
readonly sync: "sync";
|
|
190
192
|
};
|
|
193
|
+
/**
|
|
194
|
+
* JoinActionType
|
|
195
|
+
* - join 도메인 액션
|
|
196
|
+
*/
|
|
197
|
+
readonly JoinActionType: {
|
|
198
|
+
readonly '': "";
|
|
199
|
+
/** get - get join record by composite id */
|
|
200
|
+
readonly get: "get";
|
|
201
|
+
/** update - update caller's join metadata (nick/notify) */
|
|
202
|
+
readonly update: "update";
|
|
203
|
+
};
|
|
191
204
|
/**
|
|
192
205
|
* CloudActionType
|
|
193
206
|
* - cloud 도메인 액션
|
|
@@ -250,10 +263,14 @@ export declare type SocketProfileActionType = SocketActionKeyOf<typeof SocketAct
|
|
|
250
263
|
* type: `SocketCloudActionType`
|
|
251
264
|
*/
|
|
252
265
|
export declare type SocketCloudActionType = SocketActionKeyOf<typeof SocketActionTypeLUT.CloudActionType>;
|
|
266
|
+
/**
|
|
267
|
+
* type: `SocketJoinActionType`
|
|
268
|
+
*/
|
|
269
|
+
export declare type SocketJoinActionType = SocketActionKeyOf<typeof SocketActionTypeLUT.JoinActionType>;
|
|
253
270
|
/**
|
|
254
271
|
* type: `SocketActionType`
|
|
255
272
|
*/
|
|
256
|
-
export declare type SocketActionType = SocketSystemActionType | SocketSocketsActionType | SocketDeviceActionType | SocketAuthActionType | SocketChannelActionType | SocketChatActionType | SocketUserActionType | SocketPlaceActionType | SocketProfileActionType | SocketCloudActionType;
|
|
273
|
+
export declare type SocketActionType = SocketSystemActionType | SocketSocketsActionType | SocketDeviceActionType | SocketAuthActionType | SocketChannelActionType | SocketChatActionType | SocketUserActionType | SocketPlaceActionType | SocketProfileActionType | SocketCloudActionType | SocketJoinActionType;
|
|
257
274
|
/**
|
|
258
275
|
* interface: `SocketActionTypeMap`
|
|
259
276
|
* - domain to action type map
|
|
@@ -269,6 +286,7 @@ export interface SocketActionTypeMap {
|
|
|
269
286
|
place: SocketPlaceActionType;
|
|
270
287
|
profile: SocketProfileActionType;
|
|
271
288
|
cloud: SocketCloudActionType;
|
|
289
|
+
join: SocketJoinActionType;
|
|
272
290
|
}
|
|
273
291
|
/**
|
|
274
292
|
* type: `SocketSupportedDomainType`
|
|
@@ -39,6 +39,8 @@ exports.SocketActionTypeLUT = {
|
|
|
39
39
|
profile: 'profile',
|
|
40
40
|
/** cloud - cloud profile operations */
|
|
41
41
|
cloud: 'cloud',
|
|
42
|
+
/** join - channel join/membership operations */
|
|
43
|
+
join: 'join',
|
|
42
44
|
},
|
|
43
45
|
/**
|
|
44
46
|
* SystemActionType
|
|
@@ -191,6 +193,17 @@ exports.SocketActionTypeLUT = {
|
|
|
191
193
|
/** sync - synchronize site multi-profiles (delta since cursor) */
|
|
192
194
|
sync: 'sync',
|
|
193
195
|
},
|
|
196
|
+
/**
|
|
197
|
+
* JoinActionType
|
|
198
|
+
* - join 도메인 액션
|
|
199
|
+
*/
|
|
200
|
+
JoinActionType: {
|
|
201
|
+
'': '',
|
|
202
|
+
/** get - get join record by composite id */
|
|
203
|
+
get: 'get',
|
|
204
|
+
/** update - update caller's join metadata (nick/notify) */
|
|
205
|
+
update: 'update',
|
|
206
|
+
},
|
|
194
207
|
/**
|
|
195
208
|
* CloudActionType
|
|
196
209
|
* - cloud 도메인 액션
|
|
@@ -13,3 +13,4 @@ export type { PlaceCreateInput, PlaceDeleteInput, PlaceGetInput, PlaceUpdateInpu
|
|
|
13
13
|
export type { ProfileGetInput, ProfileGetMineInput, ProfileSetInput, ProfileSyncInput } from './profile/types';
|
|
14
14
|
export type { CloudCreateInput, CloudDeleteInput, CloudGetInput, CloudUpdateInput, UpdateCloudInput, } from './cloud/types';
|
|
15
15
|
export type { UserGetSiteProfileInput, UserInviteBatchInput, UserInviteInput, UserMakeSiteInput, UserMySiteInput, UserSetSiteProfileInput, UserUpdateProfileInput, UserUpdateSiteInput, } from './user/types';
|
|
16
|
+
export type { JoinGetInput, JoinUpdateInput as JoinDomainUpdateInput } from './join/types';
|
package/package.json
CHANGED