@lemoncloud/chatic-sockets-lib 0.3.2 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,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, SyncBackoffOptions, SyncFailureInfo, SyncTargetDescriptor } from '../types';
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?: ChannelView;
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: ChannelView, previous?: ChannelSyncSnapshot) => void;
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
- /** Single-channel sync: polls `channel.get`, applies on `updatedAt` change, re-pulls on a `channel.sync` nudge. */
20
- export declare class ChannelSyncPlan implements DomainSyncPlan<ChannelSyncTarget> {
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
- /** Single-channel sync: polls `channel.get`, applies on `updatedAt` change, re-pulls on a `channel.sync` nudge. */
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, SyncBackoffOptions, SyncFailureInfo, SyncTargetDescriptor } from '../types';
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: ChatView[];
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: ChatView[], snapshot: ChatSyncSnapshot) => void;
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, SyncBackoffOptions, SyncFailureInfo, SyncTargetDescriptor } from '../types';
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?: $backend.MySiteView;
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: $backend.MySiteView, previous?: PlaceSyncSnapshot) => void;
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
- /** Single-place sync: polls `place.get`, applies on `updatedAt` change, re-pulls on a `place.sync` nudge. */
20
- export declare class PlaceSyncPlan implements DomainSyncPlan<PlaceSyncTarget> {
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
- /** Single-place sync: polls `place.get`, applies on `updatedAt` change, re-pulls on a `place.sync` nudge. */
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, SyncBackoffOptions, SyncFailureInfo, SyncTargetDescriptor } from '../types';
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?: ProfileView;
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: ProfileView, previous?: ProfileSyncSnapshot) => void;
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
- /** Single-profile sync: polls `profile.get`, applies on `updatedAt` change, re-pulls on a `profile.sync` nudge. */
20
- export declare class ProfileSyncPlan implements DomainSyncPlan<ProfileSyncTarget> {
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
- /** Single-profile sync: polls `profile.get`, applies on `updatedAt` change, re-pulls on a `profile.sync` nudge. */
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,7 @@
1
+ "use strict";
2
+ /**
3
+ * `lib/join/contracts.ts`
4
+ * - client-safe join domain contracts.
5
+ * - keep this file free from server-only runtime dependencies.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -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 };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lemoncloud/chatic-sockets-lib",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Client websocket transport and sync runtime for chatic sockets v2",
5
5
  "main": "dist/client-socket-v2/index.js",
6
6
  "types": "dist/client-socket-v2/index.d.ts",