multiclaws 0.4.41 → 0.4.43
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/README.md +2 -0
- package/dist/gateway/handlers.d.ts +4 -4
- package/dist/gateway/handlers.js +239 -239
- package/dist/index.d.ts +8 -8
- package/dist/index.js +710 -710
- package/dist/infra/frp.d.ts +55 -55
- package/dist/infra/frp.js +398 -398
- package/dist/infra/gateway-client.d.ts +27 -27
- package/dist/infra/gateway-client.js +136 -136
- package/dist/infra/json-store.d.ts +4 -4
- package/dist/infra/json-store.js +57 -57
- package/dist/infra/logger.d.ts +14 -14
- package/dist/infra/logger.js +25 -25
- package/dist/infra/rate-limiter.d.ts +19 -19
- package/dist/infra/rate-limiter.js +69 -69
- package/dist/infra/tailscale.d.ts +19 -19
- package/dist/infra/tailscale.js +120 -120
- package/dist/infra/telemetry.d.ts +3 -3
- package/dist/infra/telemetry.js +17 -17
- package/dist/infra/version.d.ts +1 -1
- package/dist/infra/version.js +19 -19
- package/dist/service/a2a-adapter.d.ts +80 -80
- package/dist/service/a2a-adapter.js +505 -505
- package/dist/service/agent-profile.d.ts +17 -17
- package/dist/service/agent-profile.js +58 -58
- package/dist/service/agent-registry.d.ts +29 -29
- package/dist/service/agent-registry.js +131 -131
- package/dist/service/multiclaws-service.d.ts +150 -150
- package/dist/service/multiclaws-service.js +1137 -1137
- package/dist/service/session-store.d.ts +46 -46
- package/dist/service/session-store.js +143 -143
- package/dist/task/tracker.d.ts +46 -46
- package/dist/task/tracker.js +191 -191
- package/dist/team/team-store.d.ts +42 -42
- package/dist/team/team-store.js +195 -195
- package/dist/types/openclaw.d.ts +109 -109
- package/dist/types/openclaw.js +2 -2
- package/package.json +1 -1
- package/skills/meeting-scheduler/SKILL.md +112 -105
package/dist/task/tracker.js
CHANGED
|
@@ -1,191 +1,191 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.TaskTracker = void 0;
|
|
7
|
-
const node_crypto_1 = require("node:crypto");
|
|
8
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
|
-
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
10
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
-
const DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
12
|
-
const MAX_TASKS = 10_000;
|
|
13
|
-
const PRUNE_INTERVAL_MS = 60 * 60 * 1000;
|
|
14
|
-
function emptyStore() {
|
|
15
|
-
return {
|
|
16
|
-
version: 1,
|
|
17
|
-
tasks: [],
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
function normalizeTask(task) {
|
|
21
|
-
if (!task ||
|
|
22
|
-
typeof task.taskId !== "string" ||
|
|
23
|
-
typeof task.fromPeerId !== "string" ||
|
|
24
|
-
typeof task.toPeerId !== "string" ||
|
|
25
|
-
typeof task.task !== "string" ||
|
|
26
|
-
typeof task.status !== "string" ||
|
|
27
|
-
typeof task.createdAtMs !== "number" ||
|
|
28
|
-
typeof task.updatedAtMs !== "number") {
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
return {
|
|
32
|
-
taskId: task.taskId,
|
|
33
|
-
fromPeerId: task.fromPeerId,
|
|
34
|
-
toPeerId: task.toPeerId,
|
|
35
|
-
task: task.task,
|
|
36
|
-
context: typeof task.context === "string" ? task.context : undefined,
|
|
37
|
-
status: task.status,
|
|
38
|
-
createdAtMs: task.createdAtMs,
|
|
39
|
-
updatedAtMs: task.updatedAtMs,
|
|
40
|
-
result: typeof task.result === "string" ? task.result : undefined,
|
|
41
|
-
error: typeof task.error === "string" ? task.error : undefined,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
function normalizeStore(raw) {
|
|
45
|
-
if (raw.version !== 1 || !Array.isArray(raw.tasks)) {
|
|
46
|
-
return emptyStore();
|
|
47
|
-
}
|
|
48
|
-
const tasks = [];
|
|
49
|
-
for (const task of raw.tasks) {
|
|
50
|
-
const normalized = normalizeTask(task);
|
|
51
|
-
if (normalized) {
|
|
52
|
-
tasks.push(normalized);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return {
|
|
56
|
-
version: 1,
|
|
57
|
-
tasks,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
class TaskTracker {
|
|
61
|
-
filePath;
|
|
62
|
-
ttlMs;
|
|
63
|
-
maxTasks;
|
|
64
|
-
store;
|
|
65
|
-
logger;
|
|
66
|
-
pruneTimer = null;
|
|
67
|
-
persistPending = false;
|
|
68
|
-
constructor(opts) {
|
|
69
|
-
this.ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;
|
|
70
|
-
this.maxTasks = opts?.maxTasks ?? MAX_TASKS;
|
|
71
|
-
this.filePath = opts?.filePath ?? ".openclaw/multiclaws/tasks.json";
|
|
72
|
-
this.logger = opts?.logger;
|
|
73
|
-
// Sync load at startup is acceptable (runs once)
|
|
74
|
-
this.store = this.loadStoreSync();
|
|
75
|
-
this.pruneTimer = setInterval(() => this.prune(), PRUNE_INTERVAL_MS);
|
|
76
|
-
if (this.pruneTimer && typeof this.pruneTimer === "object" && "unref" in this.pruneTimer) {
|
|
77
|
-
this.pruneTimer.unref();
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
create(params) {
|
|
81
|
-
this.logger?.debug?.(`[task-tracker] create(from=${params.fromPeerId}, to=${params.toPeerId})`);
|
|
82
|
-
if (this.store.tasks.length >= this.maxTasks) {
|
|
83
|
-
this.prune();
|
|
84
|
-
}
|
|
85
|
-
if (this.store.tasks.length >= this.maxTasks) {
|
|
86
|
-
this.evictOldest();
|
|
87
|
-
}
|
|
88
|
-
const now = Date.now();
|
|
89
|
-
const record = {
|
|
90
|
-
taskId: (0, node_crypto_1.randomUUID)(),
|
|
91
|
-
fromPeerId: params.fromPeerId,
|
|
92
|
-
toPeerId: params.toPeerId,
|
|
93
|
-
task: params.task,
|
|
94
|
-
context: params.context,
|
|
95
|
-
status: "queued",
|
|
96
|
-
createdAtMs: now,
|
|
97
|
-
updatedAtMs: now,
|
|
98
|
-
};
|
|
99
|
-
this.store.tasks.push(record);
|
|
100
|
-
this.schedulePersist();
|
|
101
|
-
this.logger?.debug?.(`[task-tracker] create completed, taskId=${record.taskId}`);
|
|
102
|
-
return record;
|
|
103
|
-
}
|
|
104
|
-
update(taskId, patch) {
|
|
105
|
-
const index = this.store.tasks.findIndex((entry) => entry.taskId === taskId);
|
|
106
|
-
if (index < 0) {
|
|
107
|
-
return null;
|
|
108
|
-
}
|
|
109
|
-
const next = {
|
|
110
|
-
...this.store.tasks[index],
|
|
111
|
-
...patch,
|
|
112
|
-
updatedAtMs: Date.now(),
|
|
113
|
-
};
|
|
114
|
-
this.store.tasks[index] = next;
|
|
115
|
-
this.schedulePersist();
|
|
116
|
-
return next;
|
|
117
|
-
}
|
|
118
|
-
get(taskId) {
|
|
119
|
-
return this.store.tasks.find((entry) => entry.taskId === taskId) ?? null;
|
|
120
|
-
}
|
|
121
|
-
list() {
|
|
122
|
-
return [...this.store.tasks].sort((a, b) => b.updatedAtMs - a.updatedAtMs);
|
|
123
|
-
}
|
|
124
|
-
destroy() {
|
|
125
|
-
if (this.pruneTimer) {
|
|
126
|
-
clearInterval(this.pruneTimer);
|
|
127
|
-
this.pruneTimer = null;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
/** Sync load at startup — runs once before the event loop is busy. */
|
|
131
|
-
loadStoreSync() {
|
|
132
|
-
node_fs_1.default.mkdirSync(node_path_1.default.dirname(this.filePath), { recursive: true });
|
|
133
|
-
try {
|
|
134
|
-
const raw = JSON.parse(node_fs_1.default.readFileSync(this.filePath, "utf8"));
|
|
135
|
-
return normalizeStore(raw);
|
|
136
|
-
}
|
|
137
|
-
catch {
|
|
138
|
-
const store = emptyStore();
|
|
139
|
-
node_fs_1.default.writeFileSync(this.filePath, JSON.stringify(store, null, 2), "utf8");
|
|
140
|
-
return store;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
/** Coalesce rapid writes into a single async flush. */
|
|
144
|
-
schedulePersist() {
|
|
145
|
-
if (this.persistPending)
|
|
146
|
-
return;
|
|
147
|
-
this.persistPending = true;
|
|
148
|
-
queueMicrotask(() => {
|
|
149
|
-
this.persistPending = false;
|
|
150
|
-
void this.persistAsync();
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
async persistAsync() {
|
|
154
|
-
try {
|
|
155
|
-
await promises_1.default.mkdir(node_path_1.default.dirname(this.filePath), { recursive: true });
|
|
156
|
-
const tmp = `${this.filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
157
|
-
await promises_1.default.writeFile(tmp, JSON.stringify(this.store, null, 2), "utf8");
|
|
158
|
-
await promises_1.default.rename(tmp, this.filePath);
|
|
159
|
-
}
|
|
160
|
-
catch (err) {
|
|
161
|
-
// best-effort persistence — in-memory state is authoritative
|
|
162
|
-
this.logger?.warn?.(`[task-tracker] persistAsync failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
prune() {
|
|
166
|
-
const cutoff = Date.now() - this.ttlMs;
|
|
167
|
-
const before = this.store.tasks.length;
|
|
168
|
-
this.store.tasks = this.store.tasks.filter((task) => {
|
|
169
|
-
if (task.updatedAtMs >= cutoff) {
|
|
170
|
-
return true;
|
|
171
|
-
}
|
|
172
|
-
return task.status !== "completed" && task.status !== "failed";
|
|
173
|
-
});
|
|
174
|
-
if (this.store.tasks.length !== before) {
|
|
175
|
-
this.schedulePersist();
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
evictOldest() {
|
|
179
|
-
const removable = [...this.store.tasks]
|
|
180
|
-
.filter((task) => task.status === "completed" || task.status === "failed")
|
|
181
|
-
.sort((a, b) => a.updatedAtMs - b.updatedAtMs)
|
|
182
|
-
.slice(0, Math.max(1, Math.floor(this.maxTasks / 4)));
|
|
183
|
-
if (removable.length === 0) {
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
const removeIds = new Set(removable.map((entry) => entry.taskId));
|
|
187
|
-
this.store.tasks = this.store.tasks.filter((entry) => !removeIds.has(entry.taskId));
|
|
188
|
-
this.schedulePersist();
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
exports.TaskTracker = TaskTracker;
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.TaskTracker = void 0;
|
|
7
|
+
const node_crypto_1 = require("node:crypto");
|
|
8
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
|
+
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
12
|
+
const MAX_TASKS = 10_000;
|
|
13
|
+
const PRUNE_INTERVAL_MS = 60 * 60 * 1000;
|
|
14
|
+
function emptyStore() {
|
|
15
|
+
return {
|
|
16
|
+
version: 1,
|
|
17
|
+
tasks: [],
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function normalizeTask(task) {
|
|
21
|
+
if (!task ||
|
|
22
|
+
typeof task.taskId !== "string" ||
|
|
23
|
+
typeof task.fromPeerId !== "string" ||
|
|
24
|
+
typeof task.toPeerId !== "string" ||
|
|
25
|
+
typeof task.task !== "string" ||
|
|
26
|
+
typeof task.status !== "string" ||
|
|
27
|
+
typeof task.createdAtMs !== "number" ||
|
|
28
|
+
typeof task.updatedAtMs !== "number") {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
taskId: task.taskId,
|
|
33
|
+
fromPeerId: task.fromPeerId,
|
|
34
|
+
toPeerId: task.toPeerId,
|
|
35
|
+
task: task.task,
|
|
36
|
+
context: typeof task.context === "string" ? task.context : undefined,
|
|
37
|
+
status: task.status,
|
|
38
|
+
createdAtMs: task.createdAtMs,
|
|
39
|
+
updatedAtMs: task.updatedAtMs,
|
|
40
|
+
result: typeof task.result === "string" ? task.result : undefined,
|
|
41
|
+
error: typeof task.error === "string" ? task.error : undefined,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function normalizeStore(raw) {
|
|
45
|
+
if (raw.version !== 1 || !Array.isArray(raw.tasks)) {
|
|
46
|
+
return emptyStore();
|
|
47
|
+
}
|
|
48
|
+
const tasks = [];
|
|
49
|
+
for (const task of raw.tasks) {
|
|
50
|
+
const normalized = normalizeTask(task);
|
|
51
|
+
if (normalized) {
|
|
52
|
+
tasks.push(normalized);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
version: 1,
|
|
57
|
+
tasks,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
class TaskTracker {
|
|
61
|
+
filePath;
|
|
62
|
+
ttlMs;
|
|
63
|
+
maxTasks;
|
|
64
|
+
store;
|
|
65
|
+
logger;
|
|
66
|
+
pruneTimer = null;
|
|
67
|
+
persistPending = false;
|
|
68
|
+
constructor(opts) {
|
|
69
|
+
this.ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;
|
|
70
|
+
this.maxTasks = opts?.maxTasks ?? MAX_TASKS;
|
|
71
|
+
this.filePath = opts?.filePath ?? ".openclaw/multiclaws/tasks.json";
|
|
72
|
+
this.logger = opts?.logger;
|
|
73
|
+
// Sync load at startup is acceptable (runs once)
|
|
74
|
+
this.store = this.loadStoreSync();
|
|
75
|
+
this.pruneTimer = setInterval(() => this.prune(), PRUNE_INTERVAL_MS);
|
|
76
|
+
if (this.pruneTimer && typeof this.pruneTimer === "object" && "unref" in this.pruneTimer) {
|
|
77
|
+
this.pruneTimer.unref();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
create(params) {
|
|
81
|
+
this.logger?.debug?.(`[task-tracker] create(from=${params.fromPeerId}, to=${params.toPeerId})`);
|
|
82
|
+
if (this.store.tasks.length >= this.maxTasks) {
|
|
83
|
+
this.prune();
|
|
84
|
+
}
|
|
85
|
+
if (this.store.tasks.length >= this.maxTasks) {
|
|
86
|
+
this.evictOldest();
|
|
87
|
+
}
|
|
88
|
+
const now = Date.now();
|
|
89
|
+
const record = {
|
|
90
|
+
taskId: (0, node_crypto_1.randomUUID)(),
|
|
91
|
+
fromPeerId: params.fromPeerId,
|
|
92
|
+
toPeerId: params.toPeerId,
|
|
93
|
+
task: params.task,
|
|
94
|
+
context: params.context,
|
|
95
|
+
status: "queued",
|
|
96
|
+
createdAtMs: now,
|
|
97
|
+
updatedAtMs: now,
|
|
98
|
+
};
|
|
99
|
+
this.store.tasks.push(record);
|
|
100
|
+
this.schedulePersist();
|
|
101
|
+
this.logger?.debug?.(`[task-tracker] create completed, taskId=${record.taskId}`);
|
|
102
|
+
return record;
|
|
103
|
+
}
|
|
104
|
+
update(taskId, patch) {
|
|
105
|
+
const index = this.store.tasks.findIndex((entry) => entry.taskId === taskId);
|
|
106
|
+
if (index < 0) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
const next = {
|
|
110
|
+
...this.store.tasks[index],
|
|
111
|
+
...patch,
|
|
112
|
+
updatedAtMs: Date.now(),
|
|
113
|
+
};
|
|
114
|
+
this.store.tasks[index] = next;
|
|
115
|
+
this.schedulePersist();
|
|
116
|
+
return next;
|
|
117
|
+
}
|
|
118
|
+
get(taskId) {
|
|
119
|
+
return this.store.tasks.find((entry) => entry.taskId === taskId) ?? null;
|
|
120
|
+
}
|
|
121
|
+
list() {
|
|
122
|
+
return [...this.store.tasks].sort((a, b) => b.updatedAtMs - a.updatedAtMs);
|
|
123
|
+
}
|
|
124
|
+
destroy() {
|
|
125
|
+
if (this.pruneTimer) {
|
|
126
|
+
clearInterval(this.pruneTimer);
|
|
127
|
+
this.pruneTimer = null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/** Sync load at startup — runs once before the event loop is busy. */
|
|
131
|
+
loadStoreSync() {
|
|
132
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(this.filePath), { recursive: true });
|
|
133
|
+
try {
|
|
134
|
+
const raw = JSON.parse(node_fs_1.default.readFileSync(this.filePath, "utf8"));
|
|
135
|
+
return normalizeStore(raw);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
const store = emptyStore();
|
|
139
|
+
node_fs_1.default.writeFileSync(this.filePath, JSON.stringify(store, null, 2), "utf8");
|
|
140
|
+
return store;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/** Coalesce rapid writes into a single async flush. */
|
|
144
|
+
schedulePersist() {
|
|
145
|
+
if (this.persistPending)
|
|
146
|
+
return;
|
|
147
|
+
this.persistPending = true;
|
|
148
|
+
queueMicrotask(() => {
|
|
149
|
+
this.persistPending = false;
|
|
150
|
+
void this.persistAsync();
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
async persistAsync() {
|
|
154
|
+
try {
|
|
155
|
+
await promises_1.default.mkdir(node_path_1.default.dirname(this.filePath), { recursive: true });
|
|
156
|
+
const tmp = `${this.filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
157
|
+
await promises_1.default.writeFile(tmp, JSON.stringify(this.store, null, 2), "utf8");
|
|
158
|
+
await promises_1.default.rename(tmp, this.filePath);
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
// best-effort persistence — in-memory state is authoritative
|
|
162
|
+
this.logger?.warn?.(`[task-tracker] persistAsync failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
prune() {
|
|
166
|
+
const cutoff = Date.now() - this.ttlMs;
|
|
167
|
+
const before = this.store.tasks.length;
|
|
168
|
+
this.store.tasks = this.store.tasks.filter((task) => {
|
|
169
|
+
if (task.updatedAtMs >= cutoff) {
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
return task.status !== "completed" && task.status !== "failed";
|
|
173
|
+
});
|
|
174
|
+
if (this.store.tasks.length !== before) {
|
|
175
|
+
this.schedulePersist();
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
evictOldest() {
|
|
179
|
+
const removable = [...this.store.tasks]
|
|
180
|
+
.filter((task) => task.status === "completed" || task.status === "failed")
|
|
181
|
+
.sort((a, b) => a.updatedAtMs - b.updatedAtMs)
|
|
182
|
+
.slice(0, Math.max(1, Math.floor(this.maxTasks / 4)));
|
|
183
|
+
if (removable.length === 0) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const removeIds = new Set(removable.map((entry) => entry.taskId));
|
|
187
|
+
this.store.tasks = this.store.tasks.filter((entry) => !removeIds.has(entry.taskId));
|
|
188
|
+
this.schedulePersist();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
exports.TaskTracker = TaskTracker;
|
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
import type { BasicLogger } from "../infra/logger";
|
|
2
|
-
export type TeamMember = {
|
|
3
|
-
url: string;
|
|
4
|
-
name: string;
|
|
5
|
-
description?: string;
|
|
6
|
-
joinedAtMs: number;
|
|
7
|
-
};
|
|
8
|
-
export type TeamRecord = {
|
|
9
|
-
teamId: string;
|
|
10
|
-
teamName: string;
|
|
11
|
-
selfUrl: string;
|
|
12
|
-
members: TeamMember[];
|
|
13
|
-
createdAtMs: number;
|
|
14
|
-
};
|
|
15
|
-
export type InvitePayload = {
|
|
16
|
-
/** teamId */
|
|
17
|
-
t: string;
|
|
18
|
-
/** seed URL */
|
|
19
|
-
u: string;
|
|
20
|
-
};
|
|
21
|
-
export declare function encodeInvite(teamId: string, seedUrl: string): string;
|
|
22
|
-
export declare function decodeInvite(code: string): InvitePayload;
|
|
23
|
-
export declare class TeamStore {
|
|
24
|
-
private readonly filePath;
|
|
25
|
-
private readonly logger?;
|
|
26
|
-
constructor(filePath: string, logger?: BasicLogger | undefined);
|
|
27
|
-
private log;
|
|
28
|
-
private readStore;
|
|
29
|
-
createTeam(params: {
|
|
30
|
-
teamName: string;
|
|
31
|
-
selfUrl: string;
|
|
32
|
-
selfName: string;
|
|
33
|
-
selfDescription?: string;
|
|
34
|
-
}): Promise<TeamRecord>;
|
|
35
|
-
getTeam(teamId: string): Promise<TeamRecord | null>;
|
|
36
|
-
listTeams(): Promise<TeamRecord[]>;
|
|
37
|
-
getFirstTeam(): Promise<TeamRecord | null>;
|
|
38
|
-
addMember(teamId: string, member: TeamMember): Promise<boolean>;
|
|
39
|
-
removeMember(teamId: string, memberUrl: string): Promise<boolean>;
|
|
40
|
-
deleteTeam(teamId: string): Promise<boolean>;
|
|
41
|
-
saveTeam(team: TeamRecord): Promise<void>;
|
|
42
|
-
}
|
|
1
|
+
import type { BasicLogger } from "../infra/logger";
|
|
2
|
+
export type TeamMember = {
|
|
3
|
+
url: string;
|
|
4
|
+
name: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
joinedAtMs: number;
|
|
7
|
+
};
|
|
8
|
+
export type TeamRecord = {
|
|
9
|
+
teamId: string;
|
|
10
|
+
teamName: string;
|
|
11
|
+
selfUrl: string;
|
|
12
|
+
members: TeamMember[];
|
|
13
|
+
createdAtMs: number;
|
|
14
|
+
};
|
|
15
|
+
export type InvitePayload = {
|
|
16
|
+
/** teamId */
|
|
17
|
+
t: string;
|
|
18
|
+
/** seed URL */
|
|
19
|
+
u: string;
|
|
20
|
+
};
|
|
21
|
+
export declare function encodeInvite(teamId: string, seedUrl: string): string;
|
|
22
|
+
export declare function decodeInvite(code: string): InvitePayload;
|
|
23
|
+
export declare class TeamStore {
|
|
24
|
+
private readonly filePath;
|
|
25
|
+
private readonly logger?;
|
|
26
|
+
constructor(filePath: string, logger?: BasicLogger | undefined);
|
|
27
|
+
private log;
|
|
28
|
+
private readStore;
|
|
29
|
+
createTeam(params: {
|
|
30
|
+
teamName: string;
|
|
31
|
+
selfUrl: string;
|
|
32
|
+
selfName: string;
|
|
33
|
+
selfDescription?: string;
|
|
34
|
+
}): Promise<TeamRecord>;
|
|
35
|
+
getTeam(teamId: string): Promise<TeamRecord | null>;
|
|
36
|
+
listTeams(): Promise<TeamRecord[]>;
|
|
37
|
+
getFirstTeam(): Promise<TeamRecord | null>;
|
|
38
|
+
addMember(teamId: string, member: TeamMember): Promise<boolean>;
|
|
39
|
+
removeMember(teamId: string, memberUrl: string): Promise<boolean>;
|
|
40
|
+
deleteTeam(teamId: string): Promise<boolean>;
|
|
41
|
+
saveTeam(team: TeamRecord): Promise<void>;
|
|
42
|
+
}
|