@kky42/pievo-server 2.4.11 → 2.4.13
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/.output/nitro.json +1 -1
- package/.output/public/assets/SignIn-CDCdDD1a.js +1 -0
- package/.output/public/assets/{ui-s5IMg6RF.js → actionUi-D8m1FDHO.js} +1 -1
- package/.output/public/assets/app-PPhgN9iN.css +2 -0
- package/.output/public/assets/index-c0XPWXuz.js +10 -0
- package/.output/public/assets/loops._loopId-D7i_BGiE.js +67 -0
- package/.output/public/assets/loops._loopId_.runs._runId-CksSrEY7.js +3 -0
- package/.output/public/assets/{preload-helper-Bs7oCAsw.js → preload-helper-Zcmr31XG.js} +3 -3
- package/.output/public/assets/routes-79D939J4.js +1 -0
- package/.output/public/assets/routes-BYgl3Tmv.js +1 -0
- package/.output/server/_libs/@tanstack/react-router+[...].mjs +1 -1
- package/.output/server/_ssr/{MachinesModal-BhRw7oOx.mjs → MachinesModal-DBIP648Z.mjs} +18 -57
- package/.output/server/_ssr/{SignIn-BhoZIOUp.mjs → SignIn-Bp3uWaCQ.mjs} +3 -3
- package/.output/server/_ssr/{ui-DGz-q9MT.mjs → actionUi-C_WswNb1.mjs} +113 -2
- package/.output/server/_ssr/{artifactFiles-ChuJ4PzC.mjs → artifactFiles-BvVmixrs.mjs} +3 -3
- package/.output/server/_ssr/{artifactKind-DXumOv7c.mjs → artifactKind-DRCbYHZU.mjs} +6 -14
- package/.output/server/_ssr/artifacts-CzDJLaa6.mjs +2 -0
- package/.output/server/_ssr/{auth-LwPp_iim.mjs → auth-BV0MxVdo.mjs} +44 -124
- package/.output/server/_ssr/{SocialLinks-DVCLmql0.mjs → auth-client-RTpMpT4L.mjs} +143 -109
- package/.output/server/_ssr/boot-CsLXrLEa.mjs +2 -0
- package/.output/server/_ssr/{boot-BIxtZHU-.mjs → boot-U-CFI65B.mjs} +58 -331
- package/.output/server/_ssr/{bun-sqlite-dialect-BW9W1_Ps-CHMDkKqA.mjs → bun-sqlite-dialect-BW9W1_Ps-D9KUBJ-L.mjs} +2 -2
- package/.output/server/_ssr/{d1-sqlite-dialect-BLC8LXE6-DYum6qky.mjs → d1-sqlite-dialect-BLC8LXE6-CVHRzH1n.mjs} +2 -2
- package/.output/server/_ssr/db-BTX-xORB.mjs +2 -0
- package/.output/server/_ssr/{dist-bWqs5sTy.mjs → dist-D7UDVZ5G.mjs} +2 -2
- package/.output/server/_ssr/{factory-pBwrjVTI.mjs → factory-DYFx1fg-.mjs} +2 -2
- package/.output/server/_ssr/{kysely-adapter-DMf5pFTf.mjs → kysely-adapter-CwdB7yBh.mjs} +1 -1
- package/.output/server/_ssr/logger-CwiKSMp6.mjs +2 -0
- package/.output/server/_ssr/{loopApi-Im6JSK0p.mjs → loopApi-C4nN0msL.mjs} +29 -90
- package/.output/server/_ssr/{loopProjection-DIpGR6rp.mjs → loopProjection-DMSNHux6.mjs} +2 -2
- package/.output/server/_ssr/{loops._loopId-B5iPseDG.mjs → loops._loopId-Q4pRYPip.mjs} +19 -45
- package/.output/server/_ssr/{loops._loopId_.runs._runId-DVtG0xYb.mjs → loops._loopId_.runs._runId-DNXVmCt5.mjs} +6 -13
- package/.output/server/_ssr/{loops._loopId_.runs._runId-BA-P6sGA.mjs → loops._loopId_.runs._runId-ty3AhkOi.mjs} +31 -23
- package/.output/server/_ssr/{machineFns-Bb9KNXun.mjs → machineFns-CkNms3zA.mjs} +41 -108
- package/.output/server/_ssr/{node-sqlite-dialect-Dho9YjXb.mjs → node-sqlite-dialect-B_g92oFK.mjs} +2 -2
- package/.output/server/_ssr/{router-DPz3uoUr.mjs → router-DCNZ2xLm.mjs} +26 -40
- package/.output/server/_ssr/routes-8JSF7bX_.mjs +27 -0
- package/.output/server/_ssr/{routes-FO0MFfYK.mjs → routes-B3fulW5I.mjs} +4 -9
- package/.output/server/_ssr/routes-BaanDO41.mjs +367 -0
- package/.output/server/_ssr/runDiff-D7CxAgYL.mjs +2 -0
- package/.output/server/_ssr/ssr.mjs +28 -88
- package/.output/server/_ssr/store-DSNbXxqz.mjs +2 -0
- package/.output/server/_ssr/tokens-DzUv7CCp.mjs +2 -0
- package/.output/server/_tanstack-start-manifest_v-DkmxsHDK.mjs +52 -0
- package/.output/server/drizzle/0002_remove_teams.sql +15 -0
- package/.output/server/drizzle/meta/_journal.json +7 -0
- package/.output/server/index.mjs +49 -98
- package/drizzle/0002_remove_teams.sql +15 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +2 -2
- package/.output/public/assets/MachinesModal-ByHejech.js +0 -1
- package/.output/public/assets/SignIn-Cf4HOpdF.js +0 -1
- package/.output/public/assets/actionUi-yYVvoOTn.js +0 -1
- package/.output/public/assets/app-IrlFuBXa.css +0 -2
- package/.output/public/assets/index-ia26HsP1.js +0 -10
- package/.output/public/assets/invite._token-B0EKVyrU.js +0 -1
- package/.output/public/assets/invite._token-tDfe3p0Z.js +0 -1
- package/.output/public/assets/lifecycleUi-C0DaC6NM.js +0 -1
- package/.output/public/assets/loops._loopId-CuYq_XgT.js +0 -67
- package/.output/public/assets/loops._loopId_.runs._runId-mOaF51Qu.js +0 -3
- package/.output/public/assets/routes-4N6mrQK_.js +0 -1
- package/.output/public/assets/routes-Dbl_3lt_.js +0 -1
- package/.output/public/assets/t._teamId-BVsl0EGm.js +0 -1
- package/.output/public/assets/t._teamId-CAUjvMZ6.js +0 -1
- package/.output/server/_ssr/DashboardView-BMHMrOfC.mjs +0 -842
- package/.output/server/_ssr/actionUi-Cf6DuEC2.mjs +0 -119
- package/.output/server/_ssr/artifacts-DOLHJHcd.mjs +0 -2
- package/.output/server/_ssr/boot-D8cj4uZj.mjs +0 -2
- package/.output/server/_ssr/db-BphSJs66.mjs +0 -2
- package/.output/server/_ssr/invite._token-CPSvdDox.mjs +0 -27
- package/.output/server/_ssr/invite._token-CRBsTSTZ.mjs +0 -84
- package/.output/server/_ssr/invite._token-CaTLt92a.mjs +0 -20
- package/.output/server/_ssr/lifecycleUi-DauKavgx.mjs +0 -50
- package/.output/server/_ssr/logger-EinA2J6y.mjs +0 -2
- package/.output/server/_ssr/routes-B9zD2h4Y.mjs +0 -26
- package/.output/server/_ssr/routes-BuILEmHs.mjs +0 -39
- package/.output/server/_ssr/runDiff-BLdot9mi.mjs +0 -2
- package/.output/server/_ssr/store-CFCp_ggC.mjs +0 -2
- package/.output/server/_ssr/t._teamId-1t5wOXrV.mjs +0 -43
- package/.output/server/_ssr/t._teamId-A37pQ8Vp.mjs +0 -32
- package/.output/server/_ssr/t._teamId-D1BTwhWf.mjs +0 -31
- package/.output/server/_ssr/teamCookie-B7hLOIie.mjs +0 -10
- package/.output/server/_ssr/teamFns-DfqtuBW2.mjs +0 -451
- package/.output/server/_ssr/teamFns-cI_tsiCv.mjs +0 -32
- package/.output/server/_ssr/tokens-CUz4LDLm.mjs +0 -2
- package/.output/server/_tanstack-start-manifest_v-CojB4Veh.mjs +0 -86
|
@@ -11,7 +11,7 @@ import { fileURLToPath } from "node:url";
|
|
|
11
11
|
import path from "node:path";
|
|
12
12
|
import os from "node:os";
|
|
13
13
|
import fs$1 from "node:fs/promises";
|
|
14
|
-
//#region node_modules/.nitro/vite/services/ssr/assets/boot-
|
|
14
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/boot-U-CFI65B.js
|
|
15
15
|
var import_pino = /* @__PURE__ */ __toESM(require_pino());
|
|
16
16
|
var import_pino_pretty = /* @__PURE__ */ __toESM(require_pino_pretty());
|
|
17
17
|
function defineErrorCodes(codes) {
|
|
@@ -1433,7 +1433,6 @@ function coerceCodingAgent(value) {
|
|
|
1433
1433
|
var machines = pgTable("machines", {
|
|
1434
1434
|
id: text("id").primaryKey(),
|
|
1435
1435
|
userId: text("user_id").notNull(),
|
|
1436
|
-
teamId: text("team_id").notNull(),
|
|
1437
1436
|
name: text("name").notNull(),
|
|
1438
1437
|
hostname: text("hostname"),
|
|
1439
1438
|
platform: text("platform"),
|
|
@@ -1445,18 +1444,17 @@ var machines = pgTable("machines", {
|
|
|
1445
1444
|
/**
|
|
1446
1445
|
* Plaintext device token. Stored so the UI can re-show the connect command
|
|
1447
1446
|
* anytime (MVP convenience — deviates from "store only the hash"; acceptable
|
|
1448
|
-
* for a self-hosted
|
|
1447
|
+
* for a self-hosted control plane where the DB is already the trust root).
|
|
1449
1448
|
*/
|
|
1450
1449
|
token: text("token"),
|
|
1451
1450
|
roots: jsonb("roots").$type(),
|
|
1452
1451
|
lastSeen: text("last_seen"),
|
|
1453
1452
|
online: boolean("online").notNull().default(false),
|
|
1454
1453
|
createdAt: text("created_at").notNull()
|
|
1455
|
-
}, (t) => [index("machines_user_idx").on(t.userId)
|
|
1454
|
+
}, (t) => [index("machines_user_idx").on(t.userId)]);
|
|
1456
1455
|
var loops = pgTable("loops", {
|
|
1457
1456
|
id: text("id").primaryKey(),
|
|
1458
1457
|
userId: text("user_id").notNull(),
|
|
1459
|
-
teamId: text("team_id").notNull(),
|
|
1460
1458
|
/** Execution machine (set at creation; no cross-machine fallback). */
|
|
1461
1459
|
machineId: text("machine_id").notNull(),
|
|
1462
1460
|
name: text("name").notNull(),
|
|
@@ -1498,7 +1496,6 @@ var loops = pgTable("loops", {
|
|
|
1498
1496
|
updatedAt: text("updated_at").notNull()
|
|
1499
1497
|
}, (t) => [
|
|
1500
1498
|
index("loops_user_idx").on(t.userId),
|
|
1501
|
-
index("loops_team_idx").on(t.teamId),
|
|
1502
1499
|
index("loops_machine_idx").on(t.machineId),
|
|
1503
1500
|
index("delete_requested_loops").on(t.deleteRequestedAt).where(sql`${t.deleteRequestedAt} IS NOT NULL`),
|
|
1504
1501
|
check("loops_agent_check", sql`${t.agent} IN ('claude-code', 'codex', 'pi')`),
|
|
@@ -1611,38 +1608,9 @@ var terminalReportIncidents = pgTable("terminal_report_incidents", {
|
|
|
1611
1608
|
var connectKeys = pgTable("connect_keys", {
|
|
1612
1609
|
machineId: text("machine_id").primaryKey(),
|
|
1613
1610
|
userId: text("user_id").notNull(),
|
|
1614
|
-
teamId: text("team_id").notNull(),
|
|
1615
1611
|
/** Mint time (ISO) — drives the TTL. */
|
|
1616
1612
|
mintedAt: text("minted_at").notNull()
|
|
1617
1613
|
});
|
|
1618
|
-
var teams = pgTable("teams", {
|
|
1619
|
-
id: text("id").primaryKey(),
|
|
1620
|
-
name: text("name").notNull(),
|
|
1621
|
-
ownerUserId: text("owner_user_id"),
|
|
1622
|
-
createdAt: text("created_at").notNull()
|
|
1623
|
-
});
|
|
1624
|
-
var teamMembers = pgTable("team_members", {
|
|
1625
|
-
id: text("id").primaryKey(),
|
|
1626
|
-
teamId: text("team_id").notNull(),
|
|
1627
|
-
userId: text("user_id").notNull(),
|
|
1628
|
-
role: text("role", { enum: ["owner", "member"] }).notNull().default("member"),
|
|
1629
|
-
createdAt: text("created_at").notNull()
|
|
1630
|
-
}, (t) => [
|
|
1631
|
-
index("team_members_team_idx").on(t.teamId),
|
|
1632
|
-
index("team_members_user_idx").on(t.userId),
|
|
1633
|
-
check("team_members_role_check", sql`${t.role} IN ('owner', 'member')`)
|
|
1634
|
-
]);
|
|
1635
|
-
var teamInvites = pgTable("team_invites", {
|
|
1636
|
-
token: text("token").primaryKey(),
|
|
1637
|
-
teamId: text("team_id").notNull(),
|
|
1638
|
-
role: text("role", { enum: ["owner", "member"] }).notNull().default("member"),
|
|
1639
|
-
invitedByUserId: text("invited_by_user_id").notNull(),
|
|
1640
|
-
expiresAt: text("expires_at").notNull(),
|
|
1641
|
-
/** Single-use stamp: set on redeem so the same link can't be reused. */
|
|
1642
|
-
redeemedAt: text("redeemed_at"),
|
|
1643
|
-
redeemedByUserId: text("redeemed_by_user_id"),
|
|
1644
|
-
createdAt: text("created_at").notNull()
|
|
1645
|
-
}, (t) => [index("team_invites_team_idx").on(t.teamId), check("team_invites_role_check", sql`${t.role} IN ('owner', 'member')`)]);
|
|
1646
1614
|
/**
|
|
1647
1615
|
* One content-addressed blob (deduped across every loop/run). The bytes live in
|
|
1648
1616
|
* the byte store under the hash; this row records verified byte presence and size.
|
|
@@ -1767,9 +1735,6 @@ var schema = {
|
|
|
1767
1735
|
machines,
|
|
1768
1736
|
loops,
|
|
1769
1737
|
runs,
|
|
1770
|
-
teams,
|
|
1771
|
-
teamMembers,
|
|
1772
|
-
teamInvites,
|
|
1773
1738
|
blobs,
|
|
1774
1739
|
artifactFiles,
|
|
1775
1740
|
runSnapshots,
|
|
@@ -1881,6 +1846,19 @@ async function closeClient() {
|
|
|
1881
1846
|
} catch {}
|
|
1882
1847
|
}
|
|
1883
1848
|
/**
|
|
1849
|
+
* The GitHub login-gate condition, in one leaf module. `auth.ts` derives its
|
|
1850
|
+
* load-time `authEnabled` value from this, and server boot calls it before any
|
|
1851
|
+
* migration or scheduler work.
|
|
1852
|
+
*
|
|
1853
|
+
* The gate is ON exactly when a complete GitHub OAuth app is configured. Open
|
|
1854
|
+
* mode requires both values to be absent; a partial configuration fails closed.
|
|
1855
|
+
*/
|
|
1856
|
+
function loginGateEnabled() {
|
|
1857
|
+
const hasClientId = !!process.env.GITHUB_CLIENT_ID?.trim();
|
|
1858
|
+
if (hasClientId !== !!process.env.GITHUB_CLIENT_SECRET?.trim()) throw new Error("incomplete GitHub auth configuration: set both GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET, or unset both for open mode");
|
|
1859
|
+
return hasClientId;
|
|
1860
|
+
}
|
|
1861
|
+
/**
|
|
1884
1862
|
* Data-access layer over Drizzle — replaces c0's file-per-loop store. The API is
|
|
1885
1863
|
* function-style; persistence is relational (loops and runs are separate tables,
|
|
1886
1864
|
* and `owner: PeerRef` is gone → `userId` + `machineId`).
|
|
@@ -1916,13 +1894,11 @@ function runTimes(at = nowIso$1()) {
|
|
|
1916
1894
|
updatedAt: at
|
|
1917
1895
|
};
|
|
1918
1896
|
}
|
|
1919
|
-
async function listLoops(
|
|
1920
|
-
|
|
1921
|
-
return teamId ? await q.where(eq(loops.teamId, teamId)) : await q;
|
|
1897
|
+
async function listLoops() {
|
|
1898
|
+
return db.select().from(loops);
|
|
1922
1899
|
}
|
|
1923
|
-
async function
|
|
1924
|
-
|
|
1925
|
-
return Number(r?.n ?? 0);
|
|
1900
|
+
async function listLoopsForUser(userId) {
|
|
1901
|
+
return db.select().from(loops).where(eq(loops.userId, userId));
|
|
1926
1902
|
}
|
|
1927
1903
|
async function getLoop(id) {
|
|
1928
1904
|
return (await db.select().from(loops).where(eq(loops.id, id)))[0];
|
|
@@ -1950,7 +1926,12 @@ async function createLoop(input) {
|
|
|
1950
1926
|
updatedAt: ts
|
|
1951
1927
|
};
|
|
1952
1928
|
return db.transaction(async (tx) => {
|
|
1953
|
-
|
|
1929
|
+
const machine = (await tx.select({
|
|
1930
|
+
id: machines.id,
|
|
1931
|
+
userId: machines.userId
|
|
1932
|
+
}).from(machines).where(eq(machines.id, input.machineId)).for("key share"))[0];
|
|
1933
|
+
if (!machine) throw new Error(`machine ${input.machineId} does not exist`);
|
|
1934
|
+
if (machine.userId !== input.userId) throw new Error(`machine ${input.machineId} is owned by a different user`);
|
|
1954
1935
|
return (await tx.insert(loops).values(row).returning())[0];
|
|
1955
1936
|
});
|
|
1956
1937
|
}
|
|
@@ -2800,17 +2781,11 @@ async function expirePendingRun(runId, expected, at, maxLifetimeMs, message) {
|
|
|
2800
2781
|
}).where(and(eq(runs.id, runId), eq(runs.phase, "pending"), eq(runs.requestedBy, "system"), eq(runs.updatedAt, expected.updatedAt))).returning({ id: runs.id })).length > 0;
|
|
2801
2782
|
});
|
|
2802
2783
|
}
|
|
2803
|
-
async function listMachines(
|
|
2804
|
-
return
|
|
2784
|
+
async function listMachines() {
|
|
2785
|
+
return db.select().from(machines).orderBy(asc(machines.name), asc(machines.id));
|
|
2805
2786
|
}
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
* belongs to the team (join `machines.userId` → a `team_members` row for this
|
|
2809
|
-
* team). One machine therefore appears in every team its owner belongs to.
|
|
2810
|
-
* A user has at most one membership row per team, so no machine is duplicated.
|
|
2811
|
-
*/
|
|
2812
|
-
async function listMachinesForTeam(teamId) {
|
|
2813
|
-
return (await db.select({ m: machines }).from(machines).innerJoin(teamMembers, eq(machines.userId, teamMembers.userId)).where(eq(teamMembers.teamId, teamId)).orderBy(asc(machines.name), asc(machines.id))).map((r) => r.m);
|
|
2787
|
+
async function listMachinesForUser(userId) {
|
|
2788
|
+
return db.select().from(machines).where(eq(machines.userId, userId)).orderBy(asc(machines.name), asc(machines.id));
|
|
2814
2789
|
}
|
|
2815
2790
|
async function getMachine(id) {
|
|
2816
2791
|
return (await db.select().from(machines).where(eq(machines.id, id)))[0];
|
|
@@ -2826,16 +2801,18 @@ async function updateMachine(id, patch) {
|
|
|
2826
2801
|
return getMachine(id);
|
|
2827
2802
|
}
|
|
2828
2803
|
/** Atomically retire all loop authority, remove server-owned machine data, revoke
|
|
2829
|
-
* enrollment, and delete the machine.
|
|
2830
|
-
*
|
|
2831
|
-
async function forceDeleteMachine(id,
|
|
2804
|
+
* enrollment, and delete the machine. Auth-mode callers pass `ownerUserId` so
|
|
2805
|
+
* ownership is rechecked under the same lock as deletion; open/server callers omit it. */
|
|
2806
|
+
async function forceDeleteMachine(id, ownerUserId) {
|
|
2832
2807
|
return db.transaction(async (tx) => {
|
|
2833
|
-
|
|
2808
|
+
const machine = (await tx.select({
|
|
2809
|
+
id: machines.id,
|
|
2810
|
+
userId: machines.userId
|
|
2811
|
+
}).from(machines).where(eq(machines.id, id)).for("update"))[0];
|
|
2812
|
+
if (!machine) return { state: "not-found" };
|
|
2813
|
+
if (ownerUserId !== void 0 && machine.userId !== ownerUserId) return { state: "forbidden" };
|
|
2834
2814
|
const ownedLoops = await tx.select().from(loops).where(eq(loops.machineId, id)).for("update");
|
|
2835
|
-
if (
|
|
2836
|
-
const allowed = new Set(allowedTeamIds);
|
|
2837
|
-
if (ownedLoops.some((loop) => !allowed.has(loop.teamId))) return { state: "forbidden" };
|
|
2838
|
-
}
|
|
2815
|
+
if (ownerUserId !== void 0 && ownedLoops.some((loop) => loop.userId !== ownerUserId)) return { state: "forbidden" };
|
|
2839
2816
|
for (const loop of ownedLoops) if (!await forceDeleteLoopTx(tx, loop.id)) throw new Error(`failed to delete loop ${loop.id}`);
|
|
2840
2817
|
await tx.delete(connectKeys).where(eq(connectKeys.machineId, id));
|
|
2841
2818
|
await tx.delete(machines).where(eq(machines.id, id));
|
|
@@ -2851,215 +2828,6 @@ async function setMachineOnline(id, online) {
|
|
|
2851
2828
|
lastSeen: nowIso$1()
|
|
2852
2829
|
}).where(eq(machines.id, id));
|
|
2853
2830
|
}
|
|
2854
|
-
function teamIdForUser(userId) {
|
|
2855
|
-
return `team-${userId ?? "shared"}`;
|
|
2856
|
-
}
|
|
2857
|
-
var ensuredTeams = /* @__PURE__ */ new Set();
|
|
2858
|
-
/** Idempotently create a team (+ owner membership) if absent. The email-derived
|
|
2859
|
-
* `name` seeds only a new personal team, so later owner renames persist.
|
|
2860
|
-
* Memoized ⇒ at most one reconcile per team per process. The team insert +
|
|
2861
|
-
* membership insert are one atomic transaction. */
|
|
2862
|
-
async function ensureTeam(id, name, ownerUserId) {
|
|
2863
|
-
if (ensuredTeams.has(id)) return;
|
|
2864
|
-
const ts = nowIso$1();
|
|
2865
|
-
await db.transaction(async (tx) => {
|
|
2866
|
-
await tx.insert(teams).values({
|
|
2867
|
-
id,
|
|
2868
|
-
name,
|
|
2869
|
-
ownerUserId,
|
|
2870
|
-
createdAt: ts
|
|
2871
|
-
}).onConflictDoNothing();
|
|
2872
|
-
if (ownerUserId) await tx.insert(teamMembers).values({
|
|
2873
|
-
id: `${id}:${ownerUserId}`,
|
|
2874
|
-
teamId: id,
|
|
2875
|
-
userId: ownerUserId,
|
|
2876
|
-
role: "owner",
|
|
2877
|
-
createdAt: ts
|
|
2878
|
-
}).onConflictDoNothing();
|
|
2879
|
-
});
|
|
2880
|
-
ensuredTeams.add(id);
|
|
2881
|
-
}
|
|
2882
|
-
/** A fresh non-personal team id. Random (never `team-<userId>`, which is reserved
|
|
2883
|
-
* for the personal team the requestScope fallback depends on). */
|
|
2884
|
-
function newTeamId() {
|
|
2885
|
-
return `team-${randomUUID().slice(0, 12)}`;
|
|
2886
|
-
}
|
|
2887
|
-
function isPersonalTeam(team) {
|
|
2888
|
-
return !!team.ownerUserId && team.id === teamIdForUser(team.ownerUserId);
|
|
2889
|
-
}
|
|
2890
|
-
/** Create a non-personal team owned by `ownerUserId` (creator = owner in both
|
|
2891
|
-
* `teams.ownerUserId` and a `team_members` owner row), transactionally. */
|
|
2892
|
-
async function createTeam(name, ownerUserId) {
|
|
2893
|
-
const ts = nowIso$1();
|
|
2894
|
-
const id = newTeamId();
|
|
2895
|
-
return db.transaction(async (tx) => {
|
|
2896
|
-
const [team] = await tx.insert(teams).values({
|
|
2897
|
-
id,
|
|
2898
|
-
name,
|
|
2899
|
-
ownerUserId,
|
|
2900
|
-
createdAt: ts
|
|
2901
|
-
}).returning();
|
|
2902
|
-
await tx.insert(teamMembers).values({
|
|
2903
|
-
id: `${id}:${ownerUserId}`,
|
|
2904
|
-
teamId: id,
|
|
2905
|
-
userId: ownerUserId,
|
|
2906
|
-
role: "owner",
|
|
2907
|
-
createdAt: ts
|
|
2908
|
-
});
|
|
2909
|
-
return team;
|
|
2910
|
-
});
|
|
2911
|
-
}
|
|
2912
|
-
async function renameTeam(teamId, name) {
|
|
2913
|
-
await db.update(teams).set({ name }).where(eq(teams.id, teamId));
|
|
2914
|
-
}
|
|
2915
|
-
async function getTeamMember(teamId, userId) {
|
|
2916
|
-
return (await db.select().from(teamMembers).where(and(eq(teamMembers.teamId, teamId), eq(teamMembers.userId, userId))))[0];
|
|
2917
|
-
}
|
|
2918
|
-
async function listTeamMembers(teamId) {
|
|
2919
|
-
return (await db.select({
|
|
2920
|
-
id: teamMembers.id,
|
|
2921
|
-
teamId: teamMembers.teamId,
|
|
2922
|
-
userId: teamMembers.userId,
|
|
2923
|
-
role: teamMembers.role,
|
|
2924
|
-
createdAt: teamMembers.createdAt,
|
|
2925
|
-
email: user.email,
|
|
2926
|
-
displayName: user.name
|
|
2927
|
-
}).from(teamMembers).leftJoin(user, eq(teamMembers.userId, user.id)).where(eq(teamMembers.teamId, teamId))).map((r) => ({
|
|
2928
|
-
...r,
|
|
2929
|
-
email: r.email ?? null,
|
|
2930
|
-
displayName: r.displayName ?? null
|
|
2931
|
-
})).sort((a, b) => a.role === b.role ? a.createdAt < b.createdAt ? -1 : 1 : a.role === "owner" ? -1 : 1);
|
|
2932
|
-
}
|
|
2933
|
-
async function userByEmail(email) {
|
|
2934
|
-
const r = (await db.select({
|
|
2935
|
-
id: user.id,
|
|
2936
|
-
email: user.email
|
|
2937
|
-
}).from(user).where(sql`lower(${user.email}) = lower(${email})`))[0];
|
|
2938
|
-
return r ? {
|
|
2939
|
-
id: r.id,
|
|
2940
|
-
email: r.email
|
|
2941
|
-
} : void 0;
|
|
2942
|
-
}
|
|
2943
|
-
/** Add a member (idempotent — a re-add is a no-op, not a duplicate row). */
|
|
2944
|
-
async function addTeamMember(teamId, userId, role) {
|
|
2945
|
-
await db.insert(teamMembers).values({
|
|
2946
|
-
id: `${teamId}:${userId}`,
|
|
2947
|
-
teamId,
|
|
2948
|
-
userId,
|
|
2949
|
-
role,
|
|
2950
|
-
createdAt: nowIso$1()
|
|
2951
|
-
}).onConflictDoNothing();
|
|
2952
|
-
}
|
|
2953
|
-
/**
|
|
2954
|
-
* Remove a member, but REFUSE if they are the team's LAST owner (the ≥1-owner
|
|
2955
|
-
* invariant, checked in the SAME transaction as the delete so two concurrent
|
|
2956
|
-
* self-removals can't both win and strand a memberless team). Returns:
|
|
2957
|
-
* - `not-member` — no membership row;
|
|
2958
|
-
* - `last-owner` — refused (they are the sole owner; transfer/promote first);
|
|
2959
|
-
* - `ok` — removed.
|
|
2960
|
-
*/
|
|
2961
|
-
async function removeTeamMemberGuarded(teamId, userId) {
|
|
2962
|
-
return db.transaction(async (tx) => {
|
|
2963
|
-
const m = (await tx.select().from(teamMembers).where(and(eq(teamMembers.teamId, teamId), eq(teamMembers.userId, userId))))[0];
|
|
2964
|
-
if (!m) return "not-member";
|
|
2965
|
-
if (m.role === "owner") {
|
|
2966
|
-
if ((await tx.select({ id: teamMembers.id }).from(teamMembers).where(and(eq(teamMembers.teamId, teamId), eq(teamMembers.role, "owner"))).for("update")).length <= 1) return "last-owner";
|
|
2967
|
-
}
|
|
2968
|
-
await tx.delete(teamMembers).where(and(eq(teamMembers.teamId, teamId), eq(teamMembers.userId, userId)));
|
|
2969
|
-
return "ok";
|
|
2970
|
-
});
|
|
2971
|
-
}
|
|
2972
|
-
/**
|
|
2973
|
-
* Change a member's role, guarding the last-owner invariant transactionally: a
|
|
2974
|
-
* demote owner→member that would zero the owner set is refused. Returns
|
|
2975
|
-
* `not-member` / `last-owner` / `ok`. A no-op (same role) is `ok`.
|
|
2976
|
-
*/
|
|
2977
|
-
async function setTeamMemberRoleGuarded(teamId, userId, role) {
|
|
2978
|
-
return db.transaction(async (tx) => {
|
|
2979
|
-
const m = (await tx.select().from(teamMembers).where(and(eq(teamMembers.teamId, teamId), eq(teamMembers.userId, userId))))[0];
|
|
2980
|
-
if (!m) return "not-member";
|
|
2981
|
-
if (m.role === "owner" && role === "member") {
|
|
2982
|
-
if ((await tx.select({ id: teamMembers.id }).from(teamMembers).where(and(eq(teamMembers.teamId, teamId), eq(teamMembers.role, "owner"))).for("update")).length <= 1) return "last-owner";
|
|
2983
|
-
}
|
|
2984
|
-
await tx.update(teamMembers).set({ role }).where(and(eq(teamMembers.teamId, teamId), eq(teamMembers.userId, userId)));
|
|
2985
|
-
return "ok";
|
|
2986
|
-
});
|
|
2987
|
-
}
|
|
2988
|
-
/**
|
|
2989
|
-
* Delete a team and its dependents, transactionally. The CALLER enforces the
|
|
2990
|
-
* policy guards first (personal-team undeletable; blocked while the team owns loops).
|
|
2991
|
-
* The transaction rechecks the loop count and aborts (`has-loops`) if one exists,
|
|
2992
|
-
* closing the check-then-cascade gap where a loop created between the caller's
|
|
2993
|
-
* guard and here would be orphaned at a now-deleted team. On success we cascade
|
|
2994
|
-
* the team's own resources: pending invites, memberships, and reassign
|
|
2995
|
-
* every machine whose cosmetic home-team was this team back to its owner's
|
|
2996
|
-
* personal team (machines are user-owned; the team pointer is only a home hint).
|
|
2997
|
-
*/
|
|
2998
|
-
async function deleteTeamCascade(teamId) {
|
|
2999
|
-
const outcome = await db.transaction(async (tx) => {
|
|
3000
|
-
if (Number((await tx.select({ n: sql`count(*)` }).from(loops).where(eq(loops.teamId, teamId)))[0]?.n ?? 0) > 0) return "has-loops";
|
|
3001
|
-
const homed = await tx.select().from(machines).where(eq(machines.teamId, teamId));
|
|
3002
|
-
for (const m of homed) await tx.update(machines).set({ teamId: teamIdForUser(m.userId) }).where(eq(machines.id, m.id));
|
|
3003
|
-
await tx.delete(teamInvites).where(eq(teamInvites.teamId, teamId));
|
|
3004
|
-
await tx.delete(teamMembers).where(eq(teamMembers.teamId, teamId));
|
|
3005
|
-
await tx.delete(teams).where(eq(teams.id, teamId));
|
|
3006
|
-
return "ok";
|
|
3007
|
-
});
|
|
3008
|
-
if (outcome === "ok") ensuredTeams.delete(teamId);
|
|
3009
|
-
return outcome;
|
|
3010
|
-
}
|
|
3011
|
-
async function createInvite(input) {
|
|
3012
|
-
return (await db.insert(teamInvites).values({
|
|
3013
|
-
...input,
|
|
3014
|
-
createdAt: nowIso$1()
|
|
3015
|
-
}).returning())[0];
|
|
3016
|
-
}
|
|
3017
|
-
async function getInvite(token) {
|
|
3018
|
-
return (await db.select().from(teamInvites).where(eq(teamInvites.token, token)))[0];
|
|
3019
|
-
}
|
|
3020
|
-
async function listPendingInvites(teamId) {
|
|
3021
|
-
const now = nowIso$1();
|
|
3022
|
-
return db.select().from(teamInvites).where(and(eq(teamInvites.teamId, teamId), isNull(teamInvites.redeemedAt), gt(teamInvites.expiresAt, now))).orderBy(desc(teamInvites.createdAt));
|
|
3023
|
-
}
|
|
3024
|
-
/**
|
|
3025
|
-
* Atomically redeem a single-use invite: in ONE transaction, stamp
|
|
3026
|
-
* `redeemedAt`/`redeemedByUserId` ONLY if the invite is still unredeemed and,
|
|
3027
|
-
* when this call won the stamp, grant the membership in the SAME transaction so
|
|
3028
|
-
* the two commit together (a crash between them can't burn the link without
|
|
3029
|
-
* granting membership). The `redeemed_at IS NULL` guard makes the stamp the
|
|
3030
|
-
* single-use chokepoint, so two concurrent redeems can't both add a member.
|
|
3031
|
-
* Pass `grant: null` for an already-member redeem (still burns the link, no
|
|
3032
|
-
* double-add / no role change). Returns false when the invite was already spent
|
|
3033
|
-
* (a losing race, or a stale re-redeem).
|
|
3034
|
-
*/
|
|
3035
|
-
async function redeemInviteAtomic(token, userId, grant) {
|
|
3036
|
-
return db.transaction(async (tx) => {
|
|
3037
|
-
if ((await tx.update(teamInvites).set({
|
|
3038
|
-
redeemedAt: nowIso$1(),
|
|
3039
|
-
redeemedByUserId: userId
|
|
3040
|
-
}).where(and(eq(teamInvites.token, token), isNull(teamInvites.redeemedAt))).returning({ token: teamInvites.token })).length === 0) return false;
|
|
3041
|
-
if (grant) await tx.insert(teamMembers).values({
|
|
3042
|
-
id: `${grant.teamId}:${userId}`,
|
|
3043
|
-
teamId: grant.teamId,
|
|
3044
|
-
userId,
|
|
3045
|
-
role: grant.role,
|
|
3046
|
-
createdAt: nowIso$1()
|
|
3047
|
-
}).onConflictDoNothing();
|
|
3048
|
-
return true;
|
|
3049
|
-
});
|
|
3050
|
-
}
|
|
3051
|
-
async function deleteInvite(token) {
|
|
3052
|
-
await db.delete(teamInvites).where(eq(teamInvites.token, token));
|
|
3053
|
-
}
|
|
3054
|
-
async function getTeam(id) {
|
|
3055
|
-
return (await db.select().from(teams).where(eq(teams.id, id)))[0];
|
|
3056
|
-
}
|
|
3057
|
-
async function listTeamsForUser(userId) {
|
|
3058
|
-
return (await db.select({ t: teams }).from(teamMembers).innerJoin(teams, eq(teamMembers.teamId, teams.id)).where(eq(teamMembers.userId, userId)).orderBy(desc(teams.createdAt))).map((r) => r.t);
|
|
3059
|
-
}
|
|
3060
|
-
async function isTeamMember(teamId, userId) {
|
|
3061
|
-
return !!(await db.select({ id: teamMembers.id }).from(teamMembers).where(and(eq(teamMembers.teamId, teamId), eq(teamMembers.userId, userId))))[0];
|
|
3062
|
-
}
|
|
3063
2831
|
async function blobExists(hash) {
|
|
3064
2832
|
return !!(await db.select({ hash: blobs.hash }).from(blobs).where(eq(blobs.hash, hash)))[0];
|
|
3065
2833
|
}
|
|
@@ -3330,8 +3098,8 @@ function parseArtifactSyncBody(value) {
|
|
|
3330
3098
|
*
|
|
3331
3099
|
* Leases and connect-key bindings are DURABLE (run_leases / connect_keys
|
|
3332
3100
|
* tables): they must survive a deploy, or every restart 401s the in-flight
|
|
3333
|
-
* runs' callbacks/finalize and
|
|
3334
|
-
*
|
|
3101
|
+
* runs' callbacks/finalize and prevents a freshly connected machine from
|
|
3102
|
+
* enrolling under its owner. The 15-minute `new` idempotency window stays in-process;
|
|
3335
3103
|
* losing it only degrades retry deduplication, never persisted data.
|
|
3336
3104
|
*/
|
|
3337
3105
|
function sha256(s) {
|
|
@@ -3356,15 +3124,13 @@ var CONNECT_KEY_TTL_MS = 1440 * 60 * 1e3;
|
|
|
3356
3124
|
function connectKeyFresh(mintedAt, now) {
|
|
3357
3125
|
return now - Date.parse(mintedAt) <= CONNECT_KEY_TTL_MS;
|
|
3358
3126
|
}
|
|
3359
|
-
/** Bind a freshly
|
|
3360
|
-
|
|
3361
|
-
async function rememberConnectKey(connectKey, intent) {
|
|
3127
|
+
/** Bind a freshly minted connect key to its owner and prune expired rows. */
|
|
3128
|
+
async function rememberConnectKey(connectKey, binding) {
|
|
3362
3129
|
const now = /* @__PURE__ */ new Date();
|
|
3363
3130
|
await db.delete(connectKeys).where(lt(connectKeys.mintedAt, (/* @__PURE__ */ new Date(now.getTime() - CONNECT_KEY_TTL_MS)).toISOString()));
|
|
3364
3131
|
const row = {
|
|
3365
3132
|
machineId: machineIdFromToken(connectKey),
|
|
3366
|
-
userId:
|
|
3367
|
-
teamId: intent.teamId,
|
|
3133
|
+
userId: binding.userId,
|
|
3368
3134
|
mintedAt: now.toISOString()
|
|
3369
3135
|
};
|
|
3370
3136
|
await db.insert(connectKeys).values(row).onConflictDoUpdate({
|
|
@@ -3372,19 +3138,11 @@ async function rememberConnectKey(connectKey, intent) {
|
|
|
3372
3138
|
set: row
|
|
3373
3139
|
});
|
|
3374
3140
|
}
|
|
3375
|
-
async function
|
|
3141
|
+
async function readConnectKeyBinding(connectKey, now = Date.now()) {
|
|
3376
3142
|
if (!connectKey) return void 0;
|
|
3377
3143
|
const row = (await db.select().from(connectKeys).where(eq(connectKeys.machineId, machineIdFromToken(connectKey))))[0];
|
|
3378
3144
|
if (!row || !connectKeyFresh(row.mintedAt, now)) return void 0;
|
|
3379
|
-
return {
|
|
3380
|
-
userId: row.userId,
|
|
3381
|
-
teamId: row.teamId
|
|
3382
|
-
};
|
|
3383
|
-
}
|
|
3384
|
-
async function getDeviceOwner(machineId, now = Date.now()) {
|
|
3385
|
-
const row = (await db.select().from(connectKeys).where(eq(connectKeys.machineId, machineId)))[0];
|
|
3386
|
-
if (!row || !connectKeyFresh(row.mintedAt, now)) return void 0;
|
|
3387
|
-
return row.userId;
|
|
3145
|
+
return { userId: row.userId };
|
|
3388
3146
|
}
|
|
3389
3147
|
/** How long a terminal-grace lease stays alive to accept one late wake-report.
|
|
3390
3148
|
* A laptop can sleep overnight or across a weekend before the daemon resumes. */
|
|
@@ -4636,8 +4394,8 @@ var configuredRunTimeoutMs = Number(process.env.PIEVO_RUN_TIMEOUT_MS || 20 * 6e4
|
|
|
4636
4394
|
var RUN_TIMEOUT_MS = Number.isFinite(configuredRunTimeoutMs) && configuredRunTimeoutMs > 0 ? configuredRunTimeoutMs : 20 * 6e4;
|
|
4637
4395
|
/** The ONLY keys an owner `editLoop` patch may touch. A key outside this set is
|
|
4638
4396
|
* rejected (400) rather than silently ignored, so a `--json` typo fails loudly
|
|
4639
|
-
* and identity/ownership columns (id/
|
|
4640
|
-
*
|
|
4397
|
+
* and identity/ownership columns (id/userId/machineId/timestamps) can never be
|
|
4398
|
+
* patched over the device-token edit surface. Exported for `cli.ts`
|
|
4641
4399
|
* (the `new`/`edit` verb help lists these keys). */
|
|
4642
4400
|
var EDITABLE_LOOP_FIELDS = LOOP_EDIT_FIELDS;
|
|
4643
4401
|
/** Formal `report --message` text. Provider finalText is stored separately;
|
|
@@ -4961,18 +4719,14 @@ var MachineGateway = class {
|
|
|
4961
4719
|
const { machineId } = auth;
|
|
4962
4720
|
let machine = auth.machine;
|
|
4963
4721
|
if (!machine) {
|
|
4964
|
-
const
|
|
4965
|
-
if (
|
|
4722
|
+
const binding = await readConnectKeyBinding(deviceToken);
|
|
4723
|
+
if (!binding) return {
|
|
4966
4724
|
status: 401,
|
|
4967
4725
|
body: { error: "unknown device token — connect this machine first" }
|
|
4968
4726
|
};
|
|
4969
|
-
const ownerId = owner;
|
|
4970
|
-
const teamId = teamIdForUser(ownerId);
|
|
4971
|
-
await ensureTeam(teamId, ownerId === "shared" ? "Shared Workspace" : "Personal Team", ownerId === "shared" ? null : ownerId);
|
|
4972
4727
|
machine = await createMachine({
|
|
4973
4728
|
id: machineId,
|
|
4974
|
-
userId:
|
|
4975
|
-
teamId,
|
|
4729
|
+
userId: binding.userId,
|
|
4976
4730
|
name: info?.host || `machine-${machineId.slice(2, 8)}`,
|
|
4977
4731
|
tokenHash: sha256(deviceToken),
|
|
4978
4732
|
token: deviceToken,
|
|
@@ -5120,7 +4874,7 @@ var MachineGateway = class {
|
|
|
5120
4874
|
status: 200,
|
|
5121
4875
|
body: {
|
|
5122
4876
|
registered: false,
|
|
5123
|
-
claimValid: await
|
|
4877
|
+
claimValid: await readConnectKeyBinding(deviceToken) !== void 0,
|
|
5124
4878
|
online: false,
|
|
5125
4879
|
name: null,
|
|
5126
4880
|
lastSeen: null,
|
|
@@ -5156,8 +4910,7 @@ var MachineGateway = class {
|
|
|
5156
4910
|
status: 400,
|
|
5157
4911
|
body: { error: "create body must be an object" }
|
|
5158
4912
|
};
|
|
5159
|
-
const
|
|
5160
|
-
const { claim, dryRun, idempotencyKey, ...rawConfig } = rawBody;
|
|
4913
|
+
const { dryRun, idempotencyKey, ...rawConfig } = body;
|
|
5161
4914
|
if (dryRun !== void 0 && typeof dryRun !== "boolean") return {
|
|
5162
4915
|
status: 400,
|
|
5163
4916
|
body: { error: "dryRun must be boolean when provided" }
|
|
@@ -5166,26 +4919,6 @@ var MachineGateway = class {
|
|
|
5166
4919
|
status: 400,
|
|
5167
4920
|
body: { error: "idempotencyKey is required and must be exactly 64 lowercase hex characters" }
|
|
5168
4921
|
};
|
|
5169
|
-
let intent = void 0;
|
|
5170
|
-
if (Object.prototype.hasOwnProperty.call(rawBody, "claim")) {
|
|
5171
|
-
if (typeof claim !== "string" || !isDeviceTokenShape(claim)) return {
|
|
5172
|
-
status: 400,
|
|
5173
|
-
body: { error: "claim must have the exact dk_<30 lowercase hex> shape" }
|
|
5174
|
-
};
|
|
5175
|
-
intent = await readClaimIntent(claim);
|
|
5176
|
-
if (!intent) return {
|
|
5177
|
-
status: 400,
|
|
5178
|
-
body: { error: "claim is unknown or expired" }
|
|
5179
|
-
};
|
|
5180
|
-
if (machine.userId !== intent.userId) return {
|
|
5181
|
-
status: 403,
|
|
5182
|
-
body: { error: "connect-key was minted by a different user" }
|
|
5183
|
-
};
|
|
5184
|
-
if (!await isTeamMember(intent.teamId, machine.userId)) return {
|
|
5185
|
-
status: 403,
|
|
5186
|
-
body: { error: "not authorized to create loops in that team" }
|
|
5187
|
-
};
|
|
5188
|
-
}
|
|
5189
4922
|
const validated = validateLoopCreate(rawConfig);
|
|
5190
4923
|
if (!validated.ok) return {
|
|
5191
4924
|
status: 400,
|
|
@@ -5213,10 +4946,8 @@ var MachineGateway = class {
|
|
|
5213
4946
|
text: `loop: ${existing.name}\nid: ${existing.id}\nreplayed: true`
|
|
5214
4947
|
}
|
|
5215
4948
|
};
|
|
5216
|
-
const teamId = intent?.teamId ?? machine.teamId;
|
|
5217
4949
|
const loop = await createLoop({
|
|
5218
4950
|
userId: machine.userId,
|
|
5219
|
-
teamId,
|
|
5220
4951
|
machineId,
|
|
5221
4952
|
...row
|
|
5222
4953
|
});
|
|
@@ -6664,11 +6395,6 @@ var CliGateway = class {
|
|
|
6664
6395
|
body: { error: "force delete confirmation required" }
|
|
6665
6396
|
};
|
|
6666
6397
|
const machine = await getMachine(machineId);
|
|
6667
|
-
const actor = machine?.userId;
|
|
6668
|
-
if (!loop.teamId || !actor || (await getTeamMember(loop.teamId, actor))?.role !== "owner") return {
|
|
6669
|
-
status: 403,
|
|
6670
|
-
body: { error: "only a team owner can force delete this loop" }
|
|
6671
|
-
};
|
|
6672
6398
|
const reachability = machinePresence(!!machine?.online, machine?.lastSeen ?? null);
|
|
6673
6399
|
if (!await this.forceDeleteLoop(loop.id)) return {
|
|
6674
6400
|
status: 409,
|
|
@@ -6679,7 +6405,7 @@ var CliGateway = class {
|
|
|
6679
6405
|
action: "force-delete",
|
|
6680
6406
|
loopId: loop.id,
|
|
6681
6407
|
machineId,
|
|
6682
|
-
actorUserId:
|
|
6408
|
+
actorUserId: loop.userId,
|
|
6683
6409
|
machineReachability: reachability
|
|
6684
6410
|
});
|
|
6685
6411
|
return {
|
|
@@ -6992,7 +6718,7 @@ var RUN_VERB_HELP = { report: {
|
|
|
6992
6718
|
} };
|
|
6993
6719
|
var DEVICE_VERB_HELP = {
|
|
6994
6720
|
new: {
|
|
6995
|
-
syntax: "new --json '<config>' [--dry-run]
|
|
6721
|
+
syntax: "new --json '<config>' [--dry-run]",
|
|
6996
6722
|
summary: `create a loop from the canonical envelope (keys: ${[...EDITABLE_LOOP_FIELDS].join(", ")}; agent required)`,
|
|
6997
6723
|
help: ["Run `pievo new --json '{\"name\":\"Daily check\",\"schedule\":{\"mode\":\"cron\",\"cron\":\"0 8 * * *\",\"timezone\":\"UTC\",\"overlap\":\"skip\"},\"workdir\":\"<path>\",\"agent\":\"claude-code\",\"prompt\":\"Check the project.\",\"statusDefinitions\":{\"keep\":\"result retained\",\"noChange\":\"nothing changed\",\"block\":\"owner input required\"}}'` to create a loop", "Run `pievo new --json '{...}' --dry-run` to validate without creating"]
|
|
6998
6724
|
},
|
|
@@ -7402,6 +7128,7 @@ function ensureServer() {
|
|
|
7402
7128
|
return p;
|
|
7403
7129
|
}
|
|
7404
7130
|
async function boot() {
|
|
7131
|
+
loginGateEnabled();
|
|
7405
7132
|
await runMigrations();
|
|
7406
7133
|
await repairTerminalRunLeases();
|
|
7407
7134
|
const abort = new AbortController();
|
|
@@ -7463,4 +7190,4 @@ async function getCliGateway() {
|
|
|
7463
7190
|
return (await ensureServer()).cliGateway;
|
|
7464
7191
|
}
|
|
7465
7192
|
//#endregion
|
|
7466
|
-
export {
|
|
7193
|
+
export { listLoopsForUser as $, getBaseURL as A, updateMachine as At, getRun as B, defu as C, sha256 as Ct, forceDeleteMachine as D, toKebabCase as Dt, forceDeleteLoop as E, stopLoop as Et, getHost as F, wildcardMatch as Ft, isOutdated as G, hasRunningRun as H, getLoop as I, isSafeUrlScheme as J, isProduction as K, getMachine as L, getCliGateway as M, validPollCurrentRun as Mt, getEnvVar as N, validPollWireId as Nt, getArtifactFile as O, tryDeleteLoop as Ot, getGateway as P, validateLoopEdit as Pt, listLoops as Q, getOrigin as R, db as S, scheduleFromLoop as St, env as T, statusDefinitionsFromLoop as Tt, isDevelopment as U, hasPendingRun as V, isDynamicBaseURLConfig as W, kAPIErrorHeaderSymbol as X, isTest as Y, listArtifacts as Z, countRuns as _, rememberConnectKey as _t, BetterAuthError as a, loginGateEnabled as at, createMachine as b, resolveBaseURL as bt, ENV as c, machinePresence as ct, POLL_HTTP_BODY_FIELDS as d, parseArtifactSyncBody as dt, listMachines as et, SYNC_BODY_CAP as f, pauseLoop as ft, computeRunDiff as g, reconciliationStatesForRuns as gt, capitalizeFirstLetter as h, recentLoopUsage as ht, BLOB_CAP as i, logger as it, getBooleanEnvVar as j, validOptionalPollString as jt, getArtifactSync as k, updateLoop as kt, MACHINE_BODY_CAP as l, mintDeviceToken as lt, betterFetch as m, readJsonBody as mt, APIError$1 as n, listRuns as nt, BetterCallError as o, loopsForMachine as ot, ValidationError$1 as p, readByteBody as pt, isRequestLike as q, BASE_ERROR_CODES as r, listRunsBefore as rt, CODING_AGENTS as s, machineIdFromToken as st, APIError as t, listMachinesForUser as tt, MIN_DAEMON_VERSION as u, normalizePathname as ut, createDefu as v, requestDeleteLoop as vt, ensureServer as w, startLoop as wt, daemonNeedsUpdate as x, safeRelPath as xt, createFetch as y, requestRunCancel as yt, getProtocol as z };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { n as DefaultQueryCompiler, o as CompiledQuery, s as sql$1 } from "./auth-
|
|
1
|
+
import { n as DefaultQueryCompiler, o as CompiledQuery, s as sql$1 } from "./auth-BV0MxVdo.mjs";
|
|
2
2
|
import { n as DEFAULT_MIGRATION_TABLE, t as DEFAULT_MIGRATION_LOCK_TABLE } from "./kysely-migration-tables-JkVUjPF_-bPAX9LR_.mjs";
|
|
3
|
-
//#region node_modules/.nitro/vite/services/ssr/assets/bun-sqlite-dialect-BW9W1_Ps-
|
|
3
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/bun-sqlite-dialect-BW9W1_Ps-D9KUBJ-L.js
|
|
4
4
|
var BunSqliteAdapter = class {
|
|
5
5
|
get supportsCreateIfNotExists() {
|
|
6
6
|
return true;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as SqliteQueryCompiler, i as SqliteAdapter } from "./auth-
|
|
1
|
+
import { a as SqliteQueryCompiler, i as SqliteAdapter } from "./auth-BV0MxVdo.mjs";
|
|
2
2
|
import { n as DEFAULT_MIGRATION_TABLE, t as DEFAULT_MIGRATION_LOCK_TABLE } from "./kysely-migration-tables-JkVUjPF_-bPAX9LR_.mjs";
|
|
3
|
-
//#region node_modules/.nitro/vite/services/ssr/assets/d1-sqlite-dialect-BLC8LXE6-
|
|
3
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/d1-sqlite-dialect-BLC8LXE6-CVHRzH1n.js
|
|
4
4
|
var D1SqliteAdapter = class extends SqliteAdapter {};
|
|
5
5
|
var D1SqliteDriver = class {
|
|
6
6
|
#config;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { _ as logger, o as createAdapterFactory } from "./factory-
|
|
2
|
-
//#region node_modules/.nitro/vite/services/ssr/assets/dist-
|
|
1
|
+
import { _ as logger, o as createAdapterFactory } from "./factory-DYFx1fg-.mjs";
|
|
2
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/dist-D7UDVZ5G.js
|
|
3
3
|
/**
|
|
4
4
|
* Case-insensitive in-memory comparison helpers.
|
|
5
5
|
* Used when evaluating where clauses in the memory adapter.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
//#region node_modules/.nitro/vite/services/ssr/assets/factory-
|
|
1
|
+
import { N as getEnvVar, T as env, a as BetterAuthError } from "./boot-U-CFI65B.mjs";
|
|
2
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/factory-DYFx1fg-.js
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
5
5
|
var __exportAll = (all, no_symbols) => {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { r as kyselyAdapter, t as createKyselyAdapter } from "./auth-
|
|
1
|
+
import { r as kyselyAdapter, t as createKyselyAdapter } from "./auth-BV0MxVdo.mjs";
|
|
2
2
|
export { createKyselyAdapter, kyselyAdapter };
|