@promptowl/contextnest-community 1.12.0 → 1.13.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/CONFIGURATION.md +2 -1
- package/README.md +1 -1
- package/dist/{chunk-3M7677XW.js → chunk-5QQ7WKAI.js} +14 -1
- package/dist/{chunk-JHIU6RZU.js → chunk-EG77SQHO.js} +34 -1
- package/dist/{chunk-XB7T3THE.js → chunk-PAIP5KHB.js} +17 -8
- package/dist/{chunk-F7EKYNXG.js → chunk-Q5NRCDD4.js} +884 -806
- package/dist/{chunk-ZMSU7BCC.js → chunk-ZQS5W45U.js} +1 -1
- package/dist/{client-YUOEVUFU.js → client-AAMF22YJ.js} +1 -1
- package/dist/{grants-service-PS5RMMEA.js → grants-service-FZD6QM6V.js} +2 -2
- package/dist/index.js +134 -60
- package/dist/{review-service-DPN26C47.js → review-service-Q3NDK5TX.js} +5 -5
- package/dist/{stewardship-service-7BHI2YXB.js → stewardship-service-B6L7UACX.js} +4 -2
- package/dist/{version-service-YQIIQ7FN.js → version-service-L52F4WVZ.js} +6 -4
- package/dist/web3/assets/{index-BiGiarBx.css → index-DcmDj50q.css} +1 -1
- package/dist/web3/assets/index-EGPZ6MAy.js +1023 -0
- package/dist/web3/index.html +2 -2
- package/package.json +1 -1
- package/dist/web3/assets/index-CUVRdYvH.js +0 -1026
|
@@ -6,9 +6,9 @@ import {
|
|
|
6
6
|
listGrants,
|
|
7
7
|
listUserGrants,
|
|
8
8
|
resolveNodeGrant
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-ZQS5W45U.js";
|
|
10
10
|
import "./chunk-GUNJTORH.js";
|
|
11
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-5QQ7WKAI.js";
|
|
12
12
|
import "./chunk-SLTQACJW.js";
|
|
13
13
|
export {
|
|
14
14
|
createGrant,
|
package/dist/index.js
CHANGED
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
seedDefaultEdgeTypes,
|
|
29
29
|
submitForReview,
|
|
30
30
|
verifySmtp
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-PAIP5KHB.js";
|
|
32
32
|
import {
|
|
33
33
|
createGrant,
|
|
34
34
|
deleteGrant,
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
listGrants,
|
|
38
38
|
listUserGrants,
|
|
39
39
|
resolveNodeGrant
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-ZQS5W45U.js";
|
|
41
41
|
import {
|
|
42
42
|
generateApiKey,
|
|
43
43
|
getKeyPrefix,
|
|
@@ -53,8 +53,9 @@ import {
|
|
|
53
53
|
getCurrentVersion,
|
|
54
54
|
getDisplayStatus,
|
|
55
55
|
getVersions,
|
|
56
|
-
setApprovedVersion
|
|
57
|
-
|
|
56
|
+
setApprovedVersion,
|
|
57
|
+
upsertVersion
|
|
58
|
+
} from "./chunk-EG77SQHO.js";
|
|
58
59
|
import {
|
|
59
60
|
addMember,
|
|
60
61
|
buildTitleMap,
|
|
@@ -63,7 +64,6 @@ import {
|
|
|
63
64
|
canUserAccess,
|
|
64
65
|
canUserApprove,
|
|
65
66
|
canUserEdit,
|
|
66
|
-
collabPermToRole,
|
|
67
67
|
createNest,
|
|
68
68
|
createStewardRecord,
|
|
69
69
|
createTeam,
|
|
@@ -98,6 +98,7 @@ import {
|
|
|
98
98
|
listSharedNests,
|
|
99
99
|
listStewards,
|
|
100
100
|
listTeamsForUser,
|
|
101
|
+
listVisibleNests,
|
|
101
102
|
loadAccessConfig,
|
|
102
103
|
loadGrantedSuperAdmins,
|
|
103
104
|
loadServerSettings,
|
|
@@ -111,12 +112,12 @@ import {
|
|
|
111
112
|
renameNest,
|
|
112
113
|
renameTeam,
|
|
113
114
|
replaceTeamRoster,
|
|
115
|
+
resolveGrantRoles,
|
|
114
116
|
resolveMemberIdentity,
|
|
115
117
|
resolveNestPath,
|
|
116
118
|
resolveNestPermission,
|
|
117
119
|
resolveStewardsForNode,
|
|
118
120
|
resolveStewardsWithFallback,
|
|
119
|
-
resolveTeamRolesForUser,
|
|
120
121
|
resolveUserRoles,
|
|
121
122
|
setAllowSelfApprove,
|
|
122
123
|
setStewardshipEnabled,
|
|
@@ -130,7 +131,7 @@ import {
|
|
|
130
131
|
updateMemberRole,
|
|
131
132
|
updateSteward,
|
|
132
133
|
validateLicense
|
|
133
|
-
} from "./chunk-
|
|
134
|
+
} from "./chunk-Q5NRCDD4.js";
|
|
134
135
|
import {
|
|
135
136
|
AppError,
|
|
136
137
|
ConflictError,
|
|
@@ -153,7 +154,7 @@ import {
|
|
|
153
154
|
initDb,
|
|
154
155
|
isEmailListish,
|
|
155
156
|
isEmailish
|
|
156
|
-
} from "./chunk-
|
|
157
|
+
} from "./chunk-5QQ7WKAI.js";
|
|
157
158
|
import {
|
|
158
159
|
ANON_EMAIL,
|
|
159
160
|
ANON_USER_ID
|
|
@@ -901,6 +902,9 @@ authRoutes.post("/register", async (c) => {
|
|
|
901
902
|
if (!body.email || !body.password) {
|
|
902
903
|
throw new ValidationError("email and password are required");
|
|
903
904
|
}
|
|
905
|
+
if (!isEmailish(body.email)) {
|
|
906
|
+
throw new ValidationError("Enter a valid email address.");
|
|
907
|
+
}
|
|
904
908
|
assertValidPassword(body.password);
|
|
905
909
|
const email = normalizeEmail(body.email);
|
|
906
910
|
const ip = clientIp(c);
|
|
@@ -1421,6 +1425,9 @@ authRoutes.delete("/users/:userId", async (c) => {
|
|
|
1421
1425
|
authRoutes.post("/invite", async (c) => {
|
|
1422
1426
|
const body = await c.req.json();
|
|
1423
1427
|
if (!body.email) throw new ValidationError("email is required");
|
|
1428
|
+
if (!isEmailish(body.email)) {
|
|
1429
|
+
throw new ValidationError("Enter a valid email address.");
|
|
1430
|
+
}
|
|
1424
1431
|
const email = normalizeEmail(body.email);
|
|
1425
1432
|
const callerId = await resolveCallerUserId(c);
|
|
1426
1433
|
if (!callerId) {
|
|
@@ -1758,7 +1765,7 @@ async function approveExternalEdit(input) {
|
|
|
1758
1765
|
const node = await storage.readDocument(input.documentId);
|
|
1759
1766
|
const versionNum = result.versionEntry.version;
|
|
1760
1767
|
const tags = node.frontmatter.tags || [];
|
|
1761
|
-
const { createVersion: createVersion2, setApprovedVersion: setApprovedVersion2 } = await import("./version-service-
|
|
1768
|
+
const { createVersion: createVersion2, setApprovedVersion: setApprovedVersion2 } = await import("./version-service-L52F4WVZ.js");
|
|
1762
1769
|
await createVersion2({
|
|
1763
1770
|
nestId: input.nestId,
|
|
1764
1771
|
nodeId: input.documentId,
|
|
@@ -2050,6 +2057,11 @@ async function listNodesForCaller(nestId, userId, filters = {}) {
|
|
|
2050
2057
|
async function listNodesForCallerByEmail(nestId, userEmail, filters = {}) {
|
|
2051
2058
|
return listNodesForCaller(nestId, await userIdFromEmail(userEmail), filters);
|
|
2052
2059
|
}
|
|
2060
|
+
async function actorAutoPublishes(nestId, userEmail) {
|
|
2061
|
+
if (!await nestAllowsSelfApprove(nestId)) return false;
|
|
2062
|
+
const roles = await resolveUserRoles(nestId, userEmail);
|
|
2063
|
+
return roles.includes("owner") || roles.includes("admin");
|
|
2064
|
+
}
|
|
2053
2065
|
async function createNode(nestId, input, userEmail) {
|
|
2054
2066
|
const { storage, versions: versionManager } = await engineCache.get(nestId);
|
|
2055
2067
|
const slug = slugify(input.title);
|
|
@@ -2084,8 +2096,9 @@ async function createNode(nestId, input, userEmail) {
|
|
|
2084
2096
|
tags.push(deptTag);
|
|
2085
2097
|
}
|
|
2086
2098
|
const hasStewards = await isStewardshipEnabled(nestId);
|
|
2087
|
-
const
|
|
2088
|
-
const
|
|
2099
|
+
const autoPublish = !hasStewards || await actorAutoPublishes(nestId, userEmail);
|
|
2100
|
+
const initialStatus = autoPublish ? "published" : "draft";
|
|
2101
|
+
const initialVersion = autoPublish ? 0 : 1;
|
|
2089
2102
|
let node = {
|
|
2090
2103
|
id,
|
|
2091
2104
|
filePath: "",
|
|
@@ -2109,7 +2122,7 @@ async function createNode(nestId, input, userEmail) {
|
|
|
2109
2122
|
await storage.writeDocument(id, serializeDocument(node));
|
|
2110
2123
|
await syncNodeTags(nestId, id, tags);
|
|
2111
2124
|
let savedVersion = 1;
|
|
2112
|
-
if (
|
|
2125
|
+
if (!autoPublish) {
|
|
2113
2126
|
try {
|
|
2114
2127
|
await versionManager.createVersion(node, userEmail);
|
|
2115
2128
|
} catch (err) {
|
|
@@ -2128,7 +2141,7 @@ async function createNode(nestId, input, userEmail) {
|
|
|
2128
2141
|
try {
|
|
2129
2142
|
const result = await safePublishDocument(storage, id, {
|
|
2130
2143
|
editedBy: userEmail,
|
|
2131
|
-
note: "Auto-published on create (no stewards configured)"
|
|
2144
|
+
note: hasStewards ? "Auto-published on create (owner/admin self-approve)" : "Auto-published on create (no stewards configured)"
|
|
2132
2145
|
});
|
|
2133
2146
|
savedVersion = result.node.frontmatter.version || 1;
|
|
2134
2147
|
await createVersion({
|
|
@@ -2337,6 +2350,7 @@ async function updateNode(nestId, nodeId, patch, userEmail) {
|
|
|
2337
2350
|
node = { ...node, frontmatter: { ...node.frontmatter, metadata } };
|
|
2338
2351
|
}
|
|
2339
2352
|
const hasStewards = await isStewardshipEnabled(nestId);
|
|
2353
|
+
const autoPublish = !hasStewards || await actorAutoPublishes(nestId, userEmail);
|
|
2340
2354
|
const currentTags = node.frontmatter.tags || [];
|
|
2341
2355
|
if (hasStewards && await getPendingReview(nestId, nodeId)) {
|
|
2342
2356
|
throw new LockedError(
|
|
@@ -2344,7 +2358,7 @@ async function updateNode(nestId, nodeId, patch, userEmail) {
|
|
|
2344
2358
|
);
|
|
2345
2359
|
}
|
|
2346
2360
|
let responseVersion;
|
|
2347
|
-
if (
|
|
2361
|
+
if (!autoPublish) {
|
|
2348
2362
|
const currentVersion = await getCurrentVersion(nestId, nodeId);
|
|
2349
2363
|
const newVersion = currentVersion + 1;
|
|
2350
2364
|
node = {
|
|
@@ -2399,7 +2413,7 @@ async function updateNode(nestId, nodeId, patch, userEmail) {
|
|
|
2399
2413
|
try {
|
|
2400
2414
|
const result = await safePublishDocument(storage, nodeId, {
|
|
2401
2415
|
editedBy: userEmail,
|
|
2402
|
-
note: patch.changeNote || "Auto-published on edit (no stewards)"
|
|
2416
|
+
note: patch.changeNote || (hasStewards ? "Auto-published on edit (owner/admin self-approve)" : "Auto-published on edit (no stewards)")
|
|
2403
2417
|
});
|
|
2404
2418
|
publishedVersion = result.node.frontmatter.version || publishedVersion;
|
|
2405
2419
|
node = result.node;
|
|
@@ -2410,7 +2424,7 @@ async function updateNode(nestId, nodeId, patch, userEmail) {
|
|
|
2410
2424
|
);
|
|
2411
2425
|
throw err;
|
|
2412
2426
|
}
|
|
2413
|
-
await
|
|
2427
|
+
await upsertVersion({
|
|
2414
2428
|
nestId,
|
|
2415
2429
|
nodeId,
|
|
2416
2430
|
version: publishedVersion,
|
|
@@ -2734,6 +2748,25 @@ async function syncUnsyncedFolder(userId, folderName, callerEmail) {
|
|
|
2734
2748
|
}
|
|
2735
2749
|
return { nest, documents };
|
|
2736
2750
|
}
|
|
2751
|
+
function deleteUnsyncedFolder(folderName) {
|
|
2752
|
+
console.log(`[unsynced] delete requested folder="${folderName}"`);
|
|
2753
|
+
assertSafeFolderName(folderName);
|
|
2754
|
+
const src = join3(config.DATA_ROOT, folderName);
|
|
2755
|
+
if (isNestStorageRoot(src)) {
|
|
2756
|
+
throw new ValidationError("Folder is not eligible for delete");
|
|
2757
|
+
}
|
|
2758
|
+
let stat;
|
|
2759
|
+
try {
|
|
2760
|
+
stat = statSync(src);
|
|
2761
|
+
} catch {
|
|
2762
|
+
throw new NotFoundError(`Folder not found: ${folderName}`);
|
|
2763
|
+
}
|
|
2764
|
+
if (!stat.isDirectory()) {
|
|
2765
|
+
throw new ValidationError(`Not a directory: ${folderName}`);
|
|
2766
|
+
}
|
|
2767
|
+
rmSync(src, { recursive: true, force: true });
|
|
2768
|
+
console.log(`[unsynced] deleted folder ${src}`);
|
|
2769
|
+
}
|
|
2737
2770
|
|
|
2738
2771
|
// src/nests/routes.ts
|
|
2739
2772
|
async function effectivePermission(nestId, userId) {
|
|
@@ -2759,54 +2792,42 @@ nestRoutes.get("/", async (c) => {
|
|
|
2759
2792
|
const annotate = async (n) => {
|
|
2760
2793
|
const permission = await effectivePermission(n.id, userId);
|
|
2761
2794
|
const is_owner = permission === "owner";
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
);
|
|
2770
|
-
const stewardRoles = await getStewardRolesForUser(n.id, callerEmail);
|
|
2771
|
-
const teamRoles = await resolveTeamRolesForUser(n.id, userId);
|
|
2772
|
-
roles = [
|
|
2773
|
-
...new Set(
|
|
2774
|
-
[grantRole, ...stewardRoles, ...teamRoles].filter(Boolean)
|
|
2775
|
-
)
|
|
2776
|
-
];
|
|
2777
|
-
}
|
|
2778
|
-
if (!is_owner && n.user_id !== ANON_USER_ID) {
|
|
2779
|
-
const row = await db.get(ownerEmailSql, [n.user_id]);
|
|
2780
|
-
owner_email = row?.email ?? null;
|
|
2781
|
-
}
|
|
2795
|
+
const needOwnerEmail = !is_owner && n.user_id !== ANON_USER_ID;
|
|
2796
|
+
const [roles, owner_email] = await Promise.all([
|
|
2797
|
+
is_owner ? Promise.resolve(["owner"]) : resolveGrantRoles(n.id, callerEmail, userId),
|
|
2798
|
+
needOwnerEmail ? db.get(ownerEmailSql, [n.user_id]).then(
|
|
2799
|
+
(row) => row?.email ?? null
|
|
2800
|
+
) : Promise.resolve(null)
|
|
2801
|
+
]);
|
|
2782
2802
|
return {
|
|
2783
2803
|
...n,
|
|
2784
2804
|
permission,
|
|
2785
2805
|
is_owner,
|
|
2786
2806
|
owner_email,
|
|
2787
2807
|
roles,
|
|
2788
|
-
stewardship_enabled:
|
|
2808
|
+
stewardship_enabled: !!n.stewardship_enabled
|
|
2789
2809
|
};
|
|
2790
2810
|
};
|
|
2791
2811
|
const seen = /* @__PURE__ */ new Set();
|
|
2792
|
-
const
|
|
2812
|
+
const deduped = [];
|
|
2793
2813
|
for (const n of [...owned, ...shared, ...publicExtras]) {
|
|
2794
2814
|
if (seen.has(n.id)) continue;
|
|
2795
2815
|
seen.add(n.id);
|
|
2796
|
-
|
|
2816
|
+
deduped.push(n);
|
|
2797
2817
|
}
|
|
2818
|
+
const out = await Promise.all(deduped.map(annotate));
|
|
2798
2819
|
const docRows = await db.all(
|
|
2799
2820
|
"SELECT nest_id, COUNT(DISTINCT node_id) AS c FROM node_versions GROUP BY nest_id"
|
|
2800
2821
|
);
|
|
2801
|
-
const docByNest = new Map(docRows.map((r) => [r.nest_id, r.c]));
|
|
2822
|
+
const docByNest = new Map(docRows.map((r) => [r.nest_id, Number(r.c)]));
|
|
2802
2823
|
const collabRows = await db.all(
|
|
2803
2824
|
"SELECT nest_id, COUNT(*) AS c FROM nest_collaborators GROUP BY nest_id"
|
|
2804
2825
|
);
|
|
2805
|
-
const collabByNest = new Map(collabRows.map((r) => [r.nest_id, r.c]));
|
|
2826
|
+
const collabByNest = new Map(collabRows.map((r) => [r.nest_id, Number(r.c)]));
|
|
2806
2827
|
const stewardRows = await db.all(
|
|
2807
2828
|
"SELECT nest_id, COUNT(DISTINCT user_email) AS c FROM stewards WHERE is_active = 1 GROUP BY nest_id"
|
|
2808
2829
|
);
|
|
2809
|
-
const stewardByNest = new Map(stewardRows.map((r) => [r.nest_id, r.c]));
|
|
2830
|
+
const stewardByNest = new Map(stewardRows.map((r) => [r.nest_id, Number(r.c)]));
|
|
2810
2831
|
const stewardEmailRows = await db.all(
|
|
2811
2832
|
`SELECT nest_id, user_email FROM stewards WHERE is_active = 1
|
|
2812
2833
|
GROUP BY nest_id, user_email ORDER BY MIN(assigned_at)`
|
|
@@ -2913,6 +2934,21 @@ nestRoutes.post("/:nestId/sync", async (c) => {
|
|
|
2913
2934
|
);
|
|
2914
2935
|
return c.json(result, 201);
|
|
2915
2936
|
});
|
|
2937
|
+
nestRoutes.delete("/:nestId/sync", async (c) => {
|
|
2938
|
+
if (c.req.param("nestId") !== "unsynced") {
|
|
2939
|
+
throw new NotFoundError("Not found");
|
|
2940
|
+
}
|
|
2941
|
+
const userId = c.get("userId");
|
|
2942
|
+
if (config.AUTH_MODE !== "open" && !await isServerAdminUserId(userId)) {
|
|
2943
|
+
throw new ForbiddenError("Only the server admin can delete folders");
|
|
2944
|
+
}
|
|
2945
|
+
const body = await c.req.json().catch(() => ({}));
|
|
2946
|
+
if (!body?.name) {
|
|
2947
|
+
throw new ValidationError("name is required");
|
|
2948
|
+
}
|
|
2949
|
+
deleteUnsyncedFolder(body.name);
|
|
2950
|
+
return c.json({ ok: true });
|
|
2951
|
+
});
|
|
2916
2952
|
nestRoutes.get("/:nestId", async (c) => {
|
|
2917
2953
|
const nestId = c.req.param("nestId");
|
|
2918
2954
|
if (nestId === "unsynced") return handleUnsyncedList(c);
|
|
@@ -3037,6 +3073,9 @@ async function addCollaborator(params) {
|
|
|
3037
3073
|
const db = getDb();
|
|
3038
3074
|
let userId = params.userId;
|
|
3039
3075
|
if (!userId && params.email) {
|
|
3076
|
+
if (!isEmailish(params.email)) {
|
|
3077
|
+
throw new ValidationError("Enter a valid email address.");
|
|
3078
|
+
}
|
|
3040
3079
|
const email = normalizeEmail(params.email);
|
|
3041
3080
|
const existing = await db.get(
|
|
3042
3081
|
"SELECT id FROM users WHERE LOWER(email) = ?",
|
|
@@ -4011,7 +4050,7 @@ nodeRoutes.post("/", async (c) => {
|
|
|
4011
4050
|
nodeRoutes.get("/:nodeId{.+}/stewards", async (c) => {
|
|
4012
4051
|
const nestId = c.req.param("nestId");
|
|
4013
4052
|
const nodeId = c.req.param("nodeId");
|
|
4014
|
-
const { resolveStewardsWithFallback: resolveStewardsWithFallback2 } = await import("./stewardship-service-
|
|
4053
|
+
const { resolveStewardsWithFallback: resolveStewardsWithFallback2 } = await import("./stewardship-service-B6L7UACX.js");
|
|
4015
4054
|
const { stewards, fallbackToOwner, ownerEmail } = await resolveStewardsWithFallback2(
|
|
4016
4055
|
nestId,
|
|
4017
4056
|
nodeId
|
|
@@ -4032,7 +4071,7 @@ nodeRoutes.get("/:nodeId{.+}/stewards", async (c) => {
|
|
|
4032
4071
|
nodeRoutes.get("/:nodeId{.+}/versions", async (c) => {
|
|
4033
4072
|
const nestId = c.req.param("nestId");
|
|
4034
4073
|
const nodeId = c.req.param("nodeId");
|
|
4035
|
-
const { getVersions: getVersions2, getApprovedVersion: getApprovedVersion2 } = await import("./version-service-
|
|
4074
|
+
const { getVersions: getVersions2, getApprovedVersion: getApprovedVersion2 } = await import("./version-service-L52F4WVZ.js");
|
|
4036
4075
|
const allVersions = await getVersions2(nestId, nodeId);
|
|
4037
4076
|
const approved = await getApprovedVersion2(nestId, nodeId);
|
|
4038
4077
|
const db = getDb();
|
|
@@ -4064,7 +4103,7 @@ nodeRoutes.get("/:nodeId{.+}/versions", async (c) => {
|
|
|
4064
4103
|
nodeRoutes.get("/:nodeId{.+}/reviews", async (c) => {
|
|
4065
4104
|
const nestId = c.req.param("nestId");
|
|
4066
4105
|
const nodeId = c.req.param("nodeId");
|
|
4067
|
-
const { getReviewHistory: getReviewHistory2 } = await import("./review-service-
|
|
4106
|
+
const { getReviewHistory: getReviewHistory2 } = await import("./review-service-Q3NDK5TX.js");
|
|
4068
4107
|
const history = await getReviewHistory2(nestId, nodeId);
|
|
4069
4108
|
return c.json({ reviews: history });
|
|
4070
4109
|
});
|
|
@@ -7471,8 +7510,8 @@ ${list}`;
|
|
|
7471
7510
|
if (!target) return "target is required (a node id or folder prefix).";
|
|
7472
7511
|
if (!["read", "write"].includes(role)) return "role must be read or write.";
|
|
7473
7512
|
try {
|
|
7474
|
-
const { createGrant: createGrant2 } = await import("./grants-service-
|
|
7475
|
-
const db = (await import("./client-
|
|
7513
|
+
const { createGrant: createGrant2 } = await import("./grants-service-FZD6QM6V.js");
|
|
7514
|
+
const db = (await import("./client-AAMF22YJ.js")).getDb();
|
|
7476
7515
|
const { normalizeEmail: normalizeEmail2 } = await import("./email-R7DFS6E5.js");
|
|
7477
7516
|
const e = normalizeEmail2(String(args.email || ""));
|
|
7478
7517
|
if (!e) return "email is required.";
|
|
@@ -8572,7 +8611,7 @@ var CONTENT_TYPES = {
|
|
|
8572
8611
|
};
|
|
8573
8612
|
var VIDEO_EXTS = /* @__PURE__ */ new Set(["mp4", "webm"]);
|
|
8574
8613
|
var IMAGE_MAX_BYTES = 10 * 1024 * 1024;
|
|
8575
|
-
var VIDEO_MAX_BYTES =
|
|
8614
|
+
var VIDEO_MAX_BYTES = config.VIDEO_MAX_BYTES;
|
|
8576
8615
|
var ASSET_MAX_REQUEST_BYTES = VIDEO_MAX_BYTES + 1024 * 1024;
|
|
8577
8616
|
var SAFE_NAME = /^[0-9a-f-]{36}\.(png|jpe?g|gif|webp|mp4|webm)$/;
|
|
8578
8617
|
assetRoutes.post("/", async (c) => {
|
|
@@ -10016,6 +10055,22 @@ var flexAuthMiddleware = createMiddleware2(async (c, next) => {
|
|
|
10016
10055
|
}
|
|
10017
10056
|
return c.json({ error: "Missing or invalid credentials" }, 401);
|
|
10018
10057
|
});
|
|
10058
|
+
var APPROVE_CACHE_TTL_MS = 3e4;
|
|
10059
|
+
var approveCache = /* @__PURE__ */ new Map();
|
|
10060
|
+
async function canApproveInNest(nestId, email) {
|
|
10061
|
+
const key = `${nestId} ${email.toLowerCase()}`;
|
|
10062
|
+
const now = Date.now();
|
|
10063
|
+
const hit = approveCache.get(key);
|
|
10064
|
+
if (hit && hit.exp > now) return hit.ok;
|
|
10065
|
+
const roles = await resolveUserRoles(nestId, email);
|
|
10066
|
+
let ok = roles.includes("admin") || roles.includes("reviewer");
|
|
10067
|
+
if (!ok && roles.includes("owner")) ok = await nestAllowsSelfApprove(nestId);
|
|
10068
|
+
if (approveCache.size > 500) {
|
|
10069
|
+
for (const [k, v] of approveCache) if (v.exp <= now) approveCache.delete(k);
|
|
10070
|
+
}
|
|
10071
|
+
approveCache.set(key, { ok, exp: now + APPROVE_CACHE_TTL_MS });
|
|
10072
|
+
return ok;
|
|
10073
|
+
}
|
|
10019
10074
|
function createApp() {
|
|
10020
10075
|
const app = new Hono21({ router: new LinearRouter() });
|
|
10021
10076
|
const corsOrigins = config.CORS_ORIGINS;
|
|
@@ -10633,12 +10688,16 @@ function createApp() {
|
|
|
10633
10688
|
const userId = c.get("userId");
|
|
10634
10689
|
const me = await resolveCallerEmail(userId);
|
|
10635
10690
|
const nestName2 = /* @__PURE__ */ new Map();
|
|
10636
|
-
for (const n of
|
|
10637
|
-
...await listNests(userId),
|
|
10638
|
-
...await listSharedNests(userId)
|
|
10639
|
-
])
|
|
10691
|
+
for (const n of await listVisibleNests(userId))
|
|
10640
10692
|
nestName2.set(n.id, n.name ?? n.id);
|
|
10641
|
-
const
|
|
10693
|
+
const limit = Math.min(Math.max(Number(c.req.query("limit")) || 50, 1), 100);
|
|
10694
|
+
const offset = Math.max(Number(c.req.query("offset")) || 0, 0);
|
|
10695
|
+
const { requests, total } = await getReviewQueue({
|
|
10696
|
+
status: "pending",
|
|
10697
|
+
nestIds: [...nestName2.keys()],
|
|
10698
|
+
limit,
|
|
10699
|
+
offset
|
|
10700
|
+
});
|
|
10642
10701
|
const toItem = (r) => ({
|
|
10643
10702
|
type: "review",
|
|
10644
10703
|
nest_id: r.nestId,
|
|
@@ -10649,12 +10708,29 @@ function createApp() {
|
|
|
10649
10708
|
requested_at: r.requestedAt,
|
|
10650
10709
|
priority: r.priority
|
|
10651
10710
|
});
|
|
10652
|
-
const mine = requests.filter((r) => nestName2.has(r.nestId));
|
|
10653
10711
|
const byNewest = (a, b) => a.requested_at < b.requested_at ? 1 : -1;
|
|
10654
|
-
const
|
|
10655
|
-
const
|
|
10712
|
+
const others = requests.filter((r) => r.requestedBy !== me);
|
|
10713
|
+
const nestApprove = new Map(
|
|
10714
|
+
await Promise.all(
|
|
10715
|
+
[...new Set(others.map((r) => r.nestId))].map(
|
|
10716
|
+
async (nestId) => [
|
|
10717
|
+
nestId,
|
|
10718
|
+
await canApproveInNest(nestId, me)
|
|
10719
|
+
]
|
|
10720
|
+
)
|
|
10721
|
+
)
|
|
10722
|
+
);
|
|
10723
|
+
const items = others.filter((r) => nestApprove.get(r.nestId)).map(toItem).sort(byNewest);
|
|
10724
|
+
const waiting = requests.filter((r) => r.requestedBy === me).map(toItem).sort(byNewest);
|
|
10656
10725
|
const notifications = await listNotifications(me, { unreadOnly: true, limit: 50 });
|
|
10657
|
-
return c.json({
|
|
10726
|
+
return c.json({
|
|
10727
|
+
items,
|
|
10728
|
+
waiting,
|
|
10729
|
+
notifications,
|
|
10730
|
+
// total = all pending across visible nests (both buckets); has_more drives
|
|
10731
|
+
// the "Load more" control on the client.
|
|
10732
|
+
pagination: { total, limit, offset, has_more: offset + requests.length < total }
|
|
10733
|
+
});
|
|
10658
10734
|
});
|
|
10659
10735
|
app.get("/me/notifications", async (c) => {
|
|
10660
10736
|
const me = await resolveCallerEmail(c.get("userId"));
|
|
@@ -10672,9 +10748,7 @@ function createApp() {
|
|
|
10672
10748
|
const db = getDb();
|
|
10673
10749
|
const userId = c.get("userId");
|
|
10674
10750
|
const userEmail = await resolveCallerEmail(userId);
|
|
10675
|
-
const
|
|
10676
|
-
const sharedNests = await listSharedNests(userId);
|
|
10677
|
-
const visibleNests = [...owned, ...sharedNests];
|
|
10751
|
+
const visibleNests = await listVisibleNests(userId);
|
|
10678
10752
|
let documents = 0;
|
|
10679
10753
|
for (const nest of visibleNests) {
|
|
10680
10754
|
try {
|
|
@@ -6,16 +6,16 @@ import {
|
|
|
6
6
|
getReviewQueue,
|
|
7
7
|
reject,
|
|
8
8
|
submitForReview
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-PAIP5KHB.js";
|
|
10
|
+
import "./chunk-ZQS5W45U.js";
|
|
11
|
+
import "./chunk-EG77SQHO.js";
|
|
12
12
|
import {
|
|
13
13
|
canUserApprove
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-Q5NRCDD4.js";
|
|
15
15
|
import "./chunk-GUNJTORH.js";
|
|
16
16
|
import "./chunk-FRQJWGN3.js";
|
|
17
17
|
import "./chunk-XQ46F76G.js";
|
|
18
|
-
import "./chunk-
|
|
18
|
+
import "./chunk-5QQ7WKAI.js";
|
|
19
19
|
import "./chunk-SLTQACJW.js";
|
|
20
20
|
export {
|
|
21
21
|
approve,
|
|
@@ -14,17 +14,18 @@ import {
|
|
|
14
14
|
getStewardsForUser,
|
|
15
15
|
listStewards,
|
|
16
16
|
removeSteward,
|
|
17
|
+
resolveGrantRoles,
|
|
17
18
|
resolveStewardsForNode,
|
|
18
19
|
resolveStewardsWithFallback,
|
|
19
20
|
resolveUserRoles,
|
|
20
21
|
syncFromConfig,
|
|
21
22
|
updateSteward,
|
|
22
23
|
updateStewardRole
|
|
23
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-Q5NRCDD4.js";
|
|
24
25
|
import "./chunk-GUNJTORH.js";
|
|
25
26
|
import "./chunk-FRQJWGN3.js";
|
|
26
27
|
import "./chunk-XQ46F76G.js";
|
|
27
|
-
import "./chunk-
|
|
28
|
+
import "./chunk-5QQ7WKAI.js";
|
|
28
29
|
import "./chunk-SLTQACJW.js";
|
|
29
30
|
export {
|
|
30
31
|
assignSteward,
|
|
@@ -42,6 +43,7 @@ export {
|
|
|
42
43
|
getStewardsForUser,
|
|
43
44
|
listStewards,
|
|
44
45
|
removeSteward,
|
|
46
|
+
resolveGrantRoles,
|
|
45
47
|
resolveStewardsForNode,
|
|
46
48
|
resolveStewardsWithFallback,
|
|
47
49
|
resolveUserRoles,
|
|
@@ -10,10 +10,11 @@ import {
|
|
|
10
10
|
getVersions,
|
|
11
11
|
hashContent,
|
|
12
12
|
setApprovedVersion,
|
|
13
|
-
systemAuthor
|
|
14
|
-
|
|
13
|
+
systemAuthor,
|
|
14
|
+
upsertVersion
|
|
15
|
+
} from "./chunk-EG77SQHO.js";
|
|
15
16
|
import "./chunk-XQ46F76G.js";
|
|
16
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-5QQ7WKAI.js";
|
|
17
18
|
import "./chunk-SLTQACJW.js";
|
|
18
19
|
export {
|
|
19
20
|
SYSTEM_AUTHOR_PREFIX,
|
|
@@ -27,5 +28,6 @@ export {
|
|
|
27
28
|
getVersions,
|
|
28
29
|
hashContent,
|
|
29
30
|
setApprovedVersion,
|
|
30
|
-
systemAuthor
|
|
31
|
+
systemAuthor,
|
|
32
|
+
upsertVersion
|
|
31
33
|
};
|