@fluxy-chat/agent 0.1.0

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,59 @@
1
+ import { FluxyChatClient, FluxyMessageStream, type FluxyChatMessage, type FluxyRoomConnectionOptions, type FluxyWaitForOptions } from "@fluxy-chat/sdk";
2
+ export { FluxyAuthError, FluxyConnectionError, FluxySendError, FluxyTimeoutError, } from "@fluxy-chat/sdk";
3
+ export { mintWorkerToken, type MintTokenInput, type MintTokenResult } from "./mint";
4
+ export interface FluxyAgentConfig {
5
+ /** Agent id — used as JWT `sub` / message `userId` (must match a row in `agents` for invoke). */
6
+ id: string;
7
+ name: string;
8
+ /** Project API key (`fc_…`) from the Worker / console. */
9
+ apiKey: string;
10
+ baseUrl?: string;
11
+ /** JWT roles (default `["member"]`). Use `["admin"]` only for bootstrap helpers. */
12
+ roles?: string[];
13
+ tokenTtlSeconds?: number;
14
+ }
15
+ export interface FluxyAgentJoinOptions {
16
+ /** POST /rooms/:id/members with a short-lived admin token if the agent is not in the room yet. */
17
+ ensureMembership?: boolean;
18
+ connection?: FluxyRoomConnectionOptions;
19
+ }
20
+ export declare class FluxyRoom {
21
+ readonly id: string;
22
+ constructor(roomId: string);
23
+ }
24
+ type RoomListener = (message: FluxyChatMessage) => void;
25
+ export declare class FluxyAgent {
26
+ readonly id: string;
27
+ readonly name: string;
28
+ private readonly apiKey;
29
+ private readonly baseUrl;
30
+ private readonly roles;
31
+ private readonly tokenTtlSeconds;
32
+ private token;
33
+ private client;
34
+ private readonly connections;
35
+ private readonly roomListeners;
36
+ constructor(config: FluxyAgentConfig);
37
+ /** Mint JWT via Worker `POST /auth/token` and prepare REST/WS client. */
38
+ init(): Promise<this>;
39
+ getClient(): FluxyChatClient;
40
+ room(roomId: string): FluxyRoom;
41
+ join(room: FluxyRoom | string, options?: FluxyAgentJoinOptions): Promise<void>;
42
+ leave(room: FluxyRoom | string): void;
43
+ disconnect(): void;
44
+ on(room: FluxyRoom | string, callback: RoomListener): void;
45
+ off(room: FluxyRoom | string, callback: RoomListener): void;
46
+ send(room: FluxyRoom | string, content: string, replyTo?: number | null): void;
47
+ createStream(room: FluxyRoom | string, options?: {
48
+ parentId?: number | null;
49
+ flushIntervalMs?: number;
50
+ }): FluxyMessageStream;
51
+ waitFor(room: FluxyRoom | string, predicate: (message: FluxyChatMessage) => boolean, options?: FluxyWaitForOptions): Promise<FluxyChatMessage>;
52
+ invoke(room: FluxyRoom | string, content: string, options?: {
53
+ replyTo?: number | null;
54
+ }): Promise<Awaited<ReturnType<FluxyChatClient["invokeAgentRest"]>>>;
55
+ private getConnection;
56
+ private ensureRoomMembership;
57
+ }
58
+ export declare function createFluxyAgent(config: FluxyAgentConfig): Promise<FluxyAgent>;
59
+ export type { FluxyChatMessage, FluxyMessageStream, FluxyWaitForOptions };
package/dist/index.js ADDED
@@ -0,0 +1,183 @@
1
+ import { FluxyChatClient, FluxyMessageStream, buildAgentOutboundWsPayload, } from "@fluxy-chat/sdk";
2
+ import { mintWorkerToken } from "./mint";
3
+ export { FluxyAuthError, FluxyConnectionError, FluxySendError, FluxyTimeoutError, } from "@fluxy-chat/sdk";
4
+ export { mintWorkerToken } from "./mint";
5
+ const DEFAULT_BASE_URL = "http://127.0.0.1:8787";
6
+ function trimTrailingSlashes(url) {
7
+ let out = url;
8
+ while (out.endsWith("/"))
9
+ out = out.slice(0, -1);
10
+ return out;
11
+ }
12
+ export class FluxyRoom {
13
+ constructor(roomId) {
14
+ this.id = roomId;
15
+ }
16
+ }
17
+ export class FluxyAgent {
18
+ constructor(config) {
19
+ this.token = null;
20
+ this.client = null;
21
+ this.connections = new Map();
22
+ this.roomListeners = new Map();
23
+ if (!config.id?.trim())
24
+ throw new Error("FluxyAgent requires id");
25
+ if (!config.apiKey?.trim())
26
+ throw new Error("FluxyAgent requires apiKey");
27
+ this.id = config.id.trim();
28
+ this.name = config.name?.trim() || this.id;
29
+ this.apiKey = config.apiKey.trim();
30
+ this.baseUrl = trimTrailingSlashes(config.baseUrl ?? DEFAULT_BASE_URL);
31
+ this.roles = config.roles?.length ? config.roles : ["member"];
32
+ this.tokenTtlSeconds = config.tokenTtlSeconds ?? 3600;
33
+ }
34
+ /** Mint JWT via Worker `POST /auth/token` and prepare REST/WS client. */
35
+ async init() {
36
+ const minted = await mintWorkerToken({
37
+ baseUrl: this.baseUrl,
38
+ apiKey: this.apiKey,
39
+ userId: this.id,
40
+ roles: this.roles,
41
+ ttlSeconds: this.tokenTtlSeconds,
42
+ });
43
+ this.token = minted.token;
44
+ this.client = new FluxyChatClient({
45
+ baseUrl: this.baseUrl,
46
+ userId: this.id,
47
+ token: this.token,
48
+ apiKey: this.apiKey,
49
+ });
50
+ return this;
51
+ }
52
+ getClient() {
53
+ if (!this.client || !this.token) {
54
+ throw new Error("Call init() before using the agent client.");
55
+ }
56
+ return this.client;
57
+ }
58
+ room(roomId) {
59
+ return new FluxyRoom(roomId);
60
+ }
61
+ async join(room, options = {}) {
62
+ const roomId = typeof room === "string" ? room : room.id;
63
+ if (this.connections.has(roomId))
64
+ return;
65
+ if (options.ensureMembership) {
66
+ await this.ensureRoomMembership(roomId);
67
+ }
68
+ const client = this.getClient();
69
+ const connection = client.connectRoom(roomId, options.connection);
70
+ connection.addEventListener("message", (event) => {
71
+ if (event.type !== "message")
72
+ return;
73
+ const listeners = this.roomListeners.get(roomId);
74
+ if (!listeners)
75
+ return;
76
+ for (const cb of listeners) {
77
+ try {
78
+ cb(event);
79
+ }
80
+ catch {
81
+ /* ignore listener errors */
82
+ }
83
+ }
84
+ });
85
+ this.connections.set(roomId, connection);
86
+ connection.connect();
87
+ }
88
+ leave(room) {
89
+ const roomId = typeof room === "string" ? room : room.id;
90
+ const connection = this.connections.get(roomId);
91
+ if (!connection)
92
+ return;
93
+ connection.close();
94
+ this.connections.delete(roomId);
95
+ this.roomListeners.delete(roomId);
96
+ }
97
+ disconnect() {
98
+ for (const connection of this.connections.values()) {
99
+ connection.close();
100
+ }
101
+ this.connections.clear();
102
+ this.roomListeners.clear();
103
+ }
104
+ on(room, callback) {
105
+ const roomId = typeof room === "string" ? room : room.id;
106
+ const set = this.roomListeners.get(roomId) ?? new Set();
107
+ set.add(callback);
108
+ this.roomListeners.set(roomId, set);
109
+ }
110
+ off(room, callback) {
111
+ const roomId = typeof room === "string" ? room : room.id;
112
+ const set = this.roomListeners.get(roomId);
113
+ if (!set)
114
+ return;
115
+ set.delete(callback);
116
+ if (set.size === 0)
117
+ this.roomListeners.delete(roomId);
118
+ }
119
+ send(room, content, replyTo) {
120
+ const roomId = typeof room === "string" ? room : room.id;
121
+ const connection = this.getConnection(roomId, "send");
122
+ connection.sendJson(buildAgentOutboundWsPayload({
123
+ userId: this.id,
124
+ content,
125
+ parentId: replyTo ?? null,
126
+ attachments: [],
127
+ }));
128
+ }
129
+ createStream(room, options) {
130
+ const roomId = typeof room === "string" ? room : room.id;
131
+ const connection = this.getConnection(roomId, "createStream");
132
+ return new FluxyMessageStream(connection, this.id, {
133
+ parentId: options?.parentId ?? null,
134
+ flushIntervalMs: options?.flushIntervalMs,
135
+ });
136
+ }
137
+ waitFor(room, predicate, options) {
138
+ const roomId = typeof room === "string" ? room : room.id;
139
+ const connection = this.getConnection(roomId, "waitFor");
140
+ return connection.waitFor((event) => event.type === "message" && predicate(event), options);
141
+ }
142
+ async invoke(room, content, options) {
143
+ const roomId = typeof room === "string" ? room : room.id;
144
+ return this.getClient().invokeAgentRest(this.id, roomId, content, {
145
+ replyTo: options?.replyTo,
146
+ });
147
+ }
148
+ getConnection(roomId, op) {
149
+ const connection = this.connections.get(roomId);
150
+ if (!connection) {
151
+ throw new Error(`Agent "${this.id}" has not joined room "${roomId}". Call join() before ${op}().`);
152
+ }
153
+ return connection;
154
+ }
155
+ async ensureRoomMembership(roomId) {
156
+ const admin = await mintWorkerToken({
157
+ baseUrl: this.baseUrl,
158
+ apiKey: this.apiKey,
159
+ userId: this.id,
160
+ roles: ["admin"],
161
+ ttlSeconds: 120,
162
+ });
163
+ const adminClient = new FluxyChatClient({
164
+ baseUrl: this.baseUrl,
165
+ userId: this.id,
166
+ token: admin.token,
167
+ });
168
+ try {
169
+ await adminClient.addRoomMember(roomId, this.id, "member");
170
+ }
171
+ catch (err) {
172
+ const message = err instanceof Error ? err.message : String(err);
173
+ if (!message.includes("409") && !message.toLowerCase().includes("already")) {
174
+ throw err;
175
+ }
176
+ }
177
+ }
178
+ }
179
+ export async function createFluxyAgent(config) {
180
+ const agent = new FluxyAgent(config);
181
+ await agent.init();
182
+ return agent;
183
+ }
package/dist/mint.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ export interface MintTokenInput {
2
+ baseUrl: string;
3
+ apiKey: string;
4
+ userId: string;
5
+ roles?: string[];
6
+ ttlSeconds?: number;
7
+ }
8
+ export interface MintTokenResult {
9
+ token: string;
10
+ expiresIn: number;
11
+ claims: {
12
+ sub: string;
13
+ tid: string;
14
+ roles: string[];
15
+ };
16
+ }
17
+ export declare function mintWorkerToken(input: MintTokenInput): Promise<MintTokenResult>;
package/dist/mint.js ADDED
@@ -0,0 +1,29 @@
1
+ function trimTrailingSlashes(url) {
2
+ let out = url;
3
+ while (out.endsWith("/"))
4
+ out = out.slice(0, -1);
5
+ return out;
6
+ }
7
+ export async function mintWorkerToken(input) {
8
+ const base = trimTrailingSlashes(input.baseUrl);
9
+ const res = await fetch(`${base}/auth/token`, {
10
+ method: "POST",
11
+ headers: {
12
+ "Content-Type": "application/json",
13
+ "X-Fluxy-Api-Key": input.apiKey,
14
+ },
15
+ body: JSON.stringify({
16
+ userId: input.userId,
17
+ roles: input.roles ?? ["member"],
18
+ ttlSeconds: input.ttlSeconds ?? 3600,
19
+ }),
20
+ });
21
+ const json = (await res.json().catch(() => ({})));
22
+ if (!res.ok) {
23
+ throw new Error(json.error || `Mint token failed (${res.status})`);
24
+ }
25
+ if (!json.token) {
26
+ throw new Error("Worker did not return a token");
27
+ }
28
+ return json;
29
+ }
@@ -0,0 +1,56 @@
1
+ import { FluxyChatClient, FluxyMessageStream, type FluxyChatAgentRun, type FluxyChatMessage, type FluxyRoomConnectionOptions, type FluxyWaitForOptions } from "@fluxychat/sdk";
2
+ export { FluxyAuthError, FluxyConnectionError, FluxySendError, FluxyTimeoutError, } from "@fluxychat/sdk";
3
+ export { mintWorkerToken, type MintTokenInput, type MintTokenResult } from "./mint";
4
+ export interface FluxyAgentConfig {
5
+ /** Agent id used as JWT `sub` / message `userId` (must match a row in `agents` for invoke). */
6
+ id: string;
7
+ name: string;
8
+ /** Project API key (`fc_…`) from the Worker / console. */
9
+ apiKey: string;
10
+ baseUrl?: string;
11
+ /** JWT roles (default `["member"]`). Use `["admin"]` only for bootstrap helpers. */
12
+ roles?: string[];
13
+ tokenTtlSeconds?: number;
14
+ }
15
+ export interface FluxyAgentJoinOptions {
16
+ /** POST /rooms/:id/members with a short-lived admin token if the agent is not in the room yet. */
17
+ ensureMembership?: boolean;
18
+ connection?: FluxyRoomConnectionOptions;
19
+ }
20
+ export declare class FluxyRoom {
21
+ readonly id: string;
22
+ constructor(roomId: string);
23
+ }
24
+ type RoomListener = (message: FluxyChatMessage) => void;
25
+ export declare class FluxyAgent {
26
+ readonly id: string;
27
+ readonly name: string;
28
+ private readonly apiKey;
29
+ private readonly baseUrl;
30
+ private readonly roles;
31
+ private readonly tokenTtlSeconds;
32
+ private token;
33
+ private client;
34
+ private readonly connections;
35
+ private readonly roomListeners;
36
+ constructor(config: FluxyAgentConfig);
37
+ /** Mint JWT via Worker `POST /auth/token` and prepare REST/WS client. */
38
+ init(): Promise<this>;
39
+ getClient(): FluxyChatClient;
40
+ room(roomId: string): FluxyRoom;
41
+ join(room: FluxyRoom | string, options?: FluxyAgentJoinOptions): Promise<void>;
42
+ leave(room: FluxyRoom | string): void;
43
+ disconnect(): void;
44
+ on(room: FluxyRoom | string, callback: RoomListener): void;
45
+ off(room: FluxyRoom | string, callback: RoomListener): void;
46
+ send(room: FluxyRoom | string, content: string, replyTo?: number | null): void;
47
+ createStream(room: FluxyRoom | string): FluxyMessageStream;
48
+ waitFor(room: FluxyRoom | string, predicate: (message: FluxyChatMessage) => boolean, options?: FluxyWaitForOptions): Promise<FluxyChatMessage>;
49
+ invoke(room: FluxyRoom | string, content: string, options?: {
50
+ replyTo?: number | null;
51
+ }): Promise<FluxyChatAgentRun>;
52
+ private getConnection;
53
+ private ensureRoomMembership;
54
+ }
55
+ export declare function createFluxyAgent(config: FluxyAgentConfig): Promise<FluxyAgent>;
56
+ export type { FluxyChatMessage, FluxyChatAgentRun, FluxyMessageStream, FluxyWaitForOptions };
@@ -0,0 +1,175 @@
1
+ import { FluxyChatClient, FluxyMessageStream, } from "@fluxychat/sdk";
2
+ import { mintWorkerToken } from "./mint";
3
+ export { FluxyAuthError, FluxyConnectionError, FluxySendError, FluxyTimeoutError, } from "@fluxychat/sdk";
4
+ export { mintWorkerToken } from "./mint";
5
+ const DEFAULT_BASE_URL = "http://127.0.0.1:8787";
6
+ export class FluxyRoom {
7
+ constructor(roomId) {
8
+ this.id = roomId;
9
+ }
10
+ }
11
+ export class FluxyAgent {
12
+ constructor(config) {
13
+ this.token = null;
14
+ this.client = null;
15
+ this.connections = new Map();
16
+ this.roomListeners = new Map();
17
+ if (!config.id?.trim())
18
+ throw new Error("FluxyAgent requires id");
19
+ if (!config.apiKey?.trim())
20
+ throw new Error("FluxyAgent requires apiKey");
21
+ this.id = config.id.trim();
22
+ this.name = config.name?.trim() || this.id;
23
+ this.apiKey = config.apiKey.trim();
24
+ this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
25
+ this.roles = config.roles?.length ? config.roles : ["member"];
26
+ this.tokenTtlSeconds = config.tokenTtlSeconds ?? 3600;
27
+ }
28
+ /** Mint JWT via Worker `POST /auth/token` and prepare REST/WS client. */
29
+ async init() {
30
+ const minted = await mintWorkerToken({
31
+ baseUrl: this.baseUrl,
32
+ apiKey: this.apiKey,
33
+ userId: this.id,
34
+ roles: this.roles,
35
+ ttlSeconds: this.tokenTtlSeconds,
36
+ });
37
+ this.token = minted.token;
38
+ this.client = new FluxyChatClient({
39
+ baseUrl: this.baseUrl,
40
+ userId: this.id,
41
+ token: this.token,
42
+ apiKey: this.apiKey,
43
+ });
44
+ return this;
45
+ }
46
+ getClient() {
47
+ if (!this.client || !this.token) {
48
+ throw new Error("Call init() before using the agent client.");
49
+ }
50
+ return this.client;
51
+ }
52
+ room(roomId) {
53
+ return new FluxyRoom(roomId);
54
+ }
55
+ async join(room, options = {}) {
56
+ const roomId = typeof room === "string" ? room : room.id;
57
+ if (this.connections.has(roomId))
58
+ return;
59
+ if (options.ensureMembership) {
60
+ await this.ensureRoomMembership(roomId);
61
+ }
62
+ const client = this.getClient();
63
+ const connection = client.connectRoom(roomId, options.connection);
64
+ connection.addEventListener("message", (event) => {
65
+ if (event.type !== "message")
66
+ return;
67
+ const listeners = this.roomListeners.get(roomId);
68
+ if (!listeners)
69
+ return;
70
+ for (const cb of listeners) {
71
+ try {
72
+ cb(event);
73
+ }
74
+ catch {
75
+ /* ignore listener errors */
76
+ }
77
+ }
78
+ });
79
+ this.connections.set(roomId, connection);
80
+ connection.connect();
81
+ }
82
+ leave(room) {
83
+ const roomId = typeof room === "string" ? room : room.id;
84
+ const connection = this.connections.get(roomId);
85
+ if (!connection)
86
+ return;
87
+ connection.close();
88
+ this.connections.delete(roomId);
89
+ this.roomListeners.delete(roomId);
90
+ }
91
+ disconnect() {
92
+ for (const connection of this.connections.values()) {
93
+ connection.close();
94
+ }
95
+ this.connections.clear();
96
+ this.roomListeners.clear();
97
+ }
98
+ on(room, callback) {
99
+ const roomId = typeof room === "string" ? room : room.id;
100
+ const set = this.roomListeners.get(roomId) ?? new Set();
101
+ set.add(callback);
102
+ this.roomListeners.set(roomId, set);
103
+ }
104
+ off(room, callback) {
105
+ const roomId = typeof room === "string" ? room : room.id;
106
+ const set = this.roomListeners.get(roomId);
107
+ if (!set)
108
+ return;
109
+ set.delete(callback);
110
+ if (set.size === 0)
111
+ this.roomListeners.delete(roomId);
112
+ }
113
+ send(room, content, replyTo) {
114
+ const roomId = typeof room === "string" ? room : room.id;
115
+ const connection = this.getConnection(roomId, "send");
116
+ connection.sendJson({
117
+ type: "message",
118
+ userId: this.id,
119
+ content,
120
+ parentId: replyTo ?? null,
121
+ attachments: [],
122
+ });
123
+ }
124
+ createStream(room) {
125
+ const roomId = typeof room === "string" ? room : room.id;
126
+ const connection = this.getConnection(roomId, "createStream");
127
+ return new FluxyMessageStream(connection, this.id);
128
+ }
129
+ waitFor(room, predicate, options) {
130
+ const roomId = typeof room === "string" ? room : room.id;
131
+ const connection = this.getConnection(roomId, "waitFor");
132
+ return connection.waitFor((event) => event.type === "message" && predicate(event), options);
133
+ }
134
+ async invoke(room, content, options) {
135
+ const roomId = typeof room === "string" ? room : room.id;
136
+ return this.getClient().invokeAgentRest(this.id, roomId, content, {
137
+ replyTo: options?.replyTo,
138
+ });
139
+ }
140
+ getConnection(roomId, op) {
141
+ const connection = this.connections.get(roomId);
142
+ if (!connection) {
143
+ throw new Error(`Agent "${this.id}" has not joined room "${roomId}". Call join() before ${op}().`);
144
+ }
145
+ return connection;
146
+ }
147
+ async ensureRoomMembership(roomId) {
148
+ const admin = await mintWorkerToken({
149
+ baseUrl: this.baseUrl,
150
+ apiKey: this.apiKey,
151
+ userId: this.id,
152
+ roles: ["admin"],
153
+ ttlSeconds: 120,
154
+ });
155
+ const adminClient = new FluxyChatClient({
156
+ baseUrl: this.baseUrl,
157
+ userId: this.id,
158
+ token: admin.token,
159
+ });
160
+ try {
161
+ await adminClient.addRoomMember(roomId, this.id, "member");
162
+ }
163
+ catch (err) {
164
+ const message = err instanceof Error ? err.message : String(err);
165
+ if (!message.includes("409") && !message.toLowerCase().includes("already")) {
166
+ throw err;
167
+ }
168
+ }
169
+ }
170
+ }
171
+ export async function createFluxyAgent(config) {
172
+ const agent = new FluxyAgent(config);
173
+ await agent.init();
174
+ return agent;
175
+ }
@@ -0,0 +1,17 @@
1
+ export interface MintTokenInput {
2
+ baseUrl: string;
3
+ apiKey: string;
4
+ userId: string;
5
+ roles?: string[];
6
+ ttlSeconds?: number;
7
+ }
8
+ export interface MintTokenResult {
9
+ token: string;
10
+ expiresIn: number;
11
+ claims: {
12
+ sub: string;
13
+ tid: string;
14
+ roles: string[];
15
+ };
16
+ }
17
+ export declare function mintWorkerToken(input: MintTokenInput): Promise<MintTokenResult>;
@@ -0,0 +1,23 @@
1
+ export async function mintWorkerToken(input) {
2
+ const base = input.baseUrl.replace(/\/+$/, "");
3
+ const res = await fetch(`${base}/auth/token`, {
4
+ method: "POST",
5
+ headers: {
6
+ "Content-Type": "application/json",
7
+ "X-Fluxy-Api-Key": input.apiKey,
8
+ },
9
+ body: JSON.stringify({
10
+ userId: input.userId,
11
+ roles: input.roles ?? ["member"],
12
+ ttlSeconds: input.ttlSeconds ?? 3600,
13
+ }),
14
+ });
15
+ const json = (await res.json().catch(() => ({})));
16
+ if (!res.ok) {
17
+ throw new Error(json.error || `Mint token failed (${res.status})`);
18
+ }
19
+ if (!json.token) {
20
+ throw new Error("Worker did not return a token");
21
+ }
22
+ return json;
23
+ }
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@fluxy-chat/agent",
3
+ "version": "0.1.0",
4
+ "description": "Fluxychat server-side agent SDK (WebSocket bots, streaming, waitFor)",
5
+ "license": "MIT",
6
+ "author": "Fluxychat",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/AlessandroFare/fluxychat.git",
10
+ "directory": "packages/agent"
11
+ },
12
+ "homepage": "https://github.com/AlessandroFare/fluxychat/tree/main/packages/agent#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/AlessandroFare/fluxychat/issues"
15
+ },
16
+ "keywords": [
17
+ "chat",
18
+ "agent",
19
+ "bot",
20
+ "realtime",
21
+ "cloudflare",
22
+ "fluxychat"
23
+ ],
24
+ "main": "dist/index.js",
25
+ "types": "dist/index.d.ts",
26
+ "sideEffects": false,
27
+ "files": [
28
+ "dist/",
29
+ "README.md",
30
+ "LICENSE"
31
+ ],
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "engines": {
36
+ "node": "\u003e=18.0.0"
37
+ },
38
+ "scripts": {
39
+ "build": "tsc -p tsconfig.json",
40
+ "dev": "tsc -w -p tsconfig.json",
41
+ "prepublishOnly": "pnpm run build",
42
+ "test": "pnpm exec vitest run"
43
+ },
44
+ "dependencies": {
45
+ "@fluxy-chat/sdk": "workspace:*"
46
+ },
47
+ "devDependencies": {
48
+ "@types/node": "^24.3.0",
49
+ "typescript": "latest",
50
+ "vite": "^8.0.16",
51
+ "vitest": "^4.1.5"
52
+ }
53
+ }