@promptowl/contextnest-community 1.24.0 → 1.26.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.
Files changed (125) hide show
  1. package/API.md +177 -14
  2. package/CONFIGURATION.md +577 -116
  3. package/README.md +4 -3
  4. package/STEWARDSHIP.md +24 -0
  5. package/dist/{chunk-XUIWAWDO.js → chunk-2QOJE7A5.js} +4 -4
  6. package/dist/{chunk-2TPQTN4Y.js → chunk-DGPTJXIV.js} +47 -15
  7. package/dist/chunk-I5EDEZBQ.js +523 -0
  8. package/dist/{chunk-ZTT4U4NE.js → chunk-IEAWRHMV.js} +99 -12
  9. package/dist/{chunk-YVMSM7LS.js → chunk-LHWOJPFE.js} +7 -0
  10. package/dist/{chunk-5EZOPA47.js → chunk-M6PGYMBD.js} +20 -11
  11. package/dist/{chunk-F66VCBLA.js → chunk-PICUHQEM.js} +51 -2
  12. package/dist/{chunk-I3CSD6CK.js → chunk-RPGFHESR.js} +2 -2
  13. package/dist/{chunk-KIAAEHWL.js → chunk-SWA5M5XX.js} +88 -546
  14. package/dist/{chunk-LA3VTQ22.js → chunk-TRSGPS27.js} +81 -14
  15. package/dist/{engine-S3QBQ7LH.js → engine-QNMFDIBV.js} +4 -3
  16. package/dist/{external-edit-service-6FNFPOJJ.js → external-edit-service-4MEGPT4D.js} +5 -4
  17. package/dist/{grants-service-UT3EQ3R7.js → grants-service-24GLUBY4.js} +3 -3
  18. package/dist/index.js +1739 -583
  19. package/dist/invited-user-AM6A3WGO.js +12 -0
  20. package/dist/{migrations.postgres-AIQ7WSU7.js → migrations.postgres-HGSQ7IA5.js} +16 -2
  21. package/dist/{review-service-HHGOTO6P.js → review-service-2EWN7WWO.js} +8 -7
  22. package/dist/{stewardship-service-4DHNRULG.js → stewardship-service-TDZUC2Q6.js} +7 -4
  23. package/dist/{version-service-KIOQME6U.js → version-service-C3JTZLJH.js} +5 -4
  24. package/dist/web3/assets/ActivityTracePage-DzwWIjjx.js +1 -0
  25. package/dist/web3/assets/{AgentDocsPage-CIiaBqMy.js → AgentDocsPage-ixP2UdAE.js} +1 -1
  26. package/dist/web3/assets/CollaboratorManager-C9VAXZ0h.js +1 -0
  27. package/dist/web3/assets/CollaboratorsTab-tq4ZTexH.js +1 -0
  28. package/dist/web3/assets/DocumentEditor-C2CP2fiE.js +36 -0
  29. package/dist/web3/assets/DocumentsTab-Mh7KxUoB.js +6 -0
  30. package/dist/web3/assets/ExternalEditsTab-B_CWKXZ_.js +1 -0
  31. package/dist/web3/assets/MarkdownEditor-CKh4WSn-.js +653 -0
  32. package/dist/web3/assets/MarkdownEditor-ndtIx5x0.css +1 -0
  33. package/dist/web3/assets/NestPageHeader-Cizo8nUi.js +1 -0
  34. package/dist/web3/assets/NestView-EW-sraEb.js +73 -0
  35. package/dist/web3/assets/OverviewTab-CjidsMX_.js +6 -0
  36. package/dist/web3/assets/PersonCombobox-BKI7dff4.js +1 -0
  37. package/dist/web3/assets/{ReviewActions-OfOdqzCn.js → ReviewActions-CS8JXgXF.js} +2 -2
  38. package/dist/web3/assets/ReviewTab-CwVrXzw5.js +1 -0
  39. package/dist/web3/assets/StewardsTab-C-iP6gnh.js +1 -0
  40. package/dist/web3/assets/SubmitForReviewModal-Biq3m79i.js +1 -0
  41. package/dist/web3/assets/{alert-dialog-DTozKlmV.js → alert-dialog-BvF3NFr7.js} +2 -2
  42. package/dist/web3/assets/{arrow-left-BCKt4CwQ.js → arrow-left-CWIsv-sG.js} +1 -1
  43. package/dist/web3/assets/backlinks-Cqcn7n1J.js +19 -0
  44. package/dist/web3/assets/boxes-ClbgQqG2.js +6 -0
  45. package/dist/web3/assets/{chevron-left-BPwUT9DS.js → chevron-left-CK_ZPFm9.js} +1 -1
  46. package/dist/web3/assets/{circle-check-DI8IBGeo.js → circle-check-Bw_aTXiH.js} +1 -1
  47. package/dist/web3/assets/{circle-x-VKVhC88W.js → circle-x-DkIG68H7.js} +1 -1
  48. package/dist/web3/assets/client-attribution-BraarYaP.js +1 -0
  49. package/dist/web3/assets/{code-xml-CMabYZvH.js → code-xml-BlR7EN6l.js} +1 -1
  50. package/dist/web3/assets/{corner-down-right-BGxwK6wH.js → corner-down-right-DSVxK3tf.js} +1 -1
  51. package/dist/web3/assets/count-skeleton-DToLM74B.js +1 -0
  52. package/dist/web3/assets/{earth-BEp1EKTo.js → earth-BXhVPvCR.js} +1 -1
  53. package/dist/web3/assets/{file-exclamation-point-r8qZGIjP.js → file-exclamation-point-BevGZgtj.js} +1 -1
  54. package/dist/web3/assets/{folder-input-Cmtx1Jhk.js → folder-input-m8UBV4fA.js} +1 -1
  55. package/dist/web3/assets/{index-C1wTSjfP.js → index-BOVYgMvj.js} +1 -1
  56. package/dist/web3/assets/index-DVnaYqj9.css +1 -0
  57. package/dist/web3/assets/index-WYDmEOfO.js +404 -0
  58. package/dist/web3/assets/page-B6pkc9cd.js +2 -0
  59. package/dist/web3/assets/page-BJrFCKXB.js +1 -0
  60. package/dist/web3/assets/page-Bgy9Ng9p.js +1 -0
  61. package/dist/web3/assets/page-C2zoxumw.js +1 -0
  62. package/dist/web3/assets/page-CJWO06dN.js +1 -0
  63. package/dist/web3/assets/page-CptuAPJc.js +6 -0
  64. package/dist/web3/assets/page-DPY01SOj.js +1 -0
  65. package/dist/web3/assets/page-Dea2SblF.js +9 -0
  66. package/dist/web3/assets/page-Deq6IKiN.js +6 -0
  67. package/dist/web3/assets/page-Dfjg8p7Z.js +1 -0
  68. package/dist/web3/assets/{page-ByyVLDVo.js → page-Dh57L0RG.js} +5 -5
  69. package/dist/web3/assets/page-Dwbp4Seu.js +6 -0
  70. package/dist/web3/assets/{page-CHb0F5hV.js → page-DzKwP5Ds.js} +3 -3
  71. package/dist/web3/assets/page-YxjrE5b5.js +45 -0
  72. package/dist/web3/assets/{page-title-ClvvBsIo.js → page-title-DVq4qvMR.js} +1 -1
  73. package/dist/web3/assets/{play-C5YNKpAH.js → play-CXhS6Pgq.js} +1 -1
  74. package/dist/web3/assets/{send-0CHvmluT.js → send-DdfwnIrj.js} +1 -1
  75. package/dist/web3/assets/{settings-CeeF4LEb.js → settings-DKX0Q4gO.js} +1 -1
  76. package/dist/web3/assets/{share-2-CMnOlOt-.js → share-2-CxmXRt58.js} +1 -1
  77. package/dist/web3/assets/{tag-DQ_6J5Gv.js → tag-DeYC_mRv.js} +1 -1
  78. package/dist/web3/assets/{trash-2-HBi-Pslz.js → trash-2-B0HyPTnI.js} +1 -1
  79. package/dist/web3/assets/{user-plus-CvBNcpn4.js → user-plus-Ckm_Isyc.js} +1 -1
  80. package/dist/web3/assets/{x-By7piikG.js → x-mNtADYHc.js} +1 -1
  81. package/dist/web3/assets/zap-D2ifcnYb.js +16 -0
  82. package/dist/web3/index.html +2 -2
  83. package/package.json +3 -2
  84. package/dist/client-KEY4PYJH.js +0 -11
  85. package/dist/keys-CTOGAG3W.js +0 -20
  86. package/dist/web3/assets/ActivityTracePage-BOZHgJ8S.js +0 -1
  87. package/dist/web3/assets/CollaboratorManager-By91wrIr.js +0 -1
  88. package/dist/web3/assets/CollaboratorsTab-D1EE64Fs.js +0 -1
  89. package/dist/web3/assets/DocumentEditor-DrQfrW3d.js +0 -36
  90. package/dist/web3/assets/DocumentsTab-Vba-AzBv.js +0 -6
  91. package/dist/web3/assets/ExternalEditsTab-BSzAQIGM.js +0 -1
  92. package/dist/web3/assets/MarkdownEditor-74N_naNQ.css +0 -1
  93. package/dist/web3/assets/MarkdownEditor-C9zqZjC5.js +0 -643
  94. package/dist/web3/assets/NestPageHeader-CoLUV1Oz.js +0 -1
  95. package/dist/web3/assets/NestView-CTZ55tXD.js +0 -63
  96. package/dist/web3/assets/OverviewTab-Dxi-Hu-N.js +0 -1
  97. package/dist/web3/assets/PersonCombobox-CPOlNs6G.js +0 -1
  98. package/dist/web3/assets/ReasonDialog-DgLxfRWv.js +0 -1
  99. package/dist/web3/assets/ReviewTab-CyX8yxd3.js +0 -1
  100. package/dist/web3/assets/StewardsTab-DBEEfAQI.js +0 -1
  101. package/dist/web3/assets/SubmitForReviewModal-Ci2DdWs0.js +0 -1
  102. package/dist/web3/assets/backlinks-CYd4xENL.js +0 -24
  103. package/dist/web3/assets/card-XG2dP5Xf.js +0 -1
  104. package/dist/web3/assets/count-skeleton-DMbdpscX.js +0 -1
  105. package/dist/web3/assets/dates-BCxbm4_q.js +0 -1
  106. package/dist/web3/assets/index-BM-h3DwI.css +0 -1
  107. package/dist/web3/assets/index-EaX2yql0.js +0 -389
  108. package/dist/web3/assets/page-B3yvQvHy.js +0 -1
  109. package/dist/web3/assets/page-BExMvttJ.js +0 -1
  110. package/dist/web3/assets/page-BUOADv2X.js +0 -1
  111. package/dist/web3/assets/page-BYUFhYWZ.js +0 -1
  112. package/dist/web3/assets/page-Bicf02Cz.js +0 -1
  113. package/dist/web3/assets/page-BsPMDm5d.js +0 -45
  114. package/dist/web3/assets/page-CC0NJi8v.js +0 -1
  115. package/dist/web3/assets/page-CPjWQNKx.js +0 -11
  116. package/dist/web3/assets/page-CQt3ZGbf.js +0 -2
  117. package/dist/web3/assets/page-Cj1NetQ-.js +0 -1
  118. package/dist/web3/assets/page-CtaW65El.js +0 -1
  119. package/dist/web3/assets/page-DGOL9l8i.js +0 -6
  120. package/dist/web3/assets/refresh-cw-BhHzSH9m.js +0 -6
  121. package/dist/web3/assets/scroll-area-dRWncRqa.css +0 -1
  122. package/dist/web3/assets/scroll-area-hz-xtayP.js +0 -1
  123. package/dist/web3/assets/select-DBFTrUmI.js +0 -6
  124. package/dist/web3/assets/triangle-alert-CDy8-7sv.js +0 -6
  125. package/dist/web3/assets/zap-C2T8riBp.js +0 -11
@@ -2,13 +2,88 @@ import {
2
2
  buildTitleMap,
3
3
  insertOrReplace,
4
4
  nowExpr
5
- } from "./chunk-KIAAEHWL.js";
5
+ } from "./chunk-SWA5M5XX.js";
6
+ import {
7
+ ValidationError
8
+ } from "./chunk-LHWOJPFE.js";
6
9
  import {
7
10
  getDb
8
- } from "./chunk-LA3VTQ22.js";
11
+ } from "./chunk-TRSGPS27.js";
9
12
 
10
13
  // src/governance/version-service.ts
11
14
  import { createHash } from "crypto";
15
+
16
+ // src/shared/client-metadata.ts
17
+ import {
18
+ clientField,
19
+ clientMetadataSchema,
20
+ CLIENT_METADATA_MAX_VALUE_LENGTH
21
+ } from "@promptowl/contextnest-engine/api";
22
+ import { z } from "zod";
23
+ var clientToolField = {
24
+ client: z.any().optional().describe(clientField.client.description ?? "")
25
+ };
26
+ function boundedValue(raw) {
27
+ const cut = raw.slice(0, CLIENT_METADATA_MAX_VALUE_LENGTH);
28
+ const last = cut.charCodeAt(cut.length - 1);
29
+ return last >= 55296 && last <= 56319 ? cut.slice(0, -1) : cut;
30
+ }
31
+ function orAbsent(value) {
32
+ return Object.keys(value).length > 0 ? value : void 0;
33
+ }
34
+ function parseClientMetadata(raw) {
35
+ if (raw === void 0 || raw === null) return void 0;
36
+ const parsed = clientMetadataSchema.safeParse(raw);
37
+ if (!parsed.success) {
38
+ const detail = parsed.error.issues.map((i) => i.path.length ? `${i.path.join(".")}: ${i.message}` : i.message).join("; ");
39
+ throw new ValidationError(`Invalid client metadata \u2014 ${detail}`);
40
+ }
41
+ return orAbsent(parsed.data);
42
+ }
43
+ function mergeClient(derived, supplied) {
44
+ return orAbsent({ ...derived, ...supplied });
45
+ }
46
+ function derivedClient(c, connection) {
47
+ if (process.env.CONTEXTNEST_NO_ATTRIBUTION === "1") return {};
48
+ const agent = process.env.CONTEXTNEST_AGENT || connection?.agent || c.get("apiKeyLabel") || "";
49
+ const session = process.env.CONTEXTNEST_SESSION_ID || connection?.session_id || c.req.header("Mcp-Session-Id") || "";
50
+ return {
51
+ // Truncated to the engine's bound, not rejected: a derived value must never
52
+ // be the reason an otherwise valid call fails validation.
53
+ ...agent ? { agent: boundedValue(String(agent)) } : {},
54
+ ...session ? { session_id: boundedValue(String(session)) } : {}
55
+ };
56
+ }
57
+ function connectionClient(server) {
58
+ const name = server.server.getClientVersion()?.name;
59
+ const sessionId = server.server.transport?.sessionId;
60
+ return {
61
+ ...name ? { agent: name } : {},
62
+ ...sessionId ? { session_id: sessionId } : {}
63
+ };
64
+ }
65
+ function attributeRequest(c, supplied, connection) {
66
+ const client = mergeClient(
67
+ derivedClient(c, connection),
68
+ parseClientMetadata(supplied)
69
+ );
70
+ if (client) c.set("clientMetadata", client);
71
+ return client;
72
+ }
73
+ function serializeClient(value) {
74
+ return value ? JSON.stringify(value) : null;
75
+ }
76
+ function deserializeClient(raw) {
77
+ if (typeof raw !== "string" || !raw) return void 0;
78
+ try {
79
+ const parsed = JSON.parse(raw);
80
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? orAbsent(parsed) : void 0;
81
+ } catch {
82
+ return void 0;
83
+ }
84
+ }
85
+
86
+ // src/governance/version-service.ts
12
87
  function hashContent(content) {
13
88
  return createHash("sha256").update(content).digest("hex");
14
89
  }
@@ -20,8 +95,8 @@ async function createVersion(params) {
20
95
  const db = getDb();
21
96
  const contentHash = hashContent(params.content);
22
97
  await db.run(
23
- `INSERT INTO node_versions (nest_id, node_id, version, content_hash, author, status, change_note, tags_json)
24
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
98
+ `INSERT INTO node_versions (nest_id, node_id, version, content_hash, author, status, change_note, tags_json, client_json)
99
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
25
100
  [
26
101
  params.nestId,
27
102
  params.nodeId,
@@ -30,7 +105,8 @@ async function createVersion(params) {
30
105
  params.author,
31
106
  params.status,
32
107
  params.changeNote || null,
33
- params.tags ? JSON.stringify(params.tags) : null
108
+ params.tags ? JSON.stringify(params.tags) : null,
109
+ serializeClient(params.client)
34
110
  ]
35
111
  );
36
112
  return {
@@ -39,7 +115,8 @@ async function createVersion(params) {
39
115
  editedBy: params.author,
40
116
  editedAt: (/* @__PURE__ */ new Date()).toISOString(),
41
117
  changeNote: params.changeNote,
42
- status: params.status
118
+ status: params.status,
119
+ client: params.client
43
120
  };
44
121
  }
45
122
  async function upsertVersion(params) {
@@ -47,13 +124,13 @@ async function upsertVersion(params) {
47
124
  const contentHash = hashContent(params.content);
48
125
  const sql = insertOrReplace(
49
126
  db,
50
- `INSERT INTO node_versions (nest_id, node_id, version, content_hash, author, status, change_note, tags_json)
51
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
127
+ `INSERT INTO node_versions (nest_id, node_id, version, content_hash, author, status, change_note, tags_json, client_json)
128
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
52
129
  ["nest_id", "node_id", "version"],
53
130
  // Reset created_at on conflict too: SQLite's INSERT OR REPLACE deletes+
54
131
  // reinserts (created_at → now), so mirror that on Postgres — otherwise a
55
132
  // draft edited in place would keep its original (import-time) "edited at".
56
- `content_hash = excluded.content_hash, author = excluded.author, status = excluded.status, change_note = excluded.change_note, tags_json = excluded.tags_json, created_at = ${nowExpr(db)}`
133
+ `content_hash = excluded.content_hash, author = excluded.author, status = excluded.status, change_note = excluded.change_note, tags_json = excluded.tags_json, client_json = excluded.client_json, created_at = ${nowExpr(db)}`
57
134
  );
58
135
  await db.run(sql, [
59
136
  params.nestId,
@@ -63,7 +140,8 @@ async function upsertVersion(params) {
63
140
  params.author,
64
141
  params.status,
65
142
  params.changeNote || null,
66
- params.tags ? JSON.stringify(params.tags) : null
143
+ params.tags ? JSON.stringify(params.tags) : null,
144
+ serializeClient(params.client)
67
145
  ]);
68
146
  return {
69
147
  version: params.version,
@@ -71,7 +149,8 @@ async function upsertVersion(params) {
71
149
  editedBy: params.author,
72
150
  editedAt: (/* @__PURE__ */ new Date()).toISOString(),
73
151
  changeNote: params.changeNote,
74
- status: params.status
152
+ status: params.status,
153
+ client: params.client
75
154
  };
76
155
  }
77
156
  async function getVersions(nestId, nodeId) {
@@ -354,11 +433,19 @@ function rowToVersion(row) {
354
433
  editedBy: row.author,
355
434
  editedAt: row.created_at,
356
435
  changeNote: row.change_note || void 0,
357
- status: row.status
436
+ status: row.status,
437
+ client: deserializeClient(row.client_json)
358
438
  };
359
439
  }
360
440
 
361
441
  export {
442
+ clientToolField,
443
+ parseClientMetadata,
444
+ mergeClient,
445
+ connectionClient,
446
+ attributeRequest,
447
+ serializeClient,
448
+ deserializeClient,
362
449
  hashContent,
363
450
  SYSTEM_AUTHOR_PREFIX,
364
451
  systemAuthor,
@@ -31,6 +31,12 @@ var ValidationError = class extends AppError {
31
31
  this.name = "ValidationError";
32
32
  }
33
33
  };
34
+ var PayloadTooLargeError = class extends AppError {
35
+ constructor(message) {
36
+ super(413, message);
37
+ this.name = "PayloadTooLargeError";
38
+ }
39
+ };
34
40
  var ConflictError = class extends AppError {
35
41
  constructor(message) {
36
42
  super(409, message);
@@ -61,6 +67,7 @@ export {
61
67
  ForbiddenError,
62
68
  UnauthorizedError,
63
69
  ValidationError,
70
+ PayloadTooLargeError,
64
71
  ConflictError,
65
72
  LockedError,
66
73
  VaultBusyError,
@@ -4,19 +4,19 @@ import {
4
4
  resolveNestWideRoles,
5
5
  resolveStewardsForNode,
6
6
  stewardCoverageForUser
7
- } from "./chunk-2TPQTN4Y.js";
7
+ } from "./chunk-DGPTJXIV.js";
8
8
  import {
9
9
  grantCoversNode,
10
10
  listUserGrants,
11
11
  resolveNodeGrant
12
- } from "./chunk-I3CSD6CK.js";
12
+ } from "./chunk-RPGFHESR.js";
13
13
  import {
14
14
  createVersion,
15
15
  getApprovedVersion,
16
16
  getApprovedVersions,
17
17
  getCurrentVersion,
18
18
  setApprovedVersion
19
- } from "./chunk-ZTT4U4NE.js";
19
+ } from "./chunk-IEAWRHMV.js";
20
20
  import {
21
21
  buildDocContext,
22
22
  buildTitleMap,
@@ -28,25 +28,28 @@ import {
28
28
  isStewardshipEnabled,
29
29
  markNotificationsReadBySubject,
30
30
  nestName,
31
- notifyEmailForNest,
32
31
  notifyReviewRequested,
33
32
  notifyReviewResolved,
34
33
  nowExpr,
35
34
  opContext,
36
35
  prettyFolderPath,
37
36
  resolveNestPermission,
38
- sendEmailToRecipient,
39
37
  titleForNode
40
- } from "./chunk-KIAAEHWL.js";
38
+ } from "./chunk-SWA5M5XX.js";
41
39
  import {
42
40
  ConflictError,
43
41
  NotFoundError,
44
42
  ValidationError
45
- } from "./chunk-YVMSM7LS.js";
43
+ } from "./chunk-LHWOJPFE.js";
44
+ import {
45
+ notifyEmailForNest,
46
+ sendEmailToRecipient,
47
+ transportSettings
48
+ } from "./chunk-I5EDEZBQ.js";
46
49
  import {
47
50
  config,
48
51
  getDb
49
- } from "./chunk-LA3VTQ22.js";
52
+ } from "./chunk-TRSGPS27.js";
50
53
 
51
54
  // src/governance/review-service.ts
52
55
  import { v4 as uuid2 } from "uuid";
@@ -712,7 +715,7 @@ async function flush(nestId) {
712
715
  ]);
713
716
  }
714
717
  async function notifyNestEvent(nestId, message, details, opts) {
715
- if (!config.SLACK_WEBHOOK_URL && !config.MSTEAMS_WEBHOOK_URL && !config.SMTP_URL)
718
+ if (!config.SLACK_WEBHOOK_URL && !config.MSTEAMS_WEBHOOK_URL && !transportSettings())
716
719
  return;
717
720
  const buf = buffers.get(nestId);
718
721
  if (buf) {
@@ -788,7 +791,8 @@ async function submitForReview(params) {
788
791
  );
789
792
  if (!alreadySealed) {
790
793
  await versionManager.createVersion(node, params.requestedBy, {
791
- note: params.note || "Submitted for review"
794
+ note: params.note || "Submitted for review",
795
+ ...params.client ? { client: params.client } : {}
792
796
  });
793
797
  }
794
798
  } catch (err) {
@@ -955,7 +959,8 @@ async function approve(params) {
955
959
  author: params.approvedBy,
956
960
  status: "published",
957
961
  tags,
958
- changeNote: note
962
+ changeNote: note,
963
+ client: params.client
959
964
  });
960
965
  await setApprovedVersion(
961
966
  params.nestId,
@@ -1129,6 +1134,10 @@ async function getReviewQueue(params) {
1129
1134
  );
1130
1135
  args.push(...statuses);
1131
1136
  }
1137
+ if (params.requestedByEmail) {
1138
+ whereClauses.push("requested_by = ?");
1139
+ args.push(params.requestedByEmail);
1140
+ }
1132
1141
  const where = whereClauses.length > 0 ? `WHERE ${whereClauses.join(" AND ")}` : "";
1133
1142
  const total = Number(
1134
1143
  (await db.get(
@@ -1,3 +1,17 @@
1
+ import {
2
+ sendEmailToRecipient
3
+ } from "./chunk-I5EDEZBQ.js";
4
+ import {
5
+ config,
6
+ getDb
7
+ } from "./chunk-TRSGPS27.js";
8
+ import {
9
+ normalizeEmail
10
+ } from "./chunk-FRQJWGN3.js";
11
+
12
+ // src/auth/invited-user.ts
13
+ import { v4 as uuid } from "uuid";
14
+
1
15
  // src/auth/keys.ts
2
16
  import { randomBytes, createHash, timingSafeEqual } from "crypto";
3
17
  import bcrypt from "bcryptjs";
@@ -124,6 +138,40 @@ function normalizeKeyLabel(raw) {
124
138
  return trimmed;
125
139
  }
126
140
 
141
+ // src/auth/invited-user.ts
142
+ async function createInvitedUser(rawEmail, opts = {}) {
143
+ const email = normalizeEmail(rawEmail);
144
+ const id = uuid();
145
+ const tempPassword = uuid().replace(/-/g, "").slice(0, 16);
146
+ await getDb().run(
147
+ "INSERT INTO users (id, email, name, password_hash, is_invited) VALUES (?, ?, ?, ?, 1)",
148
+ [id, email, null, await hashPassword(tempPassword)]
149
+ );
150
+ const base = (opts.baseUrl || config.PUBLIC_BASE_URL || "").replace(/\/$/, "");
151
+ void sendEmailToRecipient(email, {
152
+ status: "invited",
153
+ docTitle: "ContextNest",
154
+ path: "",
155
+ actor: email,
156
+ by: opts.invitedBy || void 0,
157
+ tempPassword,
158
+ promptowlSignIn: config.PROMPTOWL_SIGN_IN_GATE === "open",
159
+ // ?invite= prefills the login page and guides them to sign in.
160
+ link: base ? `${base}/?invite=${encodeURIComponent(email)}` : ""
161
+ });
162
+ return { id, tempPassword };
163
+ }
164
+ async function findOrCreateInvitedUser(rawEmail, opts = {}) {
165
+ const email = normalizeEmail(rawEmail);
166
+ const existing = await getDb().get(
167
+ "SELECT id FROM users WHERE LOWER(email) = ?",
168
+ [email]
169
+ );
170
+ if (existing) return { id: existing.id, created: false };
171
+ const { id } = await createInvitedUser(email, opts);
172
+ return { id, created: true };
173
+ }
174
+
127
175
  export {
128
176
  generateApiKey,
129
177
  hashApiKey,
@@ -131,6 +179,7 @@ export {
131
179
  parseBearerToken,
132
180
  hashPassword,
133
181
  verifyPassword,
134
- MAX_API_KEYS_PER_USER,
135
- verifyKeyRequest
182
+ verifyKeyRequest,
183
+ createInvitedUser,
184
+ findOrCreateInvitedUser
136
185
  };
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  ValidationError
3
- } from "./chunk-YVMSM7LS.js";
3
+ } from "./chunk-LHWOJPFE.js";
4
4
  import {
5
5
  getDb
6
- } from "./chunk-LA3VTQ22.js";
6
+ } from "./chunk-TRSGPS27.js";
7
7
 
8
8
  // src/governance/grants-service.ts
9
9
  import { v4 as uuid } from "uuid";