@axiom-lattice/client-sdk 4.2.1 → 4.3.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.
- package/dist/__tests__/project-rooms.test.d.ts +2 -0
- package/dist/__tests__/project-rooms.test.d.ts.map +1 -0
- package/dist/__tests__/project-rooms.test.js +144 -0
- package/dist/__tests__/project-rooms.test.js.map +1 -0
- package/dist/__tests__/sse-parser.test.d.ts +2 -0
- package/dist/__tests__/sse-parser.test.d.ts.map +1 -0
- package/dist/__tests__/sse-parser.test.js +16 -0
- package/dist/__tests__/sse-parser.test.js.map +1 -0
- package/dist/client.d.ts +2 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +17 -134
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +153 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +422 -135
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +420 -135
- package/dist/index.mjs.map +1 -1
- package/dist/project-rooms.d.ts +152 -0
- package/dist/project-rooms.d.ts.map +1 -0
- package/dist/project-rooms.js +240 -0
- package/dist/project-rooms.js.map +1 -0
- package/dist/sse-parser.d.ts +18 -0
- package/dist/sse-parser.d.ts.map +1 -0
- package/dist/sse-parser.js +119 -0
- package/dist/sse-parser.js.map +1 -0
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -913,8 +913,8 @@ var require_encoding = __commonJS({
|
|
|
913
913
|
}
|
|
914
914
|
return serializeStream.call(this, output);
|
|
915
915
|
};
|
|
916
|
-
function
|
|
917
|
-
if (!(this instanceof
|
|
916
|
+
function TextEncoder2(label, options) {
|
|
917
|
+
if (!(this instanceof TextEncoder2))
|
|
918
918
|
throw TypeError("Called as a function. Did you forget 'new'?");
|
|
919
919
|
options = ToDictionary(options);
|
|
920
920
|
this._encoding = null;
|
|
@@ -942,14 +942,14 @@ var require_encoding = __commonJS({
|
|
|
942
942
|
return enc;
|
|
943
943
|
}
|
|
944
944
|
if (Object.defineProperty) {
|
|
945
|
-
Object.defineProperty(
|
|
945
|
+
Object.defineProperty(TextEncoder2.prototype, "encoding", {
|
|
946
946
|
/** @this {TextEncoder} */
|
|
947
947
|
get: function() {
|
|
948
948
|
return this._encoding.name.toLowerCase();
|
|
949
949
|
}
|
|
950
950
|
});
|
|
951
951
|
}
|
|
952
|
-
|
|
952
|
+
TextEncoder2.prototype.encode = function encode2(opt_string, options) {
|
|
953
953
|
opt_string = opt_string === void 0 ? "" : String(opt_string);
|
|
954
954
|
options = ToDictionary(options);
|
|
955
955
|
if (!this._do_not_flush)
|
|
@@ -1805,7 +1805,7 @@ var require_encoding = __commonJS({
|
|
|
1805
1805
|
return new XUserDefinedDecoder(options);
|
|
1806
1806
|
};
|
|
1807
1807
|
if (!global["TextEncoder"])
|
|
1808
|
-
global["TextEncoder"] =
|
|
1808
|
+
global["TextEncoder"] = TextEncoder2;
|
|
1809
1809
|
if (!global["TextDecoder"])
|
|
1810
1810
|
global["TextDecoder"] = TextDecoder2;
|
|
1811
1811
|
if (typeof module !== "undefined" && module.exports) {
|
|
@@ -2336,7 +2336,7 @@ var AbstractClient = class {
|
|
|
2336
2336
|
const query = searchParams.toString();
|
|
2337
2337
|
const response = await this.makeRequest(`/api/web-apps${query ? `?${query}` : ""}`);
|
|
2338
2338
|
return {
|
|
2339
|
-
records: response.data.records.map((
|
|
2339
|
+
records: response.data.records.map((record2) => this.hydrateAgentWebApp(record2)),
|
|
2340
2340
|
total: response.data.total
|
|
2341
2341
|
};
|
|
2342
2342
|
},
|
|
@@ -2977,19 +2977,19 @@ var AbstractClient = class {
|
|
|
2977
2977
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
2978
2978
|
throw new ApiError("Invalid Agent Web App response", 500, value);
|
|
2979
2979
|
}
|
|
2980
|
-
const
|
|
2980
|
+
const record2 = value;
|
|
2981
2981
|
const hydrateDate = (field) => {
|
|
2982
|
-
const raw =
|
|
2983
|
-
const
|
|
2982
|
+
const raw = record2[field];
|
|
2983
|
+
const date2 = raw instanceof Date ? new Date(raw.getTime()) : new Date(
|
|
2984
2984
|
typeof raw === "string" || typeof raw === "number" ? raw : Number.NaN
|
|
2985
2985
|
);
|
|
2986
|
-
if (Number.isNaN(
|
|
2986
|
+
if (Number.isNaN(date2.getTime())) {
|
|
2987
2987
|
throw new ApiError(`Invalid Agent Web App ${field}`, 500, value);
|
|
2988
2988
|
}
|
|
2989
|
-
return
|
|
2989
|
+
return date2;
|
|
2990
2990
|
};
|
|
2991
2991
|
return {
|
|
2992
|
-
...
|
|
2992
|
+
...record2,
|
|
2993
2993
|
createdAt: hydrateDate("createdAt"),
|
|
2994
2994
|
updatedAt: hydrateDate("updatedAt")
|
|
2995
2995
|
};
|
|
@@ -3429,6 +3429,398 @@ var ExportImportClient = class {
|
|
|
3429
3429
|
}
|
|
3430
3430
|
};
|
|
3431
3431
|
|
|
3432
|
+
// src/sse-parser.ts
|
|
3433
|
+
var SseParseError = class extends Error {
|
|
3434
|
+
constructor(message) {
|
|
3435
|
+
super(message);
|
|
3436
|
+
this.code = "INVALID_EVENT";
|
|
3437
|
+
this.name = "SseParseError";
|
|
3438
|
+
}
|
|
3439
|
+
};
|
|
3440
|
+
async function* parseSseBody(body, options = {}) {
|
|
3441
|
+
const maxLine = options.maxLineBytes ?? 64 * 1024;
|
|
3442
|
+
const maxEvent = options.maxEventBytes ?? 1024 * 1024;
|
|
3443
|
+
const maxDataLines = options.maxDataLines ?? 1024;
|
|
3444
|
+
const reader = body.getReader();
|
|
3445
|
+
const decoder = new TextDecoder();
|
|
3446
|
+
let buffer = "";
|
|
3447
|
+
let event = "";
|
|
3448
|
+
let id;
|
|
3449
|
+
let retry;
|
|
3450
|
+
let data = [];
|
|
3451
|
+
let bytes = 0;
|
|
3452
|
+
const dispatch = () => {
|
|
3453
|
+
if (data.length === 0) {
|
|
3454
|
+
event = "";
|
|
3455
|
+
id = void 0;
|
|
3456
|
+
retry = void 0;
|
|
3457
|
+
bytes = 0;
|
|
3458
|
+
return void 0;
|
|
3459
|
+
}
|
|
3460
|
+
let parsed;
|
|
3461
|
+
try {
|
|
3462
|
+
parsed = JSON.parse(data.join("\n"));
|
|
3463
|
+
} catch {
|
|
3464
|
+
throw new SseParseError("Invalid SSE JSON");
|
|
3465
|
+
}
|
|
3466
|
+
if (options.strictJsonObject && (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)))
|
|
3467
|
+
throw new SseParseError("SSE data must be an object");
|
|
3468
|
+
const result = { event, data: parsed, ...id === void 0 ? {} : { id }, ...retry === void 0 ? {} : { retry } };
|
|
3469
|
+
event = "";
|
|
3470
|
+
id = void 0;
|
|
3471
|
+
retry = void 0;
|
|
3472
|
+
data = [];
|
|
3473
|
+
bytes = 0;
|
|
3474
|
+
return result;
|
|
3475
|
+
};
|
|
3476
|
+
const processLine = (raw) => {
|
|
3477
|
+
const line = raw.endsWith("\r") ? raw.slice(0, -1) : raw;
|
|
3478
|
+
if (new TextEncoder().encode(line).byteLength > maxLine)
|
|
3479
|
+
throw new SseParseError("SSE line is too large");
|
|
3480
|
+
if (line === "")
|
|
3481
|
+
return dispatch();
|
|
3482
|
+
if (line.startsWith(":"))
|
|
3483
|
+
return void 0;
|
|
3484
|
+
const separator = line.indexOf(":");
|
|
3485
|
+
const field = separator < 0 ? line : line.slice(0, separator);
|
|
3486
|
+
let value = separator < 0 ? "" : line.slice(separator + 1);
|
|
3487
|
+
if (value.startsWith(" "))
|
|
3488
|
+
value = value.slice(1);
|
|
3489
|
+
if (field === "event")
|
|
3490
|
+
event = value;
|
|
3491
|
+
else if (field === "data") {
|
|
3492
|
+
if (data.length >= maxDataLines)
|
|
3493
|
+
throw new SseParseError("Too many SSE data lines");
|
|
3494
|
+
data.push(value);
|
|
3495
|
+
bytes += new TextEncoder().encode(value).byteLength + (data.length === 1 ? 0 : 1);
|
|
3496
|
+
if (bytes > maxEvent)
|
|
3497
|
+
throw new SseParseError("SSE event is too large");
|
|
3498
|
+
} else if (field === "id")
|
|
3499
|
+
id = value;
|
|
3500
|
+
else if (field === "retry") {
|
|
3501
|
+
const parsed = Number(value);
|
|
3502
|
+
if (!Number.isInteger(parsed) || parsed < 0 || !Number.isFinite(parsed))
|
|
3503
|
+
throw new SseParseError("Invalid SSE retry");
|
|
3504
|
+
retry = parsed;
|
|
3505
|
+
}
|
|
3506
|
+
return void 0;
|
|
3507
|
+
};
|
|
3508
|
+
try {
|
|
3509
|
+
while (true) {
|
|
3510
|
+
const chunk = await reader.read();
|
|
3511
|
+
if (chunk.done) {
|
|
3512
|
+
buffer += decoder.decode();
|
|
3513
|
+
if (new TextEncoder().encode(buffer).byteLength > maxLine)
|
|
3514
|
+
throw new SseParseError("SSE line is too large");
|
|
3515
|
+
break;
|
|
3516
|
+
}
|
|
3517
|
+
buffer += decoder.decode(chunk.value, { stream: true });
|
|
3518
|
+
if (new TextEncoder().encode(buffer.slice(0, Math.max(0, findLineBreak(buffer) < 0 ? buffer.length : findLineBreak(buffer)))).byteLength > maxLine)
|
|
3519
|
+
throw new SseParseError("SSE line is too large");
|
|
3520
|
+
let index = findLineBreak(buffer);
|
|
3521
|
+
while (index >= 0) {
|
|
3522
|
+
if (buffer[index] === "\r" && index === buffer.length - 1)
|
|
3523
|
+
break;
|
|
3524
|
+
const frame2 = processLine(buffer.slice(0, index));
|
|
3525
|
+
buffer = buffer.slice(index + lineBreakLength(buffer, index));
|
|
3526
|
+
if (frame2)
|
|
3527
|
+
yield frame2;
|
|
3528
|
+
index = findLineBreak(buffer);
|
|
3529
|
+
}
|
|
3530
|
+
}
|
|
3531
|
+
if (buffer) {
|
|
3532
|
+
const frame2 = processLine(buffer);
|
|
3533
|
+
if (frame2)
|
|
3534
|
+
yield frame2;
|
|
3535
|
+
}
|
|
3536
|
+
const frame = processLine("");
|
|
3537
|
+
if (frame)
|
|
3538
|
+
yield frame;
|
|
3539
|
+
} finally {
|
|
3540
|
+
await reader.cancel().catch(() => void 0);
|
|
3541
|
+
reader.releaseLock();
|
|
3542
|
+
}
|
|
3543
|
+
}
|
|
3544
|
+
function findLineBreak(value) {
|
|
3545
|
+
const lf = value.indexOf("\n");
|
|
3546
|
+
const cr = value.indexOf("\r");
|
|
3547
|
+
if (lf < 0)
|
|
3548
|
+
return cr;
|
|
3549
|
+
if (cr < 0)
|
|
3550
|
+
return lf;
|
|
3551
|
+
return Math.min(lf, cr);
|
|
3552
|
+
}
|
|
3553
|
+
function lineBreakLength(value, index) {
|
|
3554
|
+
return value[index] === "\r" && value[index + 1] === "\n" ? 2 : 1;
|
|
3555
|
+
}
|
|
3556
|
+
|
|
3557
|
+
// src/project-rooms.ts
|
|
3558
|
+
var ProjectRoomClientError = class extends Error {
|
|
3559
|
+
constructor(message, status, code, retryable, details) {
|
|
3560
|
+
super(message);
|
|
3561
|
+
this.status = status;
|
|
3562
|
+
this.code = code;
|
|
3563
|
+
this.retryable = retryable;
|
|
3564
|
+
this.details = details;
|
|
3565
|
+
this.name = "ProjectRoomClientError";
|
|
3566
|
+
}
|
|
3567
|
+
};
|
|
3568
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3569
|
+
var date = (value, field) => {
|
|
3570
|
+
const result = value instanceof Date ? new Date(value.getTime()) : new Date(typeof value === "string" || typeof value === "number" ? value : Number.NaN);
|
|
3571
|
+
if (!Number.isFinite(result.getTime()))
|
|
3572
|
+
throw new ProjectRoomClientError(`Invalid ${field}`, 500, "INVALID_RESPONSE", false);
|
|
3573
|
+
return result;
|
|
3574
|
+
};
|
|
3575
|
+
var requiredString = (record2, field) => {
|
|
3576
|
+
if (typeof record2[field] !== "string")
|
|
3577
|
+
throw new ProjectRoomClientError(`Invalid ${field}`, 500, "INVALID_RESPONSE", false);
|
|
3578
|
+
return record2[field];
|
|
3579
|
+
};
|
|
3580
|
+
var oneOf = (value, values, field) => {
|
|
3581
|
+
if (typeof value !== "string" || !values.includes(value))
|
|
3582
|
+
throw new ProjectRoomClientError(`Invalid ${field}`, 500, "INVALID_RESPONSE", false);
|
|
3583
|
+
return value;
|
|
3584
|
+
};
|
|
3585
|
+
var messageSources = ["user", "agent", "task", "routine", "system"];
|
|
3586
|
+
var humanRoles = ["owner", "admin", "member", "viewer"];
|
|
3587
|
+
var memberStatuses = ["active", "removed"];
|
|
3588
|
+
var botRoles = ["coordinator", "specialist"];
|
|
3589
|
+
var botStatuses = ["active", "paused", "removed"];
|
|
3590
|
+
var exactKeys = (row, required, optional = []) => {
|
|
3591
|
+
if (required.some((key) => !Object.prototype.hasOwnProperty.call(row, key)) || Object.keys(row).some((key) => !required.includes(key) && !optional.includes(key)))
|
|
3592
|
+
throw new ProjectRoomClientError("Invalid Project Room response", 500, "INVALID_RESPONSE", false);
|
|
3593
|
+
};
|
|
3594
|
+
var hydrateAuthor = (value) => {
|
|
3595
|
+
const row = record(value);
|
|
3596
|
+
const type = oneOf(row.type, ["human", "bot", "system"], "author.type");
|
|
3597
|
+
if (type === "human") {
|
|
3598
|
+
exactKeys(row, ["type", "userId"]);
|
|
3599
|
+
return { type, userId: requiredString(row, "userId") };
|
|
3600
|
+
}
|
|
3601
|
+
if (type === "bot")
|
|
3602
|
+
return { type, membershipId: requiredString(row, "membershipId") };
|
|
3603
|
+
if (Object.keys(row).some((key) => key !== "type"))
|
|
3604
|
+
throw new ProjectRoomClientError("Invalid author", 500, "INVALID_RESPONSE", false);
|
|
3605
|
+
return { type };
|
|
3606
|
+
};
|
|
3607
|
+
var hydrateMentions = (value) => {
|
|
3608
|
+
if (!Array.isArray(value))
|
|
3609
|
+
throw new ProjectRoomClientError("Invalid mentions", 500, "INVALID_RESPONSE", false);
|
|
3610
|
+
return value.map((entry) => {
|
|
3611
|
+
const row = record(entry);
|
|
3612
|
+
const type = oneOf(row.type, ["bot", "team"], "mention.type");
|
|
3613
|
+
if (type === "team") {
|
|
3614
|
+
if (Object.keys(row).length !== 1)
|
|
3615
|
+
throw new ProjectRoomClientError("Invalid mention", 500, "INVALID_RESPONSE", false);
|
|
3616
|
+
return { type };
|
|
3617
|
+
}
|
|
3618
|
+
return { type, membershipId: requiredString(row, "membershipId") };
|
|
3619
|
+
});
|
|
3620
|
+
};
|
|
3621
|
+
var record = (value) => {
|
|
3622
|
+
if (!isRecord(value))
|
|
3623
|
+
throw new ProjectRoomClientError("Invalid Project Room response", 500, "INVALID_RESPONSE", false);
|
|
3624
|
+
return value;
|
|
3625
|
+
};
|
|
3626
|
+
var hydrateRoom = (value) => {
|
|
3627
|
+
const row = record(value);
|
|
3628
|
+
exactKeys(row, ["id", "tenantId", "workspaceId", "projectId", "type", "name", "createdAt", "updatedAt"]);
|
|
3629
|
+
return { id: requiredString(row, "id"), tenantId: requiredString(row, "tenantId"), workspaceId: requiredString(row, "workspaceId"), projectId: requiredString(row, "projectId"), type: oneOf(row.type, ["main"], "type"), name: requiredString(row, "name"), createdAt: date(row.createdAt, "createdAt"), updatedAt: date(row.updatedAt, "updatedAt") };
|
|
3630
|
+
};
|
|
3631
|
+
var hydrateMessage = (value) => {
|
|
3632
|
+
const row = record(value);
|
|
3633
|
+
exactKeys(row, ["id", "roomId", "author", "content", "mentions", "source", "createdAt"], ["replyToMessageId"]);
|
|
3634
|
+
const content = record(row.content);
|
|
3635
|
+
if (oneOf(content.type, ["text"], "content.type") !== "text")
|
|
3636
|
+
throw new ProjectRoomClientError("Invalid content", 500, "INVALID_RESPONSE", false);
|
|
3637
|
+
return { id: requiredString(row, "id"), roomId: requiredString(row, "roomId"), author: hydrateAuthor(row.author), content: { type: "text", text: requiredString(content, "text") }, mentions: hydrateMentions(row.mentions), ...row.replyToMessageId === void 0 ? {} : { replyToMessageId: requiredString(row, "replyToMessageId") }, source: oneOf(row.source, messageSources, "source"), createdAt: date(row.createdAt, "createdAt") };
|
|
3638
|
+
};
|
|
3639
|
+
var hydrateMember = (value) => {
|
|
3640
|
+
const row = record(value);
|
|
3641
|
+
exactKeys(row, ["id", "tenantId", "projectId", "userId", "role", "status", "joinedAt", "updatedAt"]);
|
|
3642
|
+
return { id: requiredString(row, "id"), tenantId: requiredString(row, "tenantId"), projectId: requiredString(row, "projectId"), userId: requiredString(row, "userId"), role: oneOf(row.role, humanRoles, "role"), status: oneOf(row.status, memberStatuses, "status"), joinedAt: date(row.joinedAt, "joinedAt"), updatedAt: date(row.updatedAt, "updatedAt") };
|
|
3643
|
+
};
|
|
3644
|
+
var hydrateBot = (value) => {
|
|
3645
|
+
const row = record(value);
|
|
3646
|
+
exactKeys(row, ["id", "tenantId", "workspaceId", "projectId", "roomId", "assistantId", "role", "title", "mentionName", "status", "roomThreadId", "joinedAt", "updatedAt"], ["responsibility"]);
|
|
3647
|
+
return { id: requiredString(row, "id"), tenantId: requiredString(row, "tenantId"), workspaceId: requiredString(row, "workspaceId"), projectId: requiredString(row, "projectId"), roomId: requiredString(row, "roomId"), assistantId: requiredString(row, "assistantId"), role: oneOf(row.role, botRoles, "role"), title: requiredString(row, "title"), ...row.responsibility === void 0 ? {} : { responsibility: requiredString(row, "responsibility") }, mentionName: requiredString(row, "mentionName"), status: oneOf(row.status, botStatuses, "status"), roomThreadId: requiredString(row, "roomThreadId"), joinedAt: date(row.joinedAt, "joinedAt"), updatedAt: date(row.updatedAt, "updatedAt") };
|
|
3648
|
+
};
|
|
3649
|
+
var iso = (value) => date(value, "date").toISOString();
|
|
3650
|
+
var hydrateDispatch = (value) => {
|
|
3651
|
+
const row = record(value);
|
|
3652
|
+
if (typeof row.success !== "boolean" || row.membershipId !== void 0 && typeof row.membershipId !== "string" || row.errorCode !== void 0 && typeof row.errorCode !== "string")
|
|
3653
|
+
throw new ProjectRoomClientError("Invalid dispatch response", 500, "INVALID_RESPONSE", false);
|
|
3654
|
+
return { success: row.success, ...row.membershipId === void 0 ? {} : { membershipId: row.membershipId }, ...row.errorCode === void 0 ? {} : { errorCode: row.errorCode } };
|
|
3655
|
+
};
|
|
3656
|
+
var encode = encodeURIComponent;
|
|
3657
|
+
var ProjectRoomsClient = class {
|
|
3658
|
+
constructor(baseURL, getHeaders) {
|
|
3659
|
+
this.baseURL = baseURL;
|
|
3660
|
+
this.getHeaders = getHeaders;
|
|
3661
|
+
this.messages = {
|
|
3662
|
+
list: async (projectId, options = {}) => {
|
|
3663
|
+
const query = new URLSearchParams();
|
|
3664
|
+
if (options.cursor) {
|
|
3665
|
+
query.set("beforeCreatedAt", iso(options.cursor.createdAt));
|
|
3666
|
+
query.set("beforeId", options.cursor.id);
|
|
3667
|
+
}
|
|
3668
|
+
if (options.limit !== void 0)
|
|
3669
|
+
query.set("limit", String(options.limit));
|
|
3670
|
+
const result = await this.request(`/api/projects/${encode(projectId)}/room/messages${query.toString() ? `?${query}` : ""}`);
|
|
3671
|
+
if (!Array.isArray(result))
|
|
3672
|
+
throw new ProjectRoomClientError("Invalid messages response", 500, "INVALID_RESPONSE", false);
|
|
3673
|
+
return result.map(hydrateMessage);
|
|
3674
|
+
},
|
|
3675
|
+
send: async (projectId, input) => {
|
|
3676
|
+
const result = await this.request(`/api/projects/${encode(projectId)}/room/messages`, { method: "POST", body: { text: input.text, mentions: input.mentions, ...input.replyToMessageId === void 0 ? {} : { replyToMessageId: input.replyToMessageId } }, headers: { "Idempotency-Key": input.idempotencyKey.trim() } });
|
|
3677
|
+
if (!Array.isArray(result.dispatch) || typeof result.replayed !== "boolean")
|
|
3678
|
+
throw new ProjectRoomClientError("Invalid send response", 500, "INVALID_RESPONSE", false);
|
|
3679
|
+
return { message: hydrateMessage(result.message), dispatch: result.dispatch.map(hydrateDispatch), replayed: result.replayed };
|
|
3680
|
+
},
|
|
3681
|
+
retry: async (projectId, messageId) => {
|
|
3682
|
+
const result = await this.request(`/api/projects/${encode(projectId)}/room/messages/${encode(messageId)}/retry`, { method: "POST", body: {} });
|
|
3683
|
+
if (!Array.isArray(result))
|
|
3684
|
+
throw new ProjectRoomClientError("Invalid retry response", 500, "INVALID_RESPONSE", false);
|
|
3685
|
+
return result.map(hydrateDispatch);
|
|
3686
|
+
}
|
|
3687
|
+
};
|
|
3688
|
+
this.members = {
|
|
3689
|
+
list: async (projectId) => this.records(`/api/projects/${encode(projectId)}/members`, hydrateMember),
|
|
3690
|
+
add: async (projectId, input) => hydrateMember(await this.request(`/api/projects/${encode(projectId)}/members`, { method: "POST", body: input })),
|
|
3691
|
+
update: async (projectId, membershipId, input) => hydrateMember(await this.request(`/api/projects/${encode(projectId)}/members/${encode(membershipId)}`, { method: "PATCH", body: { role: input.role, expectedUpdatedAt: iso(input.expectedUpdatedAt) } })),
|
|
3692
|
+
remove: async (projectId, membershipId, input) => this.request(`/api/projects/${encode(projectId)}/members/${encode(membershipId)}?expectedUpdatedAt=${encode(iso(input.expectedUpdatedAt))}`, { method: "DELETE" })
|
|
3693
|
+
};
|
|
3694
|
+
this.bots = {
|
|
3695
|
+
list: async (projectId) => this.records(`/api/projects/${encode(projectId)}/bots`, hydrateBot),
|
|
3696
|
+
add: async (projectId, input) => hydrateBot(await this.request(`/api/projects/${encode(projectId)}/bots`, { method: "POST", body: input })),
|
|
3697
|
+
update: async (projectId, membershipId, input) => hydrateBot(await this.request(`/api/projects/${encode(projectId)}/bots/${encode(membershipId)}`, { method: "PATCH", body: { ...input, expectedUpdatedAt: iso(input.expectedUpdatedAt) } })),
|
|
3698
|
+
pause: async (projectId, membershipId, input) => hydrateBot(await this.request(`/api/projects/${encode(projectId)}/bots/${encode(membershipId)}/pause`, { method: "POST", body: { expectedUpdatedAt: iso(input.expectedUpdatedAt) } })),
|
|
3699
|
+
resume: async (projectId, membershipId, input) => hydrateBot(await this.request(`/api/projects/${encode(projectId)}/bots/${encode(membershipId)}/resume`, { method: "POST", body: { expectedUpdatedAt: iso(input.expectedUpdatedAt) } })),
|
|
3700
|
+
remove: async (projectId, membershipId, input) => this.request(`/api/projects/${encode(projectId)}/bots/${encode(membershipId)}?expectedUpdatedAt=${encode(iso(input.expectedUpdatedAt))}`, { method: "DELETE" })
|
|
3701
|
+
};
|
|
3702
|
+
this.events = { connect: (projectId, options) => this.connect(projectId, options) };
|
|
3703
|
+
}
|
|
3704
|
+
async getRoom(projectId) {
|
|
3705
|
+
return hydrateRoom(await this.request(`/api/projects/${encode(projectId)}/room`));
|
|
3706
|
+
}
|
|
3707
|
+
async getRealtimeMode(projectId) {
|
|
3708
|
+
return this.request(`/api/projects/${encode(projectId)}/room/realtime-mode`);
|
|
3709
|
+
}
|
|
3710
|
+
async records(path, hydrate) {
|
|
3711
|
+
const result = await this.request(path);
|
|
3712
|
+
if (!Array.isArray(result))
|
|
3713
|
+
throw new ProjectRoomClientError("Invalid records response", 500, "INVALID_RESPONSE", false);
|
|
3714
|
+
return result.map(hydrate);
|
|
3715
|
+
}
|
|
3716
|
+
async request(path, options = {}) {
|
|
3717
|
+
const headers = { ...this.getHeaders(), ...options.headers ?? {} };
|
|
3718
|
+
const body = options.body === void 0 ? void 0 : JSON.parse(JSON.stringify(options.body));
|
|
3719
|
+
const response = await fetch(`${this.baseURL}${path}`, { method: options.method ?? "GET", headers, ...body === void 0 ? {} : { body: JSON.stringify(body) } });
|
|
3720
|
+
const payload = await response.json().catch(() => void 0);
|
|
3721
|
+
if (!response.ok || !payload?.success) {
|
|
3722
|
+
const error = payload?.error;
|
|
3723
|
+
throw new ProjectRoomClientError(typeof error?.message === "string" ? error.message : "Project Room request failed", response.status, typeof error?.code === "string" ? error.code : response.ok ? "INVALID_RESPONSE" : "HTTP_ERROR", error?.retryable === true, error?.details);
|
|
3724
|
+
}
|
|
3725
|
+
if (!Object.prototype.hasOwnProperty.call(payload, "data"))
|
|
3726
|
+
throw new ProjectRoomClientError("Missing response data", 500, "INVALID_RESPONSE", false);
|
|
3727
|
+
return payload.data;
|
|
3728
|
+
}
|
|
3729
|
+
connect(projectId, options) {
|
|
3730
|
+
const headers = { ...this.getHeaders(), Accept: "text/event-stream", ...options.lastEventId ? { "Last-Event-ID": options.lastEventId } : {} };
|
|
3731
|
+
let resolveOpen;
|
|
3732
|
+
let rejectOpen;
|
|
3733
|
+
const opened = new Promise((resolve, reject) => {
|
|
3734
|
+
resolveOpen = resolve;
|
|
3735
|
+
rejectOpen = reject;
|
|
3736
|
+
});
|
|
3737
|
+
const responsePromise = fetch(`${this.baseURL}/api/projects/${encode(projectId)}/room/events`, { headers, signal: options.signal }).then(async (response) => {
|
|
3738
|
+
if (!response.ok) {
|
|
3739
|
+
const payload = await response.json().catch(() => void 0);
|
|
3740
|
+
const error = payload?.error;
|
|
3741
|
+
throw new ProjectRoomClientError(typeof error?.message === "string" ? error.message : "Project Room stream failed", response.status, typeof error?.code === "string" ? error.code : "HTTP_ERROR", error?.retryable === true, error?.details);
|
|
3742
|
+
}
|
|
3743
|
+
if (response.headers?.get && response.headers.get("content-type")?.split(";")[0].trim() !== "text/event-stream")
|
|
3744
|
+
throw new ProjectRoomClientError("Project Room stream has invalid content type", response.status, "INVALID_RESPONSE", false);
|
|
3745
|
+
if (!response.body)
|
|
3746
|
+
throw new ProjectRoomClientError("Project Room stream has no body", 500, "INVALID_RESPONSE", false);
|
|
3747
|
+
resolveOpen({ status: 200, ...options.lastEventId === void 0 ? {} : { lastEventId: options.lastEventId } });
|
|
3748
|
+
return response;
|
|
3749
|
+
}).catch((error) => {
|
|
3750
|
+
rejectOpen(error);
|
|
3751
|
+
throw error;
|
|
3752
|
+
});
|
|
3753
|
+
const stream = async function* () {
|
|
3754
|
+
const response = await responsePromise;
|
|
3755
|
+
const body = response.body;
|
|
3756
|
+
if (!body)
|
|
3757
|
+
throw new ProjectRoomClientError("Project Room stream has no body", 500, "INVALID_RESPONSE", false);
|
|
3758
|
+
for await (const raw of parseSseBody(body, { strictJsonObject: true })) {
|
|
3759
|
+
try {
|
|
3760
|
+
const event = raw.event;
|
|
3761
|
+
const payload = isRecord(raw.data) ? raw.data : void 0;
|
|
3762
|
+
let value = payload;
|
|
3763
|
+
if (event === "ready" || event === "resync" || event === "access.revoked") {
|
|
3764
|
+
if (!payload || Object.prototype.hasOwnProperty.call(payload, "type"))
|
|
3765
|
+
throw new ProjectRoomClientError("Invalid SSE control", 200, "INVALID_EVENT", false);
|
|
3766
|
+
value = { type: event, data: payload };
|
|
3767
|
+
} else {
|
|
3768
|
+
if (typeof payload?.type !== "string" || payload.type !== event || typeof payload.id !== "string" || raw.id !== payload.id)
|
|
3769
|
+
throw new ProjectRoomClientError("Invalid SSE business event", 200, "INVALID_EVENT", false);
|
|
3770
|
+
value = payload;
|
|
3771
|
+
}
|
|
3772
|
+
yield { event: hydrateEvent(value), ...raw.id === void 0 ? {} : { id: raw.id }, ...raw.retry === void 0 ? {} : { retry: raw.retry } };
|
|
3773
|
+
} catch (error) {
|
|
3774
|
+
if (error instanceof ProjectRoomClientError && error.code === "INVALID_EVENT")
|
|
3775
|
+
throw new ProjectRoomClientError(error.message, 400, "INVALID_EVENT", false, error.details);
|
|
3776
|
+
if (error instanceof SseParseError)
|
|
3777
|
+
throw new ProjectRoomClientError(error.message, 400, "INVALID_EVENT", false);
|
|
3778
|
+
if (error instanceof ProjectRoomClientError)
|
|
3779
|
+
throw new ProjectRoomClientError(error.message, 400, "INVALID_EVENT", false, error.details);
|
|
3780
|
+
throw new ProjectRoomClientError("Invalid SSE event", 400, "INVALID_EVENT", false);
|
|
3781
|
+
}
|
|
3782
|
+
}
|
|
3783
|
+
}();
|
|
3784
|
+
return { opened, [Symbol.asyncIterator]: () => stream };
|
|
3785
|
+
}
|
|
3786
|
+
};
|
|
3787
|
+
function hydrateEvent(value) {
|
|
3788
|
+
const row = record(value);
|
|
3789
|
+
if (row.type === "ready") {
|
|
3790
|
+
exactKeys(row, ["type", "data"]);
|
|
3791
|
+
const data2 = record(row.data);
|
|
3792
|
+
exactKeys(data2, ["epoch", "headEventId"]);
|
|
3793
|
+
if (typeof data2.epoch !== "string" || data2.headEventId !== null && typeof data2.headEventId !== "string")
|
|
3794
|
+
throw new ProjectRoomClientError("Invalid SSE control", 200, "INVALID_EVENT", false);
|
|
3795
|
+
return { type: "ready", data: { epoch: data2.epoch, headEventId: data2.headEventId } };
|
|
3796
|
+
}
|
|
3797
|
+
if (row.type === "resync" || row.type === "access.revoked") {
|
|
3798
|
+
exactKeys(row, ["type", "data"]);
|
|
3799
|
+
const data2 = record(row.data);
|
|
3800
|
+
exactKeys(data2, ["reason"]);
|
|
3801
|
+
const reasons = row.type === "resync" ? ["SERVER_RESTART", "CURSOR_EXPIRED", "SLOW_CONSUMER"] : ["PROJECT_ACCESS_REVOKED", "TOKEN_EXPIRED"];
|
|
3802
|
+
return { type: row.type, data: { reason: oneOf(data2.reason, reasons, "reason") } };
|
|
3803
|
+
}
|
|
3804
|
+
const data = record(row.data);
|
|
3805
|
+
if (row.type === "message.created")
|
|
3806
|
+
return { ...row, occurredAt: date(row.occurredAt, "occurredAt"), data: { message: hydrateMessage(data.message) } };
|
|
3807
|
+
if (row.type === "roster.changed")
|
|
3808
|
+
return { ...row, occurredAt: date(row.occurredAt, "occurredAt"), data: { change: data.change, membership: hydratePublicBot(data.membership) } };
|
|
3809
|
+
if (row.type === "membership.changed")
|
|
3810
|
+
return { ...row, occurredAt: date(row.occurredAt, "occurredAt"), data: { change: data.change, membership: hydratePublicMember(data.membership) } };
|
|
3811
|
+
if (row.type === "task.changed")
|
|
3812
|
+
return { ...row, occurredAt: date(row.occurredAt, "occurredAt"), data: { taskId: requiredString(data, "taskId"), status: data.status, ownerMembershipId: requiredString(data, "ownerMembershipId"), updatedAt: date(data.updatedAt, "updatedAt") } };
|
|
3813
|
+
throw new ProjectRoomClientError("Invalid SSE event", 200, "INVALID_EVENT", false);
|
|
3814
|
+
}
|
|
3815
|
+
function hydratePublicMember(value) {
|
|
3816
|
+
const row = record(value);
|
|
3817
|
+
return { id: requiredString(row, "id"), userId: requiredString(row, "userId"), role: row.role, status: row.status, joinedAt: date(row.joinedAt, "joinedAt"), updatedAt: date(row.updatedAt, "updatedAt") };
|
|
3818
|
+
}
|
|
3819
|
+
function hydratePublicBot(value) {
|
|
3820
|
+
const row = record(value);
|
|
3821
|
+
return { id: requiredString(row, "id"), role: row.role, title: requiredString(row, "title"), ...row.responsibility === void 0 ? {} : { responsibility: row.responsibility }, mentionName: requiredString(row, "mentionName"), status: row.status, joinedAt: date(row.joinedAt, "joinedAt"), updatedAt: date(row.updatedAt, "updatedAt") };
|
|
3822
|
+
}
|
|
3823
|
+
|
|
3432
3824
|
// src/client.ts
|
|
3433
3825
|
var _Client = class extends AbstractClient {
|
|
3434
3826
|
/**
|
|
@@ -3444,6 +3836,7 @@ var _Client = class extends AbstractClient {
|
|
|
3444
3836
|
};
|
|
3445
3837
|
this.resources = new ResourcesClient(this.config.baseURL, () => this.getAllHeaders());
|
|
3446
3838
|
this.exportImport = new ExportImportClient(this.config, () => this.getAllHeaders());
|
|
3839
|
+
this.projectRooms = new ProjectRoomsClient(this.config.baseURL, () => this.getAllHeaders());
|
|
3447
3840
|
}
|
|
3448
3841
|
/**
|
|
3449
3842
|
* Helper method to handle fetch responses and errors
|
|
@@ -3659,41 +4052,8 @@ var _Client = class extends AbstractClient {
|
|
|
3659
4052
|
if (!response.body) {
|
|
3660
4053
|
throw new Error("Response body is null");
|
|
3661
4054
|
}
|
|
3662
|
-
const
|
|
3663
|
-
|
|
3664
|
-
let buffer = "";
|
|
3665
|
-
while (true) {
|
|
3666
|
-
const { done, value } = await reader.read();
|
|
3667
|
-
if (done)
|
|
3668
|
-
break;
|
|
3669
|
-
const chunk = decoder.decode(value, { stream: true });
|
|
3670
|
-
buffer += chunk;
|
|
3671
|
-
const lines = buffer.split("\n");
|
|
3672
|
-
buffer = lines.pop() || "";
|
|
3673
|
-
for (const line of lines) {
|
|
3674
|
-
if (line.trim().startsWith("data: ")) {
|
|
3675
|
-
try {
|
|
3676
|
-
const eventData = JSON.parse(line.trim().slice(6));
|
|
3677
|
-
onEvent(eventData);
|
|
3678
|
-
} catch (error) {
|
|
3679
|
-
console.error("Error parsing SSE data:", line, error);
|
|
3680
|
-
if (onError) {
|
|
3681
|
-
onError(
|
|
3682
|
-
error instanceof Error ? error : new Error(String(error))
|
|
3683
|
-
);
|
|
3684
|
-
}
|
|
3685
|
-
}
|
|
3686
|
-
}
|
|
3687
|
-
}
|
|
3688
|
-
}
|
|
3689
|
-
if (buffer && buffer.trim().startsWith("data: ")) {
|
|
3690
|
-
try {
|
|
3691
|
-
const eventData = JSON.parse(buffer.trim().slice(6));
|
|
3692
|
-
onEvent(eventData);
|
|
3693
|
-
} catch (error) {
|
|
3694
|
-
console.error("Error parsing SSE data:", buffer, error);
|
|
3695
|
-
}
|
|
3696
|
-
}
|
|
4055
|
+
for await (const frame of parseSseBody(response.body, { strictJsonObject: true }))
|
|
4056
|
+
onEvent(frame.data);
|
|
3697
4057
|
if (onComplete) {
|
|
3698
4058
|
onComplete();
|
|
3699
4059
|
}
|
|
@@ -3736,62 +4096,18 @@ var _Client = class extends AbstractClient {
|
|
|
3736
4096
|
const res = await fetch(`${this.config.baseURL}${path}`, { headers, signal });
|
|
3737
4097
|
if (!res.ok || !res.body)
|
|
3738
4098
|
throw new Error("Stream connection failed");
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
let event = "";
|
|
3743
|
-
let dataLines = [];
|
|
3744
|
-
const processLine = (rawLine) => {
|
|
3745
|
-
const line = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
|
|
3746
|
-
if (line === "") {
|
|
3747
|
-
if (dataLines.length === 0) {
|
|
3748
|
-
event = "";
|
|
3749
|
-
return null;
|
|
3750
|
-
}
|
|
3751
|
-
const data = dataLines.join("\n");
|
|
3752
|
-
const eventName = event;
|
|
3753
|
-
event = "";
|
|
3754
|
-
dataLines = [];
|
|
3755
|
-
try {
|
|
3756
|
-
return { event: eventName, data: JSON.parse(data) };
|
|
3757
|
-
} catch {
|
|
3758
|
-
return null;
|
|
3759
|
-
}
|
|
3760
|
-
}
|
|
3761
|
-
if (line.startsWith(":"))
|
|
3762
|
-
return null;
|
|
3763
|
-
const separator = line.indexOf(":");
|
|
3764
|
-
const field = separator === -1 ? line : line.slice(0, separator);
|
|
3765
|
-
let value = separator === -1 ? "" : line.slice(separator + 1);
|
|
3766
|
-
if (value.startsWith(" "))
|
|
3767
|
-
value = value.slice(1);
|
|
3768
|
-
if (field === "event")
|
|
3769
|
-
event = value;
|
|
3770
|
-
else if (field === "data")
|
|
3771
|
-
dataLines.push(value);
|
|
3772
|
-
return null;
|
|
3773
|
-
};
|
|
3774
|
-
while (true) {
|
|
3775
|
-
const { done, value } = await reader.read();
|
|
3776
|
-
if (done) {
|
|
3777
|
-
buffer += decoder.decode();
|
|
3778
|
-
break;
|
|
4099
|
+
try {
|
|
4100
|
+
for await (const frame of parseSseBody(res.body, { strictJsonObject: true })) {
|
|
4101
|
+
yield { event: frame.event, data: frame.data };
|
|
3779
4102
|
}
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
if (parsed)
|
|
3786
|
-
yield parsed;
|
|
3787
|
-
newline = buffer.indexOf("\n");
|
|
4103
|
+
} catch (error) {
|
|
4104
|
+
if (error instanceof SseParseError) {
|
|
4105
|
+
const parseError = new Error(error.message);
|
|
4106
|
+
parseError.name = "StreamParseError";
|
|
4107
|
+
throw parseError;
|
|
3788
4108
|
}
|
|
4109
|
+
throw error;
|
|
3789
4110
|
}
|
|
3790
|
-
if (buffer.length > 0)
|
|
3791
|
-
processLine(buffer);
|
|
3792
|
-
const finalEvent = processLine("");
|
|
3793
|
-
if (finalEvent)
|
|
3794
|
-
yield finalEvent;
|
|
3795
4111
|
}
|
|
3796
4112
|
/**
|
|
3797
4113
|
* Get all headers including workspace context
|
|
@@ -3833,41 +4149,8 @@ var _Client = class extends AbstractClient {
|
|
|
3833
4149
|
if (!response.body) {
|
|
3834
4150
|
throw new Error("Response body is null");
|
|
3835
4151
|
}
|
|
3836
|
-
const
|
|
3837
|
-
|
|
3838
|
-
let buffer = "";
|
|
3839
|
-
while (true) {
|
|
3840
|
-
const { done, value } = await reader.read();
|
|
3841
|
-
if (done)
|
|
3842
|
-
break;
|
|
3843
|
-
const chunk = decoder.decode(value, { stream: true });
|
|
3844
|
-
buffer += chunk;
|
|
3845
|
-
const lines = buffer.split("\n");
|
|
3846
|
-
buffer = lines.pop() || "";
|
|
3847
|
-
for (const line of lines) {
|
|
3848
|
-
if (line.trim().startsWith("data: ")) {
|
|
3849
|
-
try {
|
|
3850
|
-
const eventData = JSON.parse(line.trim().slice(6));
|
|
3851
|
-
onEvent(eventData);
|
|
3852
|
-
} catch (error) {
|
|
3853
|
-
console.error("Error parsing SSE data:", line, error);
|
|
3854
|
-
if (onError) {
|
|
3855
|
-
onError(
|
|
3856
|
-
error instanceof Error ? error : new Error(String(error))
|
|
3857
|
-
);
|
|
3858
|
-
}
|
|
3859
|
-
}
|
|
3860
|
-
}
|
|
3861
|
-
}
|
|
3862
|
-
}
|
|
3863
|
-
if (buffer && buffer.trim().startsWith("data: ")) {
|
|
3864
|
-
try {
|
|
3865
|
-
const eventData = JSON.parse(buffer.trim().slice(6));
|
|
3866
|
-
onEvent(eventData);
|
|
3867
|
-
} catch (error) {
|
|
3868
|
-
console.error("Error parsing SSE data:", buffer, error);
|
|
3869
|
-
}
|
|
3870
|
-
}
|
|
4152
|
+
for await (const frame of parseSseBody(response.body, { strictJsonObject: true }))
|
|
4153
|
+
onEvent(frame.data);
|
|
3871
4154
|
if (onComplete) {
|
|
3872
4155
|
if (options.enableReturnStateWhenSteamCompleted) {
|
|
3873
4156
|
try {
|
|
@@ -4638,6 +4921,8 @@ export {
|
|
|
4638
4921
|
Client,
|
|
4639
4922
|
ExportImportClient,
|
|
4640
4923
|
NetworkError,
|
|
4924
|
+
ProjectRoomClientError,
|
|
4925
|
+
ProjectRoomsClient,
|
|
4641
4926
|
ResourcesClient,
|
|
4642
4927
|
ScheduleExecutionType,
|
|
4643
4928
|
ScheduledTaskStatus,
|