@promptowl/contextnest-community 1.16.1 → 1.17.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 +415 -415
- package/LICENSE.md +142 -142
- package/README.md +164 -169
- package/dist/{chunk-QJVRZT6M.js → chunk-4YGJSUJC.js} +35 -5
- package/dist/{chunk-OTGZQZKK.js → chunk-HWDPCPYT.js} +10 -9
- package/dist/{chunk-L7UCMGWZ.js → chunk-SNFGU5Q7.js} +166 -81
- package/dist/{chunk-D6HICFVW.js → chunk-UXJSO54R.js} +1 -1
- package/dist/{chunk-CLKZZZS2.js → chunk-YF4OFT2V.js} +1 -1
- package/dist/{grants-service-I535QVTW.js → grants-service-4NXPBYWD.js} +3 -3
- package/dist/index.js +213 -65
- package/dist/{review-service-V2GR6VM3.js → review-service-3CCKDO5N.js} +9 -7
- package/dist/{stewardship-service-LTREGVSJ.js → stewardship-service-OHTTZFND.js} +2 -2
- package/dist/{version-service-V6K5SZ3P.js → version-service-EFZGGL3Y.js} +2 -2
- package/dist/web3/assets/{hootie-C2ocYkn4.svg → hootie-_U3ECslt.svg} +8 -8
- package/dist/web3/assets/index-D1299AIf.css +1 -0
- package/dist/web3/assets/index-W6tEA3RK.js +1046 -0
- package/dist/web3/index.html +14 -14
- package/package.json +165 -165
- package/dist/web3/assets/index-DnQARUL3.css +0 -1
- package/dist/web3/assets/index-_m7WyozM.js +0 -1051
package/README.md
CHANGED
|
@@ -1,169 +1,164 @@
|
|
|
1
|
-
# ContextNest Community Edition
|
|
2
|
-
|
|
3
|
-
**Self-hosted context governance server for AI workflows.** Part of the [PromptOwl](https://promptowl.ai) platform.
|
|
4
|
-
|
|
5
|
-
> ⚠️ **Commercial Software.** ContextNest Community Edition is proprietary software licensed by Promptowl LLC. A free [PromptOwl account](https://app.promptowl.ai) is required to use it. Redistribution, hosting-as-a-service, and competitive use are prohibited. See [LICENSE.md](./LICENSE.md) for full terms.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## What it is
|
|
10
|
-
|
|
11
|
-
ContextNest Community Edition is a self-hosted server that lets you:
|
|
12
|
-
|
|
13
|
-
- Store, version, and govern markdown-based context documents ("nests")
|
|
14
|
-
- Import an existing folder or vault of markdown files in one step
|
|
15
|
-
- Export a nest as a portable bundle and re-import it on another self-hosted host
|
|
16
|
-
- Apply stewardship workflows — draft, pending review, approved
|
|
17
|
-
- Share nests with collaborators or publish them read-only to the public
|
|
18
|
-
- Serve approved context to AI agents via MCP
|
|
19
|
-
- Sync with the PromptOwl hosted platform for multi-user collaboration
|
|
20
|
-
|
|
21
|
-
The server runs locally or on your own infrastructure. Your PromptOwl account handles authentication, entitlement, and governance metadata.
|
|
22
|
-
|
|
23
|
-
## Quickstart
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
# 1. Run the community server
|
|
27
|
-
npx @promptowl/contextnest-community
|
|
28
|
-
|
|
29
|
-
# 2. Open the server in your browser
|
|
30
|
-
# http://localhost:3838
|
|
31
|
-
# On first boot with no license, it lands on the License Setup Page.
|
|
32
|
-
|
|
33
|
-
# 3. Paste your PromptOwl license key (pk_...) — see "License setup" below
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
The server listens on `http://localhost:3838` by default. Without a valid license the server still runs and serves reads, but write actions return `503` until you activate. See [CONFIGURATION.md](./CONFIGURATION.md) for all environment variables (port, auth mode, storage, telemetry).
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
|
91
|
-
|
|
92
|
-
|
|
|
93
|
-
|
|
|
94
|
-
|
|
|
95
|
-
|
|
|
96
|
-
|
|
|
97
|
-
|
|
|
98
|
-
|
|
|
99
|
-
|
|
|
100
|
-
|
|
|
101
|
-
|
|
|
102
|
-
|
|
|
103
|
-
|
|
|
104
|
-
|
|
|
105
|
-
|
|
|
106
|
-
|
|
|
107
|
-
|
|
|
108
|
-
|
|
|
109
|
-
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
**You may:**
|
|
127
|
-
-
|
|
128
|
-
-
|
|
129
|
-
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
- **
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
- **
|
|
151
|
-
- **
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
**Copyright © 2026 Promptowl LLC.** All rights reserved.
|
|
167
|
-
"ContextNest" and "PromptOwl" are trademarks of Promptowl LLC.
|
|
168
|
-
|
|
169
|
-
Promptowl LLC · 3060 Mercer University Dr Ste 110 · Atlanta, GA 30341 · USA
|
|
1
|
+
# ContextNest Community Edition
|
|
2
|
+
|
|
3
|
+
**Self-hosted context governance server for AI workflows.** Part of the [PromptOwl](https://promptowl.ai) platform.
|
|
4
|
+
|
|
5
|
+
> ⚠️ **Commercial Software.** ContextNest Community Edition is proprietary software licensed by Promptowl LLC. A free [PromptOwl account](https://app.promptowl.ai) is required to use it. Redistribution, hosting-as-a-service, and competitive use are prohibited. See [LICENSE.md](./LICENSE.md) for full terms.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What it is
|
|
10
|
+
|
|
11
|
+
ContextNest Community Edition is a self-hosted server that lets you:
|
|
12
|
+
|
|
13
|
+
- Store, version, and govern markdown-based context documents ("nests")
|
|
14
|
+
- Import an existing folder or vault of markdown files in one step
|
|
15
|
+
- Export a nest as a portable bundle and re-import it on another self-hosted host
|
|
16
|
+
- Apply stewardship workflows — draft, pending review, approved
|
|
17
|
+
- Share nests with collaborators or publish them read-only to the public
|
|
18
|
+
- Serve approved context to AI agents via MCP or HTTP
|
|
19
|
+
- Sync with the PromptOwl hosted platform for multi-user collaboration
|
|
20
|
+
|
|
21
|
+
The server runs locally or on your own infrastructure. Your PromptOwl account handles authentication, entitlement, and governance metadata.
|
|
22
|
+
|
|
23
|
+
## Quickstart
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# 1. Run the community server
|
|
27
|
+
npx @promptowl/contextnest-community
|
|
28
|
+
|
|
29
|
+
# 2. Open the server in your browser
|
|
30
|
+
# http://localhost:3838
|
|
31
|
+
# On first boot with no license, it lands on the License Setup Page.
|
|
32
|
+
|
|
33
|
+
# 3. Paste your PromptOwl license key (pk_...) — see "License setup" below
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The server listens on `http://localhost:3838` by default. Without a valid license the server still runs and serves reads, but write actions return `503` until you activate. See [CONFIGURATION.md](./CONFIGURATION.md) for all environment variables (port, auth mode, storage, telemetry).
|
|
37
|
+
|
|
38
|
+
## License setup
|
|
39
|
+
|
|
40
|
+
ContextNest Community Edition requires a PromptOwl Community License key (`pk_...`). Getting and activating one:
|
|
41
|
+
|
|
42
|
+
### 1. Create the key (free)
|
|
43
|
+
|
|
44
|
+
1. Sign up or log in at <https://app.promptowl.ai>
|
|
45
|
+
2. Open the **Overview** menu → **Community License**
|
|
46
|
+
3. Click **Create a Community License key**
|
|
47
|
+
4. Copy the generated key — it starts with `pk_`
|
|
48
|
+
|
|
49
|
+
### 2. Activate the server
|
|
50
|
+
|
|
51
|
+
Pick **one** of two ways:
|
|
52
|
+
|
|
53
|
+
**A. Browser setup page (recommended for first run)**
|
|
54
|
+
|
|
55
|
+
1. Start the server: `npx @promptowl/contextnest-community`
|
|
56
|
+
2. Open <http://localhost:3838> — with no license installed, the server boots into **setup mode** and shows the **License Setup Page**
|
|
57
|
+
3. Paste your `pk_...` key and submit
|
|
58
|
+
4. The server validates it against PromptOwl, writes it to your `.env`, and exits setup mode — no restart needed
|
|
59
|
+
|
|
60
|
+
**B. Environment variable (recommended for Docker / CI / scripted deploys)**
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
PROMPTOWL_KEY=pk_... npx @promptowl/contextnest-community
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The key is read at boot. The server validates against PromptOwl on startup; if valid, it goes straight into licensed mode.
|
|
67
|
+
|
|
68
|
+
### 3. How licensing behaves at runtime
|
|
69
|
+
|
|
70
|
+
- **Unlicensed / setup mode** — reads work; every non-GET (write) request returns `503` until a valid key is installed.
|
|
71
|
+
- **Live revocation** — a long-poll watcher tracks license state against PromptOwl. If your key is revoked, the server blocks writes within seconds (no restart required) and returns to setup mode.
|
|
72
|
+
- **Admin identity follows the license** — the admin user is whichever PromptOwl account owns the installed key, resolved live per request. Transferring the license to another account immediately promotes the new owner and demotes the old one.
|
|
73
|
+
|
|
74
|
+
For redistribution, hosted-service, OEM, or regulated-industry licensing, contact **hoot@promptowl.ai**.
|
|
75
|
+
|
|
76
|
+
## System requirements
|
|
77
|
+
|
|
78
|
+
- **Node.js** 20.x or later
|
|
79
|
+
- **PromptOwl account** — free signup at <https://app.promptowl.ai/signup>
|
|
80
|
+
- **OS:** Windows, macOS, or Linux
|
|
81
|
+
- **Disk:** ~200 MB for the server, plus storage for your nests
|
|
82
|
+
|
|
83
|
+
## What you get
|
|
84
|
+
|
|
85
|
+
| Feature | Community Edition | Enterprise |
|
|
86
|
+
|---|:---:|:---:|
|
|
87
|
+
| Self-hosted context server | ✅ | ✅ |
|
|
88
|
+
| SQLite or PostgreSQL / Cloud SQL backend | ✅ | ✅ |
|
|
89
|
+
| Configurable nest storage (external / GCS volume mount) | ✅ | ✅ |
|
|
90
|
+
| Markdown + YAML frontmatter vaults | ✅ | ✅ |
|
|
91
|
+
| Import existing folder / vault | ✅ | ✅ |
|
|
92
|
+
| Export nest as portable bundle (.zip) | ✅ | ✅ |
|
|
93
|
+
| Markdown rendering + wiki cross-linking | ✅ | ✅ |
|
|
94
|
+
| External-edit detection + version diff | ✅ | ✅ |
|
|
95
|
+
| Stewardship workflow (draft/review/approve) | ✅ | ✅ |
|
|
96
|
+
| Per-nest sharing + collaborators | ✅ | ✅ |
|
|
97
|
+
| Public read-only nests | ✅ | ✅ |
|
|
98
|
+
| Custom logo / branding | ✅ | ✅ |
|
|
99
|
+
| Admin password reset + user removal (in-platform) | ✅ | ✅ |
|
|
100
|
+
| Wiki backlinks, outline, hover-preview, link health | ✅ | ✅ |
|
|
101
|
+
| Rich editor — tables, callouts, toggles, code highlight, find/replace, image & video upload | ✅ | ✅ |
|
|
102
|
+
| Steward version revert | ✅ | ✅ |
|
|
103
|
+
| MCP server for AI agents | ✅ | ✅ |
|
|
104
|
+
| Centralized multi-tenant admin console | — | ✅ |
|
|
105
|
+
| Single sign-on (OIDC — Entra ID, Google, Okta, Keycloak) | ✅ | ✅ |
|
|
106
|
+
| SAML / SCIM provisioning | — | ✅ |
|
|
107
|
+
| Audit log streaming | — | ✅ |
|
|
108
|
+
| Policy transforms (redaction, summarization) | — | ✅ |
|
|
109
|
+
| Priority support and SLA | — | ✅ |
|
|
110
|
+
|
|
111
|
+
For Enterprise pricing and features, contact **hoot@promptowl.ai** or visit <https://promptowl.ai/contextnest/>.
|
|
112
|
+
|
|
113
|
+
## What's new
|
|
114
|
+
|
|
115
|
+
Release notes live in [CHANGELOG.md](./CHANGELOG.md).
|
|
116
|
+
|
|
117
|
+
## Licensing
|
|
118
|
+
|
|
119
|
+
ContextNest Community Edition is **commercial software**. It is **not open source**.
|
|
120
|
+
|
|
121
|
+
**You may:**
|
|
122
|
+
- Install and run the Software on devices You own or control
|
|
123
|
+
- Use the Software for internal business purposes, tied to a valid PromptOwl account
|
|
124
|
+
- Make backup and archival copies
|
|
125
|
+
|
|
126
|
+
**You may not:**
|
|
127
|
+
- Redistribute, resell, rent, lease, or sublicense the Software
|
|
128
|
+
- Offer the Software as a hosted, managed, or software-as-a-service product to third parties
|
|
129
|
+
- Reverse engineer, decompile, or create derivative works
|
|
130
|
+
- Use the Software to build a competing product or service
|
|
131
|
+
- Remove copyright, trademark, or license notices
|
|
132
|
+
|
|
133
|
+
Full license text: [LICENSE.md](./LICENSE.md)
|
|
134
|
+
|
|
135
|
+
**For redistribution, hosted-service, OEM, or regulated-industry use,** contact **hoot@promptowl.ai** for a commercial license agreement.
|
|
136
|
+
|
|
137
|
+
## Platform terms
|
|
138
|
+
|
|
139
|
+
Because the Software requires a PromptOwl account, the following terms also apply to Your use:
|
|
140
|
+
|
|
141
|
+
- **End User License Agreement** — <https://promptowl.ai/eula/>
|
|
142
|
+
- **Terms of Service** — <https://promptowl.ai/terms-of-service/>
|
|
143
|
+
- **Privacy Policy** — <https://promptowl.ai/privacy-policy/>
|
|
144
|
+
- **Acceptable Use Policy** — <https://promptowl.ai/acceptable-use/>
|
|
145
|
+
- **Disclaimer** — <https://promptowl.ai/disclaimer/>
|
|
146
|
+
- **Cookie Policy** — <https://promptowl.ai/cookies/>
|
|
147
|
+
|
|
148
|
+
## Support
|
|
149
|
+
|
|
150
|
+
- **Documentation:** <https://promptowl.ai/contextnest/>
|
|
151
|
+
- **Product questions:** <https://promptowl.ai/contact-us/>
|
|
152
|
+
- **Support & bugs:** `hoot@promptowl.ai`
|
|
153
|
+
- **Commercial licensing:** `hoot@promptowl.ai` (subject: *ContextNest Commercial License*)
|
|
154
|
+
|
|
155
|
+
## AI output disclaimer
|
|
156
|
+
|
|
157
|
+
The Software injects content into large language models. AI output may be inaccurate, incomplete, or inappropriate for your use case. You are responsible for reviewing and validating any AI-generated content before relying on it, particularly in business-critical or regulated contexts. Do not deploy the Software in medical, legal, financial-advisory, or safety-critical environments without appropriate human oversight.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
**Copyright © 2026 Promptowl LLC.** All rights reserved.
|
|
162
|
+
"ContextNest" and "PromptOwl" are trademarks of Promptowl LLC.
|
|
163
|
+
|
|
164
|
+
Promptowl LLC · 3060 Mercer University Dr Ste 110 · Atlanta, GA 30341 · USA
|
|
@@ -2,19 +2,19 @@ import {
|
|
|
2
2
|
grantCoversNode,
|
|
3
3
|
listUserGrants,
|
|
4
4
|
resolveNodeGrant
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-HWDPCPYT.js";
|
|
6
6
|
import {
|
|
7
7
|
createVersion,
|
|
8
8
|
getApprovedVersion,
|
|
9
9
|
getApprovedVersions,
|
|
10
10
|
getCurrentVersion,
|
|
11
11
|
setApprovedVersion
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-UXJSO54R.js";
|
|
13
13
|
import {
|
|
14
14
|
canUserAccess,
|
|
15
15
|
canUserApprove,
|
|
16
16
|
resolveStewardsForNode
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-YF4OFT2V.js";
|
|
18
18
|
import {
|
|
19
19
|
buildDocContext,
|
|
20
20
|
buildTitleMap,
|
|
@@ -29,9 +29,10 @@ import {
|
|
|
29
29
|
nowExpr,
|
|
30
30
|
opContext,
|
|
31
31
|
prettyFolderPath,
|
|
32
|
+
resolveNestPermission,
|
|
32
33
|
sendEmailToRecipient,
|
|
33
34
|
titleForNode
|
|
34
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-SNFGU5Q7.js";
|
|
35
36
|
import {
|
|
36
37
|
ConflictError,
|
|
37
38
|
NotFoundError,
|
|
@@ -225,13 +226,31 @@ async function canReadNode(nestId, nodeId, userId, userEmail) {
|
|
|
225
226
|
if ((await canUserAccess(nestId, nodeId, userEmail)).allowed) return true;
|
|
226
227
|
return await resolveNodeGrant(nestId, userId, nodeId) !== null;
|
|
227
228
|
}
|
|
229
|
+
async function canRequestDeletion(params) {
|
|
230
|
+
const { nestId, userId, userEmail, nodeId } = params;
|
|
231
|
+
const permission = params.permission ?? await resolveNestPermission(nestId, userId);
|
|
232
|
+
if (permission === "owner" || permission === "admin" || permission === "write") {
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
const resolved = await resolveStewardsForNode(nestId, nodeId);
|
|
236
|
+
const isEditorSteward = resolved.some(
|
|
237
|
+
(r) => r.steward.userEmail.toLowerCase() === userEmail.toLowerCase() && r.steward.role === "editor" && (nodeId !== "" || r.steward.scope === "nest")
|
|
238
|
+
);
|
|
239
|
+
if (isEditorSteward) return true;
|
|
240
|
+
if (nodeId === "") return false;
|
|
241
|
+
return await resolveNodeGrant(nestId, userId, nodeId) === "write";
|
|
242
|
+
}
|
|
228
243
|
async function filterAccessible(nestId, userId, userEmail, nodes, approvedVersions) {
|
|
229
244
|
if (await isPublicReader(nestId, userId)) {
|
|
230
245
|
const approved = approvedVersions ?? await getApprovedVersions(nestId);
|
|
231
246
|
return nodes.filter((n) => approved.has(n.id));
|
|
232
247
|
}
|
|
233
|
-
if (!await isStewardshipEnabled(nestId)) return nodes;
|
|
234
248
|
const grants = await listUserGrants(nestId, userId);
|
|
249
|
+
if (!await isStewardshipEnabled(nestId)) {
|
|
250
|
+
if (grants.length === 0) return nodes;
|
|
251
|
+
if (await resolveNestPermission(nestId, userId) !== "none") return nodes;
|
|
252
|
+
return nodes.filter((n) => grantCoversNode(grants, n.id));
|
|
253
|
+
}
|
|
235
254
|
const accessible = [];
|
|
236
255
|
for (const n of nodes) {
|
|
237
256
|
if ((await canUserAccess(nestId, n.id, userEmail)).allowed || grantCoversNode(grants, n.id)) {
|
|
@@ -1477,6 +1496,15 @@ async function listDeletionRequests(params) {
|
|
|
1477
1496
|
async function dropDeletionRequest(id) {
|
|
1478
1497
|
await getDb().run("DELETE FROM deletion_requests WHERE id = ?", [id]);
|
|
1479
1498
|
}
|
|
1499
|
+
async function withdrawDeletionRequest(params) {
|
|
1500
|
+
const db = getDb();
|
|
1501
|
+
const pending = await getDeletionRequest(params.id);
|
|
1502
|
+
if (!pending || pending.nestId !== params.nestId || pending.status !== "pending" || pending.requestedBy.toLowerCase() !== params.withdrawnBy.toLowerCase()) {
|
|
1503
|
+
return null;
|
|
1504
|
+
}
|
|
1505
|
+
await db.run("DELETE FROM deletion_requests WHERE id = ?", [params.id]);
|
|
1506
|
+
return pending;
|
|
1507
|
+
}
|
|
1480
1508
|
async function declineDeletion(params) {
|
|
1481
1509
|
const db = getDb();
|
|
1482
1510
|
const pending = await getDeletionRequest(params.id);
|
|
@@ -1556,6 +1584,7 @@ export {
|
|
|
1556
1584
|
markNotificationsRead,
|
|
1557
1585
|
resolveCallerEmail,
|
|
1558
1586
|
canReadNode,
|
|
1587
|
+
canRequestDeletion,
|
|
1559
1588
|
filterAccessible,
|
|
1560
1589
|
safeJson,
|
|
1561
1590
|
requireWorkflowPlane,
|
|
@@ -1586,5 +1615,6 @@ export {
|
|
|
1586
1615
|
getDeletionRequest,
|
|
1587
1616
|
listDeletionRequests,
|
|
1588
1617
|
dropDeletionRequest,
|
|
1618
|
+
withdrawDeletionRequest,
|
|
1589
1619
|
declineDeletion
|
|
1590
1620
|
};
|
|
@@ -22,14 +22,6 @@ async function resolveNodeGrant(nestId, userId, nodeId) {
|
|
|
22
22
|
}
|
|
23
23
|
return best;
|
|
24
24
|
}
|
|
25
|
-
async function hasAnyGrant(nestId, userId) {
|
|
26
|
-
if (!userId) return false;
|
|
27
|
-
const row = await getDb().get(
|
|
28
|
-
"SELECT 1 AS x FROM grants WHERE nest_id = ? AND user_id = ? LIMIT 1",
|
|
29
|
-
[nestId, userId]
|
|
30
|
-
);
|
|
31
|
-
return !!row;
|
|
32
|
-
}
|
|
33
25
|
async function listUserGrants(nestId, userId) {
|
|
34
26
|
if (!userId) return [];
|
|
35
27
|
return await getDb().all(
|
|
@@ -42,6 +34,15 @@ function grantCoversNode(grants, nodeId) {
|
|
|
42
34
|
(g) => nodeId === g.target || nodeId.startsWith(g.target + "/")
|
|
43
35
|
);
|
|
44
36
|
}
|
|
37
|
+
function grantRoleForNode(grants, nodeId) {
|
|
38
|
+
let best = null;
|
|
39
|
+
for (const g of grants) {
|
|
40
|
+
if (nodeId === g.target || nodeId.startsWith(g.target + "/")) {
|
|
41
|
+
if (!best || rank(g.role) > rank(best)) best = g.role;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return best;
|
|
45
|
+
}
|
|
45
46
|
async function createGrant(params) {
|
|
46
47
|
const { nestId, targetType, target, userId, role, grantedBy } = params;
|
|
47
48
|
if (!["document", "folder"].includes(targetType)) {
|
|
@@ -94,9 +95,9 @@ async function deleteGrant(nestId, id) {
|
|
|
94
95
|
|
|
95
96
|
export {
|
|
96
97
|
resolveNodeGrant,
|
|
97
|
-
hasAnyGrant,
|
|
98
98
|
listUserGrants,
|
|
99
99
|
grantCoversNode,
|
|
100
|
+
grantRoleForNode,
|
|
100
101
|
createGrant,
|
|
101
102
|
listGrants,
|
|
102
103
|
deleteGrant
|