@standardagents/builder 0.17.3 → 0.18.1
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/built-in-routes.js +442 -358
- package/dist/built-in-routes.js.map +1 -1
- package/dist/client/LoginView.js +1 -1
- package/dist/client/index.js +3 -3
- package/dist/index.js +461 -47
- package/dist/index.js.map +1 -1
- package/dist/plugin.js +70 -2
- package/dist/plugin.js.map +1 -1
- package/dist/runtime.d.ts +72 -4
- package/dist/runtime.js +391 -45
- package/dist/runtime.js.map +1 -1
- package/package.json +4 -4
package/dist/runtime.js
CHANGED
|
@@ -12556,7 +12556,7 @@ function isValidUserToken(token) {
|
|
|
12556
12556
|
return token.startsWith("agtuser_") && token.length > 10;
|
|
12557
12557
|
}
|
|
12558
12558
|
function isValidApiKey(key) {
|
|
12559
|
-
return key.startsWith("agtbldr_") && key.length > 10;
|
|
12559
|
+
return key.startsWith("agtbldr_") && key.length > 10 || key.startsWith("sak_live_") && key.length > 10;
|
|
12560
12560
|
}
|
|
12561
12561
|
async function verifySignedToken(signedToken, encryptionKey) {
|
|
12562
12562
|
try {
|
|
@@ -12680,7 +12680,11 @@ async function authenticate(request, env) {
|
|
|
12680
12680
|
user: {
|
|
12681
12681
|
id: user.id,
|
|
12682
12682
|
username: user.username,
|
|
12683
|
-
role: user.role
|
|
12683
|
+
role: user.role,
|
|
12684
|
+
platform_user_id: user.platform_user_id ?? null,
|
|
12685
|
+
email: user.email ?? null,
|
|
12686
|
+
display_name: user.display_name ?? null,
|
|
12687
|
+
avatar_url: user.avatar_url ?? null
|
|
12684
12688
|
},
|
|
12685
12689
|
authType: "session"
|
|
12686
12690
|
};
|
|
@@ -12698,7 +12702,11 @@ async function authenticate(request, env) {
|
|
|
12698
12702
|
user: {
|
|
12699
12703
|
id: user.id,
|
|
12700
12704
|
username: user.username,
|
|
12701
|
-
role: user.role
|
|
12705
|
+
role: user.role,
|
|
12706
|
+
platform_user_id: user.platform_user_id ?? null,
|
|
12707
|
+
email: user.email ?? null,
|
|
12708
|
+
display_name: user.display_name ?? null,
|
|
12709
|
+
avatar_url: user.avatar_url ?? null
|
|
12702
12710
|
},
|
|
12703
12711
|
authType: "api_key"
|
|
12704
12712
|
};
|
|
@@ -15488,9 +15496,9 @@ var DurableThread = class extends DurableObject {
|
|
|
15488
15496
|
* Each migration is run in order, starting from the current version + 1.
|
|
15489
15497
|
*/
|
|
15490
15498
|
async runMigrations(fromVersion) {
|
|
15491
|
-
for (const
|
|
15492
|
-
if (
|
|
15493
|
-
await
|
|
15499
|
+
for (const migration38 of migrations) {
|
|
15500
|
+
if (migration38.version > fromVersion) {
|
|
15501
|
+
await migration38.up(this.ctx.storage.sql);
|
|
15494
15502
|
}
|
|
15495
15503
|
}
|
|
15496
15504
|
}
|
|
@@ -18925,9 +18933,38 @@ var migration36 = {
|
|
|
18925
18933
|
}
|
|
18926
18934
|
};
|
|
18927
18935
|
|
|
18936
|
+
// src/durable-objects/agentbuilder-migrations/0007_platform_identity_replica.ts
|
|
18937
|
+
var migration37 = {
|
|
18938
|
+
version: 7,
|
|
18939
|
+
async up(sql) {
|
|
18940
|
+
sql.exec(`ALTER TABLE users ADD COLUMN platform_user_id TEXT`);
|
|
18941
|
+
sql.exec(`ALTER TABLE users ADD COLUMN email TEXT`);
|
|
18942
|
+
sql.exec(`ALTER TABLE users ADD COLUMN display_name TEXT`);
|
|
18943
|
+
sql.exec(`ALTER TABLE users ADD COLUMN avatar_url TEXT`);
|
|
18944
|
+
sql.exec(`ALTER TABLE users ADD COLUMN instance_role TEXT NOT NULL DEFAULT 'admin' CHECK (instance_role IN ('admin', 'user'))`);
|
|
18945
|
+
sql.exec(`ALTER TABLE users ADD COLUMN source TEXT NOT NULL DEFAULT 'local' CHECK (source IN ('local', 'standard_agents'))`);
|
|
18946
|
+
sql.exec(`ALTER TABLE users ADD COLUMN replica_active INTEGER NOT NULL DEFAULT 1`);
|
|
18947
|
+
sql.exec(`ALTER TABLE users ADD COLUMN replica_updated_at INTEGER`);
|
|
18948
|
+
sql.exec(`ALTER TABLE users ADD COLUMN deleted_at INTEGER`);
|
|
18949
|
+
sql.exec(`CREATE INDEX IF NOT EXISTS idx_users_platform_user_id ON users(platform_user_id)`);
|
|
18950
|
+
sql.exec(`CREATE INDEX IF NOT EXISTS idx_users_replica_active ON users(replica_active)`);
|
|
18951
|
+
sql.exec(`CREATE INDEX IF NOT EXISTS idx_users_instance_role ON users(instance_role)`);
|
|
18952
|
+
sql.exec(`ALTER TABLE api_keys ADD COLUMN platform_key_id TEXT`);
|
|
18953
|
+
sql.exec(`ALTER TABLE api_keys ADD COLUMN scope TEXT`);
|
|
18954
|
+
sql.exec(`ALTER TABLE api_keys ADD COLUMN source TEXT NOT NULL DEFAULT 'local' CHECK (source IN ('local', 'standard_agents'))`);
|
|
18955
|
+
sql.exec(`ALTER TABLE api_keys ADD COLUMN replica_active INTEGER NOT NULL DEFAULT 1`);
|
|
18956
|
+
sql.exec(`ALTER TABLE api_keys ADD COLUMN replica_updated_at INTEGER`);
|
|
18957
|
+
sql.exec(`CREATE INDEX IF NOT EXISTS idx_api_keys_platform_key_id ON api_keys(platform_key_id)`);
|
|
18958
|
+
sql.exec(`CREATE INDEX IF NOT EXISTS idx_api_keys_replica_active ON api_keys(replica_active)`);
|
|
18959
|
+
sql.exec(`
|
|
18960
|
+
INSERT OR REPLACE INTO _metadata (key, value) VALUES ('schema_version', '7')
|
|
18961
|
+
`);
|
|
18962
|
+
}
|
|
18963
|
+
};
|
|
18964
|
+
|
|
18928
18965
|
// src/durable-objects/agentbuilder-migrations/index.ts
|
|
18929
|
-
var migrations2 = [migration31, migration32, migration33, migration34, migration35, migration36];
|
|
18930
|
-
var LATEST_SCHEMA_VERSION2 =
|
|
18966
|
+
var migrations2 = [migration31, migration32, migration33, migration34, migration35, migration36, migration37];
|
|
18967
|
+
var LATEST_SCHEMA_VERSION2 = 7;
|
|
18931
18968
|
|
|
18932
18969
|
// src/utils/crypto.ts
|
|
18933
18970
|
var CryptoUtil = class {
|
|
@@ -19551,9 +19588,9 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
19551
19588
|
}
|
|
19552
19589
|
}
|
|
19553
19590
|
async runMigrations(fromVersion) {
|
|
19554
|
-
for (const
|
|
19555
|
-
if (
|
|
19556
|
-
await
|
|
19591
|
+
for (const migration38 of migrations2) {
|
|
19592
|
+
if (migration38.version > fromVersion) {
|
|
19593
|
+
await migration38.up(this.ctx.storage.sql);
|
|
19557
19594
|
}
|
|
19558
19595
|
}
|
|
19559
19596
|
}
|
|
@@ -20586,27 +20623,54 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
20586
20623
|
// ============================================================
|
|
20587
20624
|
// User Authentication Methods
|
|
20588
20625
|
// ============================================================
|
|
20626
|
+
normalizeReplicaUsername(input, fallback) {
|
|
20627
|
+
const normalized = (input || fallback).trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 50);
|
|
20628
|
+
return normalized || fallback;
|
|
20629
|
+
}
|
|
20630
|
+
async availableReplicaUsername(candidate, platformUserId) {
|
|
20631
|
+
const existing = await this.ctx.storage.sql.exec(
|
|
20632
|
+
`SELECT id, platform_user_id FROM users WHERE username = ? LIMIT 1`,
|
|
20633
|
+
candidate
|
|
20634
|
+
);
|
|
20635
|
+
const row = existing.toArray()[0];
|
|
20636
|
+
if (!row || row.platform_user_id === platformUserId) {
|
|
20637
|
+
return candidate;
|
|
20638
|
+
}
|
|
20639
|
+
const suffix = platformUserId.replace(/[^a-zA-Z0-9]/g, "").slice(0, 8) || "user";
|
|
20640
|
+
const trimmed = candidate.slice(0, Math.max(1, 50 - suffix.length - 1)).replace(/-+$/g, "");
|
|
20641
|
+
return `${trimmed || "sa"}-${suffix}`;
|
|
20642
|
+
}
|
|
20643
|
+
userFromRow(row) {
|
|
20644
|
+
return {
|
|
20645
|
+
id: row.id,
|
|
20646
|
+
username: row.username,
|
|
20647
|
+
password_hash: row.password_hash,
|
|
20648
|
+
role: row.role === "user" ? "user" : "admin",
|
|
20649
|
+
platform_user_id: row.platform_user_id ?? null,
|
|
20650
|
+
email: row.email ?? null,
|
|
20651
|
+
display_name: row.display_name ?? null,
|
|
20652
|
+
avatar_url: row.avatar_url ?? null,
|
|
20653
|
+
source: row.source ?? "local",
|
|
20654
|
+
replica_active: row.replica_active ?? 1,
|
|
20655
|
+
created_at: row.created_at,
|
|
20656
|
+
updated_at: row.updated_at
|
|
20657
|
+
};
|
|
20658
|
+
}
|
|
20589
20659
|
/**
|
|
20590
20660
|
* Get a user by username.
|
|
20591
20661
|
*/
|
|
20592
20662
|
async getUserByUsername(username) {
|
|
20593
20663
|
await this.ensureMigrated();
|
|
20594
20664
|
const cursor = await this.ctx.storage.sql.exec(
|
|
20595
|
-
`SELECT id, username, password_hash,
|
|
20596
|
-
|
|
20665
|
+
`SELECT id, username, password_hash, COALESCE(instance_role, role) AS role,
|
|
20666
|
+
platform_user_id, email, display_name, avatar_url, source, replica_active,
|
|
20667
|
+
created_at, updated_at
|
|
20668
|
+
FROM users WHERE username = ? AND deleted_at IS NULL AND replica_active != 0`,
|
|
20597
20669
|
username
|
|
20598
20670
|
);
|
|
20599
20671
|
const rows = cursor.toArray();
|
|
20600
20672
|
if (rows.length === 0) return null;
|
|
20601
|
-
|
|
20602
|
-
return {
|
|
20603
|
-
id: row.id,
|
|
20604
|
-
username: row.username,
|
|
20605
|
-
password_hash: row.password_hash,
|
|
20606
|
-
role: row.role,
|
|
20607
|
-
created_at: row.created_at,
|
|
20608
|
-
updated_at: row.updated_at
|
|
20609
|
-
};
|
|
20673
|
+
return this.userFromRow(rows[0]);
|
|
20610
20674
|
}
|
|
20611
20675
|
/**
|
|
20612
20676
|
* Get a user by ID.
|
|
@@ -20614,21 +20678,15 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
20614
20678
|
async getUserById(id) {
|
|
20615
20679
|
await this.ensureMigrated();
|
|
20616
20680
|
const cursor = await this.ctx.storage.sql.exec(
|
|
20617
|
-
`SELECT id, username, password_hash,
|
|
20618
|
-
|
|
20681
|
+
`SELECT id, username, password_hash, COALESCE(instance_role, role) AS role,
|
|
20682
|
+
platform_user_id, email, display_name, avatar_url, source, replica_active,
|
|
20683
|
+
created_at, updated_at
|
|
20684
|
+
FROM users WHERE id = ? AND deleted_at IS NULL AND replica_active != 0`,
|
|
20619
20685
|
id
|
|
20620
20686
|
);
|
|
20621
20687
|
const rows = cursor.toArray();
|
|
20622
20688
|
if (rows.length === 0) return null;
|
|
20623
|
-
|
|
20624
|
-
return {
|
|
20625
|
-
id: row.id,
|
|
20626
|
-
username: row.username,
|
|
20627
|
-
password_hash: row.password_hash,
|
|
20628
|
-
role: row.role,
|
|
20629
|
-
created_at: row.created_at,
|
|
20630
|
-
updated_at: row.updated_at
|
|
20631
|
-
};
|
|
20689
|
+
return this.userFromRow(rows[0]);
|
|
20632
20690
|
}
|
|
20633
20691
|
/**
|
|
20634
20692
|
* Create a new user.
|
|
@@ -20638,12 +20696,23 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
20638
20696
|
const id = crypto.randomUUID();
|
|
20639
20697
|
const now = Math.floor(Date.now() / 1e3);
|
|
20640
20698
|
await this.ctx.storage.sql.exec(
|
|
20641
|
-
`INSERT INTO users (
|
|
20642
|
-
|
|
20699
|
+
`INSERT INTO users (
|
|
20700
|
+
id, username, password_hash, role, instance_role, platform_user_id,
|
|
20701
|
+
email, display_name, avatar_url, source, replica_active,
|
|
20702
|
+
replica_updated_at, created_at, updated_at
|
|
20703
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
20643
20704
|
id,
|
|
20644
20705
|
params.username,
|
|
20645
20706
|
params.password_hash,
|
|
20707
|
+
"admin",
|
|
20646
20708
|
params.role || "admin",
|
|
20709
|
+
params.platform_user_id ?? null,
|
|
20710
|
+
params.email ?? null,
|
|
20711
|
+
params.display_name ?? null,
|
|
20712
|
+
params.avatar_url ?? null,
|
|
20713
|
+
params.source ?? "local",
|
|
20714
|
+
1,
|
|
20715
|
+
params.source === "standard_agents" ? now : null,
|
|
20647
20716
|
now,
|
|
20648
20717
|
now
|
|
20649
20718
|
);
|
|
@@ -20652,6 +20721,12 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
20652
20721
|
username: params.username,
|
|
20653
20722
|
password_hash: params.password_hash,
|
|
20654
20723
|
role: params.role || "admin",
|
|
20724
|
+
platform_user_id: params.platform_user_id ?? null,
|
|
20725
|
+
email: params.email ?? null,
|
|
20726
|
+
display_name: params.display_name ?? null,
|
|
20727
|
+
avatar_url: params.avatar_url ?? null,
|
|
20728
|
+
source: params.source ?? "local",
|
|
20729
|
+
replica_active: 1,
|
|
20655
20730
|
created_at: now,
|
|
20656
20731
|
updated_at: now
|
|
20657
20732
|
};
|
|
@@ -20671,11 +20746,24 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
20671
20746
|
*/
|
|
20672
20747
|
async listUsers() {
|
|
20673
20748
|
await this.ensureMigrated();
|
|
20674
|
-
const cursor = await this.ctx.storage.sql.exec(
|
|
20749
|
+
const cursor = await this.ctx.storage.sql.exec(
|
|
20750
|
+
`SELECT id, username, COALESCE(instance_role, role) AS role,
|
|
20751
|
+
platform_user_id, email, display_name, avatar_url, source, replica_active,
|
|
20752
|
+
created_at, updated_at
|
|
20753
|
+
FROM users
|
|
20754
|
+
WHERE deleted_at IS NULL
|
|
20755
|
+
ORDER BY created_at DESC`
|
|
20756
|
+
);
|
|
20675
20757
|
return cursor.toArray().map((row) => ({
|
|
20676
20758
|
id: row.id,
|
|
20677
20759
|
username: row.username,
|
|
20678
|
-
role: row.role,
|
|
20760
|
+
role: row.role === "user" ? "user" : "admin",
|
|
20761
|
+
platform_user_id: row.platform_user_id ?? null,
|
|
20762
|
+
email: row.email ?? null,
|
|
20763
|
+
display_name: row.display_name ?? null,
|
|
20764
|
+
avatar_url: row.avatar_url ?? null,
|
|
20765
|
+
source: row.source ?? "local",
|
|
20766
|
+
replica_active: row.replica_active ?? 1,
|
|
20679
20767
|
created_at: row.created_at,
|
|
20680
20768
|
updated_at: row.updated_at
|
|
20681
20769
|
}));
|
|
@@ -20699,14 +20787,42 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
20699
20787
|
values.push(params.password_hash);
|
|
20700
20788
|
}
|
|
20701
20789
|
if (params.role !== void 0) {
|
|
20702
|
-
updates.push("
|
|
20790
|
+
updates.push("instance_role = ?");
|
|
20703
20791
|
values.push(params.role);
|
|
20704
20792
|
}
|
|
20793
|
+
if (params.platform_user_id !== void 0) {
|
|
20794
|
+
updates.push("platform_user_id = ?");
|
|
20795
|
+
values.push(params.platform_user_id);
|
|
20796
|
+
}
|
|
20797
|
+
if (params.email !== void 0) {
|
|
20798
|
+
updates.push("email = ?");
|
|
20799
|
+
values.push(params.email);
|
|
20800
|
+
}
|
|
20801
|
+
if (params.display_name !== void 0) {
|
|
20802
|
+
updates.push("display_name = ?");
|
|
20803
|
+
values.push(params.display_name);
|
|
20804
|
+
}
|
|
20805
|
+
if (params.avatar_url !== void 0) {
|
|
20806
|
+
updates.push("avatar_url = ?");
|
|
20807
|
+
values.push(params.avatar_url);
|
|
20808
|
+
}
|
|
20809
|
+
if (params.source !== void 0) {
|
|
20810
|
+
updates.push("source = ?");
|
|
20811
|
+
values.push(params.source);
|
|
20812
|
+
}
|
|
20813
|
+
if (params.replica_active !== void 0) {
|
|
20814
|
+
updates.push("replica_active = ?");
|
|
20815
|
+
values.push(params.replica_active);
|
|
20816
|
+
}
|
|
20705
20817
|
if (updates.length === 0) {
|
|
20706
20818
|
return existing;
|
|
20707
20819
|
}
|
|
20708
20820
|
updates.push("updated_at = ?");
|
|
20709
20821
|
values.push(now);
|
|
20822
|
+
if (params.source === "standard_agents" || params.replica_active !== void 0) {
|
|
20823
|
+
updates.push("replica_updated_at = ?");
|
|
20824
|
+
values.push(now);
|
|
20825
|
+
}
|
|
20710
20826
|
values.push(id);
|
|
20711
20827
|
await this.ctx.storage.sql.exec(
|
|
20712
20828
|
`UPDATE users SET ${updates.join(", ")} WHERE id = ?`,
|
|
@@ -20727,9 +20843,223 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
20727
20843
|
`DELETE FROM api_keys WHERE user_id = ?`,
|
|
20728
20844
|
id
|
|
20729
20845
|
);
|
|
20730
|
-
await this.ctx.storage.sql.exec(
|
|
20846
|
+
await this.ctx.storage.sql.exec(
|
|
20847
|
+
`UPDATE users SET deleted_at = ?, replica_active = 0 WHERE id = ?`,
|
|
20848
|
+
Math.floor(Date.now() / 1e3),
|
|
20849
|
+
id
|
|
20850
|
+
);
|
|
20731
20851
|
return true;
|
|
20732
20852
|
}
|
|
20853
|
+
/**
|
|
20854
|
+
* Upsert a platform-replicated identity and return the local user row.
|
|
20855
|
+
*/
|
|
20856
|
+
async upsertPlatformReplicaUser(replica) {
|
|
20857
|
+
await this.ensureMigrated();
|
|
20858
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
20859
|
+
const fallback = this.normalizeReplicaUsername(
|
|
20860
|
+
replica.email?.split("@")[0] ?? null,
|
|
20861
|
+
`sa-${replica.platform_user_id.slice(0, 12)}`
|
|
20862
|
+
);
|
|
20863
|
+
const username = this.normalizeReplicaUsername(
|
|
20864
|
+
replica.username ?? replica.display_name ?? replica.email ?? null,
|
|
20865
|
+
fallback
|
|
20866
|
+
);
|
|
20867
|
+
const existingCursor = await this.ctx.storage.sql.exec(
|
|
20868
|
+
`SELECT id FROM users WHERE platform_user_id = ? LIMIT 1`,
|
|
20869
|
+
replica.platform_user_id
|
|
20870
|
+
);
|
|
20871
|
+
const existing = existingCursor.toArray()[0];
|
|
20872
|
+
const availableUsername = await this.availableReplicaUsername(username, replica.platform_user_id);
|
|
20873
|
+
if (existing) {
|
|
20874
|
+
await this.ctx.storage.sql.exec(
|
|
20875
|
+
`UPDATE users SET
|
|
20876
|
+
username = ?,
|
|
20877
|
+
instance_role = ?,
|
|
20878
|
+
email = ?,
|
|
20879
|
+
display_name = ?,
|
|
20880
|
+
avatar_url = ?,
|
|
20881
|
+
source = 'standard_agents',
|
|
20882
|
+
replica_active = 1,
|
|
20883
|
+
replica_updated_at = ?,
|
|
20884
|
+
deleted_at = NULL,
|
|
20885
|
+
updated_at = ?
|
|
20886
|
+
WHERE id = ?`,
|
|
20887
|
+
availableUsername,
|
|
20888
|
+
replica.role,
|
|
20889
|
+
replica.email ?? null,
|
|
20890
|
+
replica.display_name ?? null,
|
|
20891
|
+
replica.avatar_url ?? null,
|
|
20892
|
+
now,
|
|
20893
|
+
now,
|
|
20894
|
+
existing.id
|
|
20895
|
+
);
|
|
20896
|
+
const updated = await this.getUserById(existing.id);
|
|
20897
|
+
if (!updated) {
|
|
20898
|
+
throw new Error("Failed to load replicated user after update");
|
|
20899
|
+
}
|
|
20900
|
+
return updated;
|
|
20901
|
+
}
|
|
20902
|
+
return this.createUser({
|
|
20903
|
+
username: availableUsername,
|
|
20904
|
+
password_hash: `platform-replica:${crypto.randomUUID()}`,
|
|
20905
|
+
role: replica.role,
|
|
20906
|
+
platform_user_id: replica.platform_user_id,
|
|
20907
|
+
email: replica.email ?? null,
|
|
20908
|
+
display_name: replica.display_name ?? null,
|
|
20909
|
+
avatar_url: replica.avatar_url ?? null,
|
|
20910
|
+
source: "standard_agents"
|
|
20911
|
+
});
|
|
20912
|
+
}
|
|
20913
|
+
/**
|
|
20914
|
+
* Apply a full platform read-replica snapshot for this instance.
|
|
20915
|
+
*/
|
|
20916
|
+
async applyPlatformReplicaSnapshot(snapshot) {
|
|
20917
|
+
await this.ensureMigrated();
|
|
20918
|
+
const activeUserIds = /* @__PURE__ */ new Set();
|
|
20919
|
+
for (const replicaUser of snapshot.users) {
|
|
20920
|
+
const user = await this.upsertPlatformReplicaUser(replicaUser);
|
|
20921
|
+
activeUserIds.add(user.id);
|
|
20922
|
+
}
|
|
20923
|
+
const activeList = Array.from(activeUserIds);
|
|
20924
|
+
if (activeList.length > 0) {
|
|
20925
|
+
const placeholders = activeList.map(() => "?").join(", ");
|
|
20926
|
+
const inactive = await this.ctx.storage.sql.exec(
|
|
20927
|
+
`SELECT id FROM users
|
|
20928
|
+
WHERE source = 'standard_agents'
|
|
20929
|
+
AND replica_active != 0
|
|
20930
|
+
AND id NOT IN (${placeholders})`,
|
|
20931
|
+
...activeList
|
|
20932
|
+
);
|
|
20933
|
+
for (const row of inactive.toArray()) {
|
|
20934
|
+
await this.ctx.storage.sql.exec(`DELETE FROM sessions WHERE user_id = ?`, row.id);
|
|
20935
|
+
await this.ctx.storage.sql.exec(
|
|
20936
|
+
`UPDATE users SET replica_active = 0, deleted_at = ?, replica_updated_at = ?, updated_at = ? WHERE id = ?`,
|
|
20937
|
+
Math.floor(Date.now() / 1e3),
|
|
20938
|
+
Math.floor(Date.now() / 1e3),
|
|
20939
|
+
Math.floor(Date.now() / 1e3),
|
|
20940
|
+
row.id
|
|
20941
|
+
);
|
|
20942
|
+
}
|
|
20943
|
+
} else {
|
|
20944
|
+
const inactive = await this.ctx.storage.sql.exec(
|
|
20945
|
+
`SELECT id FROM users WHERE source = 'standard_agents' AND replica_active != 0`
|
|
20946
|
+
);
|
|
20947
|
+
for (const row of inactive.toArray()) {
|
|
20948
|
+
await this.ctx.storage.sql.exec(`DELETE FROM sessions WHERE user_id = ?`, row.id);
|
|
20949
|
+
}
|
|
20950
|
+
const now2 = Math.floor(Date.now() / 1e3);
|
|
20951
|
+
await this.ctx.storage.sql.exec(
|
|
20952
|
+
`UPDATE users SET replica_active = 0, deleted_at = ?, replica_updated_at = ?, updated_at = ?
|
|
20953
|
+
WHERE source = 'standard_agents'`,
|
|
20954
|
+
now2,
|
|
20955
|
+
now2,
|
|
20956
|
+
now2
|
|
20957
|
+
);
|
|
20958
|
+
}
|
|
20959
|
+
const activePlatformKeyIds = /* @__PURE__ */ new Set();
|
|
20960
|
+
const keys = snapshot.api_keys ?? [];
|
|
20961
|
+
for (const key of keys) {
|
|
20962
|
+
const user = key.user_platform_id ? await this.getUserByPlatformUserId(key.user_platform_id) : await this.getFirstReplicaAdminUser();
|
|
20963
|
+
const keyUser = user ?? await this.getFirstReplicaAdminUser();
|
|
20964
|
+
if (!keyUser) continue;
|
|
20965
|
+
activePlatformKeyIds.add(key.id);
|
|
20966
|
+
await this.upsertPlatformReplicaApiKey(key, keyUser.id);
|
|
20967
|
+
}
|
|
20968
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
20969
|
+
if (activePlatformKeyIds.size > 0) {
|
|
20970
|
+
const ids = Array.from(activePlatformKeyIds);
|
|
20971
|
+
const placeholders = ids.map(() => "?").join(", ");
|
|
20972
|
+
await this.ctx.storage.sql.exec(
|
|
20973
|
+
`UPDATE api_keys SET replica_active = 0, replica_updated_at = ?
|
|
20974
|
+
WHERE source = 'standard_agents' AND platform_key_id NOT IN (${placeholders})`,
|
|
20975
|
+
now,
|
|
20976
|
+
...ids
|
|
20977
|
+
);
|
|
20978
|
+
} else {
|
|
20979
|
+
await this.ctx.storage.sql.exec(
|
|
20980
|
+
`UPDATE api_keys SET replica_active = 0, replica_updated_at = ?
|
|
20981
|
+
WHERE source = 'standard_agents'`,
|
|
20982
|
+
now
|
|
20983
|
+
);
|
|
20984
|
+
}
|
|
20985
|
+
return { users: activeUserIds.size, api_keys: activePlatformKeyIds.size };
|
|
20986
|
+
}
|
|
20987
|
+
async getUserByPlatformUserId(platformUserId) {
|
|
20988
|
+
await this.ensureMigrated();
|
|
20989
|
+
const cursor = await this.ctx.storage.sql.exec(
|
|
20990
|
+
`SELECT id FROM users
|
|
20991
|
+
WHERE platform_user_id = ? AND deleted_at IS NULL AND replica_active != 0
|
|
20992
|
+
LIMIT 1`,
|
|
20993
|
+
platformUserId
|
|
20994
|
+
);
|
|
20995
|
+
const row = cursor.toArray()[0];
|
|
20996
|
+
return row ? this.getUserById(row.id) : null;
|
|
20997
|
+
}
|
|
20998
|
+
async getFirstReplicaAdminUser() {
|
|
20999
|
+
await this.ensureMigrated();
|
|
21000
|
+
const cursor = await this.ctx.storage.sql.exec(
|
|
21001
|
+
`SELECT id FROM users
|
|
21002
|
+
WHERE source = 'standard_agents'
|
|
21003
|
+
AND instance_role = 'admin'
|
|
21004
|
+
AND deleted_at IS NULL
|
|
21005
|
+
AND replica_active != 0
|
|
21006
|
+
ORDER BY created_at ASC
|
|
21007
|
+
LIMIT 1`
|
|
21008
|
+
);
|
|
21009
|
+
const row = cursor.toArray()[0];
|
|
21010
|
+
return row ? this.getUserById(row.id) : null;
|
|
21011
|
+
}
|
|
21012
|
+
async upsertPlatformReplicaApiKey(key, userId) {
|
|
21013
|
+
await this.ensureMigrated();
|
|
21014
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
21015
|
+
const existing = await this.ctx.storage.sql.exec(
|
|
21016
|
+
`SELECT id FROM api_keys WHERE platform_key_id = ? LIMIT 1`,
|
|
21017
|
+
key.id
|
|
21018
|
+
);
|
|
21019
|
+
const row = existing.toArray()[0];
|
|
21020
|
+
const name = key.name || `Standard Agents ${key.key_prefix}`;
|
|
21021
|
+
const lastFive = key.last_five || key.key_prefix.slice(-5);
|
|
21022
|
+
if (row) {
|
|
21023
|
+
await this.ctx.storage.sql.exec(
|
|
21024
|
+
`UPDATE api_keys SET
|
|
21025
|
+
name = ?,
|
|
21026
|
+
key_hash = ?,
|
|
21027
|
+
key_prefix = ?,
|
|
21028
|
+
last_five = ?,
|
|
21029
|
+
user_id = ?,
|
|
21030
|
+
scope = ?,
|
|
21031
|
+
source = 'standard_agents',
|
|
21032
|
+
replica_active = 1,
|
|
21033
|
+
replica_updated_at = ?
|
|
21034
|
+
WHERE id = ?`,
|
|
21035
|
+
name,
|
|
21036
|
+
key.key_hash,
|
|
21037
|
+
key.key_prefix,
|
|
21038
|
+
lastFive,
|
|
21039
|
+
userId,
|
|
21040
|
+
key.scope ?? null,
|
|
21041
|
+
now,
|
|
21042
|
+
row.id
|
|
21043
|
+
);
|
|
21044
|
+
return;
|
|
21045
|
+
}
|
|
21046
|
+
await this.ctx.storage.sql.exec(
|
|
21047
|
+
`INSERT INTO api_keys (
|
|
21048
|
+
id, name, key_hash, key_prefix, last_five, user_id, created_at,
|
|
21049
|
+
platform_key_id, scope, source, replica_active, replica_updated_at
|
|
21050
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'standard_agents', 1, ?)`,
|
|
21051
|
+
`platform:${key.id}`,
|
|
21052
|
+
name,
|
|
21053
|
+
key.key_hash,
|
|
21054
|
+
key.key_prefix,
|
|
21055
|
+
lastFive,
|
|
21056
|
+
userId,
|
|
21057
|
+
key.created_at ?? now,
|
|
21058
|
+
key.id,
|
|
21059
|
+
key.scope ?? null,
|
|
21060
|
+
now
|
|
21061
|
+
);
|
|
21062
|
+
}
|
|
20733
21063
|
// ============================================================
|
|
20734
21064
|
// Session Methods
|
|
20735
21065
|
// ============================================================
|
|
@@ -20758,8 +21088,13 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
20758
21088
|
await this.ensureMigrated();
|
|
20759
21089
|
const now = Math.floor(Date.now() / 1e3);
|
|
20760
21090
|
const cursor = await this.ctx.storage.sql.exec(
|
|
20761
|
-
`SELECT user_id, expires_at
|
|
20762
|
-
|
|
21091
|
+
`SELECT sessions.user_id, sessions.expires_at
|
|
21092
|
+
FROM sessions
|
|
21093
|
+
JOIN users ON users.id = sessions.user_id
|
|
21094
|
+
WHERE sessions.token_hash = ?
|
|
21095
|
+
AND sessions.expires_at > ?
|
|
21096
|
+
AND users.deleted_at IS NULL
|
|
21097
|
+
AND users.replica_active != 0`,
|
|
20763
21098
|
tokenHash,
|
|
20764
21099
|
now
|
|
20765
21100
|
);
|
|
@@ -20816,14 +21151,23 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
20816
21151
|
*/
|
|
20817
21152
|
async validateApiKey(keyHash) {
|
|
20818
21153
|
await this.ensureMigrated();
|
|
20819
|
-
const cursor = await this.ctx.storage.sql.exec(
|
|
21154
|
+
const cursor = await this.ctx.storage.sql.exec(
|
|
21155
|
+
`SELECT api_keys.id, api_keys.user_id
|
|
21156
|
+
FROM api_keys
|
|
21157
|
+
JOIN users ON users.id = api_keys.user_id
|
|
21158
|
+
WHERE api_keys.key_hash = ?
|
|
21159
|
+
AND api_keys.replica_active != 0
|
|
21160
|
+
AND users.deleted_at IS NULL
|
|
21161
|
+
AND users.replica_active != 0`,
|
|
21162
|
+
keyHash
|
|
21163
|
+
);
|
|
20820
21164
|
const rows = cursor.toArray();
|
|
20821
21165
|
if (rows.length === 0) {
|
|
20822
21166
|
return null;
|
|
20823
21167
|
}
|
|
20824
21168
|
const now = Math.floor(Date.now() / 1e3);
|
|
20825
21169
|
await this.ctx.storage.sql.exec(
|
|
20826
|
-
`UPDATE api_keys SET last_used_at = ? WHERE key_hash =
|
|
21170
|
+
`UPDATE api_keys SET last_used_at = ? WHERE key_hash = ? AND replica_active != 0`,
|
|
20827
21171
|
now,
|
|
20828
21172
|
keyHash
|
|
20829
21173
|
);
|
|
@@ -20835,8 +21179,10 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
20835
21179
|
async listApiKeys(userId) {
|
|
20836
21180
|
await this.ensureMigrated();
|
|
20837
21181
|
const cursor = await this.ctx.storage.sql.exec(
|
|
20838
|
-
`SELECT id, name, key_prefix, last_five, created_at, last_used_at
|
|
20839
|
-
FROM api_keys
|
|
21182
|
+
`SELECT id, name, key_prefix, last_five, source, created_at, last_used_at
|
|
21183
|
+
FROM api_keys
|
|
21184
|
+
WHERE user_id = ? AND replica_active != 0
|
|
21185
|
+
ORDER BY created_at DESC`,
|
|
20840
21186
|
userId
|
|
20841
21187
|
);
|
|
20842
21188
|
return cursor.toArray();
|