harper-kb 0.2.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 (146) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +288 -0
  3. package/config.yaml +13 -0
  4. package/dist/core/embeddings.d.ts +31 -0
  5. package/dist/core/embeddings.d.ts.map +1 -0
  6. package/dist/core/embeddings.js +199 -0
  7. package/dist/core/embeddings.js.map +1 -0
  8. package/dist/core/entries.d.ts +101 -0
  9. package/dist/core/entries.d.ts.map +1 -0
  10. package/dist/core/entries.js +304 -0
  11. package/dist/core/entries.js.map +1 -0
  12. package/dist/core/history.d.ts +31 -0
  13. package/dist/core/history.d.ts.map +1 -0
  14. package/dist/core/history.js +119 -0
  15. package/dist/core/history.js.map +1 -0
  16. package/dist/core/knowledge-base.d.ts +49 -0
  17. package/dist/core/knowledge-base.d.ts.map +1 -0
  18. package/dist/core/knowledge-base.js +117 -0
  19. package/dist/core/knowledge-base.js.map +1 -0
  20. package/dist/core/search.d.ts +34 -0
  21. package/dist/core/search.d.ts.map +1 -0
  22. package/dist/core/search.js +327 -0
  23. package/dist/core/search.js.map +1 -0
  24. package/dist/core/tags.d.ts +39 -0
  25. package/dist/core/tags.d.ts.map +1 -0
  26. package/dist/core/tags.js +97 -0
  27. package/dist/core/tags.js.map +1 -0
  28. package/dist/core/triage.d.ts +61 -0
  29. package/dist/core/triage.d.ts.map +1 -0
  30. package/dist/core/triage.js +136 -0
  31. package/dist/core/triage.js.map +1 -0
  32. package/dist/core/webhook-endpoints.d.ts +46 -0
  33. package/dist/core/webhook-endpoints.d.ts.map +1 -0
  34. package/dist/core/webhook-endpoints.js +85 -0
  35. package/dist/core/webhook-endpoints.js.map +1 -0
  36. package/dist/hooks.d.ts +67 -0
  37. package/dist/hooks.d.ts.map +1 -0
  38. package/dist/hooks.js +53 -0
  39. package/dist/hooks.js.map +1 -0
  40. package/dist/http-utils.d.ts +38 -0
  41. package/dist/http-utils.d.ts.map +1 -0
  42. package/dist/http-utils.js +133 -0
  43. package/dist/http-utils.js.map +1 -0
  44. package/dist/index.d.ts +27 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +78 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/mcp/protocol.d.ts +25 -0
  49. package/dist/mcp/protocol.d.ts.map +1 -0
  50. package/dist/mcp/protocol.js +105 -0
  51. package/dist/mcp/protocol.js.map +1 -0
  52. package/dist/mcp/server.d.ts +28 -0
  53. package/dist/mcp/server.d.ts.map +1 -0
  54. package/dist/mcp/server.js +144 -0
  55. package/dist/mcp/server.js.map +1 -0
  56. package/dist/mcp/tools.d.ts +26 -0
  57. package/dist/mcp/tools.d.ts.map +1 -0
  58. package/dist/mcp/tools.js +706 -0
  59. package/dist/mcp/tools.js.map +1 -0
  60. package/dist/oauth/authorize.d.ts +28 -0
  61. package/dist/oauth/authorize.d.ts.map +1 -0
  62. package/dist/oauth/authorize.js +421 -0
  63. package/dist/oauth/authorize.js.map +1 -0
  64. package/dist/oauth/init.d.ts +18 -0
  65. package/dist/oauth/init.d.ts.map +1 -0
  66. package/dist/oauth/init.js +30 -0
  67. package/dist/oauth/init.js.map +1 -0
  68. package/dist/oauth/keys.d.ts +34 -0
  69. package/dist/oauth/keys.d.ts.map +1 -0
  70. package/dist/oauth/keys.js +101 -0
  71. package/dist/oauth/keys.js.map +1 -0
  72. package/dist/oauth/metadata.d.ts +23 -0
  73. package/dist/oauth/metadata.d.ts.map +1 -0
  74. package/dist/oauth/metadata.js +57 -0
  75. package/dist/oauth/metadata.js.map +1 -0
  76. package/dist/oauth/middleware.d.ts +23 -0
  77. package/dist/oauth/middleware.d.ts.map +1 -0
  78. package/dist/oauth/middleware.js +65 -0
  79. package/dist/oauth/middleware.js.map +1 -0
  80. package/dist/oauth/register.d.ts +15 -0
  81. package/dist/oauth/register.d.ts.map +1 -0
  82. package/dist/oauth/register.js +78 -0
  83. package/dist/oauth/register.js.map +1 -0
  84. package/dist/oauth/token.d.ts +16 -0
  85. package/dist/oauth/token.d.ts.map +1 -0
  86. package/dist/oauth/token.js +184 -0
  87. package/dist/oauth/token.js.map +1 -0
  88. package/dist/oauth/validate.d.ts +40 -0
  89. package/dist/oauth/validate.d.ts.map +1 -0
  90. package/dist/oauth/validate.js +61 -0
  91. package/dist/oauth/validate.js.map +1 -0
  92. package/dist/resources/HistoryResource.d.ts +41 -0
  93. package/dist/resources/HistoryResource.d.ts.map +1 -0
  94. package/dist/resources/HistoryResource.js +61 -0
  95. package/dist/resources/HistoryResource.js.map +1 -0
  96. package/dist/resources/KnowledgeBaseResource.d.ts +60 -0
  97. package/dist/resources/KnowledgeBaseResource.d.ts.map +1 -0
  98. package/dist/resources/KnowledgeBaseResource.js +118 -0
  99. package/dist/resources/KnowledgeBaseResource.js.map +1 -0
  100. package/dist/resources/KnowledgeEntryResource.d.ts +61 -0
  101. package/dist/resources/KnowledgeEntryResource.d.ts.map +1 -0
  102. package/dist/resources/KnowledgeEntryResource.js +191 -0
  103. package/dist/resources/KnowledgeEntryResource.js.map +1 -0
  104. package/dist/resources/MeResource.d.ts +31 -0
  105. package/dist/resources/MeResource.d.ts.map +1 -0
  106. package/dist/resources/MeResource.js +40 -0
  107. package/dist/resources/MeResource.js.map +1 -0
  108. package/dist/resources/QueryLogResource.d.ts +22 -0
  109. package/dist/resources/QueryLogResource.d.ts.map +1 -0
  110. package/dist/resources/QueryLogResource.js +66 -0
  111. package/dist/resources/QueryLogResource.js.map +1 -0
  112. package/dist/resources/ServiceKeyResource.d.ts +52 -0
  113. package/dist/resources/ServiceKeyResource.d.ts.map +1 -0
  114. package/dist/resources/ServiceKeyResource.js +151 -0
  115. package/dist/resources/ServiceKeyResource.js.map +1 -0
  116. package/dist/resources/TagResource.d.ts +27 -0
  117. package/dist/resources/TagResource.d.ts.map +1 -0
  118. package/dist/resources/TagResource.js +41 -0
  119. package/dist/resources/TagResource.js.map +1 -0
  120. package/dist/resources/TriageResource.d.ts +53 -0
  121. package/dist/resources/TriageResource.d.ts.map +1 -0
  122. package/dist/resources/TriageResource.js +120 -0
  123. package/dist/resources/TriageResource.js.map +1 -0
  124. package/dist/resources/WebhookEndpointResource.d.ts +63 -0
  125. package/dist/resources/WebhookEndpointResource.d.ts.map +1 -0
  126. package/dist/resources/WebhookEndpointResource.js +115 -0
  127. package/dist/resources/WebhookEndpointResource.js.map +1 -0
  128. package/dist/types.d.ts +378 -0
  129. package/dist/types.d.ts.map +1 -0
  130. package/dist/types.js +8 -0
  131. package/dist/types.js.map +1 -0
  132. package/dist/webhooks/github.d.ts +25 -0
  133. package/dist/webhooks/github.d.ts.map +1 -0
  134. package/dist/webhooks/github.js +165 -0
  135. package/dist/webhooks/github.js.map +1 -0
  136. package/dist/webhooks/middleware.d.ts +19 -0
  137. package/dist/webhooks/middleware.d.ts.map +1 -0
  138. package/dist/webhooks/middleware.js +144 -0
  139. package/dist/webhooks/middleware.js.map +1 -0
  140. package/dist/webhooks/types.d.ts +18 -0
  141. package/dist/webhooks/types.d.ts.map +1 -0
  142. package/dist/webhooks/types.js +5 -0
  143. package/dist/webhooks/types.js.map +1 -0
  144. package/package.json +69 -0
  145. package/schema/knowledge.graphql +136 -0
  146. package/schema/oauth.graphql +45 -0
@@ -0,0 +1,40 @@
1
+ /**
2
+ * OAuth JWT Bearer Token Validation
3
+ *
4
+ * Validates JWT access tokens on incoming MCP requests.
5
+ * Verifies the signature, issuer, audience, expiration, and scope.
6
+ *
7
+ * Tokens are scoped to a specific KB via the audience claim:
8
+ * aud = "{baseUrl}/mcp/{kbId}"
9
+ */
10
+ import type { HarperRequest } from '../types.ts';
11
+ export interface ValidatedCaller {
12
+ /** User identifier (from JWT sub claim, e.g. "github:octocat") */
13
+ userId: string;
14
+ /** OAuth client ID */
15
+ clientId: string;
16
+ /** Granted scopes */
17
+ scopes: string[];
18
+ /** Knowledge base this caller is scoped to (from URL path) */
19
+ kbId: string;
20
+ }
21
+ export interface AuthResult {
22
+ /** Validated caller, or null if no valid token */
23
+ caller: ValidatedCaller | null;
24
+ /** Whether an Authorization header with Bearer token was present */
25
+ hasToken: boolean;
26
+ }
27
+ /**
28
+ * Validate the Bearer token from an MCP request.
29
+ *
30
+ * The kbId is extracted from the URL path and used as part of the
31
+ * expected audience claim — tokens issued for one KB cannot be used
32
+ * on another.
33
+ *
34
+ * Returns { caller, hasToken } so the MCP middleware can distinguish:
35
+ * - No token → anonymous read-only access
36
+ * - Valid token → authenticated access with granted scopes
37
+ * - Invalid token → 401 (token present but verification failed)
38
+ */
39
+ export declare function validateMcpAuth(request: HarperRequest, kbId: string): Promise<AuthResult>;
40
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/oauth/validate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,MAAM,WAAW,eAAe;IAC/B,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IAC1B,kDAAkD;IAClD,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,oEAAoE;IACpE,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA0B/F"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * OAuth JWT Bearer Token Validation
3
+ *
4
+ * Validates JWT access tokens on incoming MCP requests.
5
+ * Verifies the signature, issuer, audience, expiration, and scope.
6
+ *
7
+ * Tokens are scoped to a specific KB via the audience claim:
8
+ * aud = "{baseUrl}/mcp/{kbId}"
9
+ */
10
+ import { jwtVerify, createLocalJWKSet } from 'jose';
11
+ import { getBaseUrl, getHeader } from "../http-utils.js";
12
+ import { getJwks } from "./keys.js";
13
+ /**
14
+ * Validate the Bearer token from an MCP request.
15
+ *
16
+ * The kbId is extracted from the URL path and used as part of the
17
+ * expected audience claim — tokens issued for one KB cannot be used
18
+ * on another.
19
+ *
20
+ * Returns { caller, hasToken } so the MCP middleware can distinguish:
21
+ * - No token → anonymous read-only access
22
+ * - Valid token → authenticated access with granted scopes
23
+ * - Invalid token → 401 (token present but verification failed)
24
+ */
25
+ export async function validateMcpAuth(request, kbId) {
26
+ const token = extractBearerToken(request);
27
+ if (!token)
28
+ return { caller: null, hasToken: false };
29
+ try {
30
+ const baseUrl = getBaseUrl(request);
31
+ const jwks = createLocalJWKSet(await getJwks());
32
+ const { payload } = await jwtVerify(token, jwks, {
33
+ issuer: baseUrl,
34
+ audience: `${baseUrl}/mcp/${kbId}`,
35
+ });
36
+ return {
37
+ caller: {
38
+ userId: payload.sub || 'unknown',
39
+ clientId: payload.client_id || 'unknown',
40
+ scopes: typeof payload.scope === 'string' ? payload.scope.split(' ') : [],
41
+ kbId,
42
+ },
43
+ hasToken: true,
44
+ };
45
+ }
46
+ catch (error) {
47
+ logger?.warn?.(`JWT validation failed: ${error.message}`);
48
+ return { caller: null, hasToken: true };
49
+ }
50
+ }
51
+ /**
52
+ * Extract the Bearer token from the Authorization header.
53
+ */
54
+ function extractBearerToken(request) {
55
+ const authValue = getHeader(request, 'authorization');
56
+ if (!authValue)
57
+ return null;
58
+ const match = authValue.match(/^Bearer\s+(.+)$/i);
59
+ return match ? match[1] : null;
60
+ }
61
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/oauth/validate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAEpD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoBpC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAsB,EAAE,IAAY;IACzE,MAAM,KAAK,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAErD,IAAI,CAAC;QACJ,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QACpC,MAAM,IAAI,GAAG,iBAAiB,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC;QAEhD,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE;YAChD,MAAM,EAAE,OAAO;YACf,QAAQ,EAAE,GAAG,OAAO,QAAQ,IAAI,EAAE;SAClC,CAAC,CAAC;QAEH,OAAO;YACN,MAAM,EAAE;gBACP,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,SAAS;gBAChC,QAAQ,EAAG,OAAO,CAAC,SAAoB,IAAI,SAAS;gBACpD,MAAM,EAAE,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE;gBACzE,IAAI;aACJ;YACD,QAAQ,EAAE,IAAI;SACd,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,EAAE,IAAI,EAAE,CAAC,0BAA2B,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;QACrE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACzC,CAAC;AACF,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAC,OAAsB;IACjD,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IACtD,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAE5B,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAClD,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAChC,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * History Resource
3
+ *
4
+ * REST endpoint for knowledge entry edit history.
5
+ * All operations require kbId query parameter for tenant scoping.
6
+ *
7
+ * Routes:
8
+ * GET /History/<entryId>?kbId=.. — get edit history for a knowledge entry
9
+ */
10
+ declare const HistoryResource_base: any;
11
+ export declare class HistoryResource extends HistoryResource_base {
12
+ static loadAsInstance: boolean;
13
+ /**
14
+ * GET /History/<entryId>?kbId=.. — get edit history for a knowledge entry.
15
+ * Public read access (same as KnowledgeEntry).
16
+ */
17
+ get(target?: any): Promise<{
18
+ status: number;
19
+ data: {
20
+ error: string;
21
+ };
22
+ entryId?: undefined;
23
+ editCount?: undefined;
24
+ edits?: undefined;
25
+ } | {
26
+ entryId: string;
27
+ editCount: number;
28
+ edits: {
29
+ id: string;
30
+ kbId: string;
31
+ entryId: string;
32
+ editSummary: string | undefined;
33
+ changedFields: string[];
34
+ createdAt: Date | undefined;
35
+ }[];
36
+ status?: undefined;
37
+ data?: undefined;
38
+ }>;
39
+ }
40
+ export {};
41
+ //# sourceMappingURL=HistoryResource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HistoryResource.d.ts","sourceRoot":"","sources":["../../src/resources/HistoryResource.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;;AAaH,qBAAa,eAAgB,SAAQ,oBAAkB;IACtD,MAAM,CAAC,cAAc,UAAS;IAE9B;;;OAGG;IACG,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG;;;;;;;;;;;;;;;;;;;;;;CAwCtB"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * History Resource
3
+ *
4
+ * REST endpoint for knowledge entry edit history.
5
+ * All operations require kbId query parameter for tenant scoping.
6
+ *
7
+ * Routes:
8
+ * GET /History/<entryId>?kbId=.. — get edit history for a knowledge entry
9
+ */
10
+ import { getHistory } from "../core/history.js";
11
+ import { getEntry } from "../core/entries.js";
12
+ function getResourceClass() {
13
+ return globalThis.Resource;
14
+ }
15
+ function extractKbId(target) {
16
+ return target?.get?.('kbId') || target?.kbId || null;
17
+ }
18
+ export class HistoryResource extends getResourceClass() {
19
+ static loadAsInstance = false;
20
+ /**
21
+ * GET /History/<entryId>?kbId=.. — get edit history for a knowledge entry.
22
+ * Public read access (same as KnowledgeEntry).
23
+ */
24
+ async get(target) {
25
+ const kbId = extractKbId(target);
26
+ if (!kbId) {
27
+ return { status: 400, data: { error: 'kbId query parameter is required' } };
28
+ }
29
+ const entryId = this.getId();
30
+ if (!entryId) {
31
+ return {
32
+ status: 400,
33
+ data: { error: 'Entry ID required: GET /History/<entryId>?kbId=..' },
34
+ };
35
+ }
36
+ // Verify entry belongs to this KB
37
+ const entry = await getEntry(String(entryId));
38
+ if (!entry || entry.kbId !== kbId) {
39
+ return { status: 404, data: { error: 'Knowledge entry not found' } };
40
+ }
41
+ const limitParam = target?.get?.('limit') || target?.limit;
42
+ const limit = limitParam ? parseInt(String(limitParam), 10) : 50;
43
+ const edits = await getHistory(String(entryId), limit);
44
+ // Strip sensitive fields from public responses (usernames, previous values).
45
+ // Harper records use non-enumerable properties, so we must read fields explicitly.
46
+ const publicEdits = edits.map((edit) => ({
47
+ id: edit.id,
48
+ kbId: edit.kbId,
49
+ entryId: edit.entryId,
50
+ editSummary: edit.editSummary,
51
+ changedFields: edit.changedFields,
52
+ createdAt: edit.createdAt,
53
+ }));
54
+ return {
55
+ entryId: String(entryId),
56
+ editCount: publicEdits.length,
57
+ edits: publicEdits,
58
+ };
59
+ }
60
+ }
61
+ //# sourceMappingURL=HistoryResource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HistoryResource.js","sourceRoot":"","sources":["../../src/resources/HistoryResource.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,SAAS,gBAAgB;IACxB,OAAQ,UAAkB,CAAC,QAAQ,CAAC;AACrC,CAAC;AAED,SAAS,WAAW,CAAC,MAAY;IAChC,OAAO,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,MAAM,EAAE,IAAI,IAAI,IAAI,CAAC;AACtD,CAAC;AAED,MAAM,OAAO,eAAgB,SAAQ,gBAAgB,EAAE;IACtD,MAAM,CAAC,cAAc,GAAG,KAAK,CAAC;IAE9B;;;OAGG;IACH,KAAK,CAAC,GAAG,CAAC,MAAY;QACrB,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,IAAI,EAAE,CAAC;YACX,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,kCAAkC,EAAE,EAAE,CAAC;QAC7E,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;YACd,OAAO;gBACN,MAAM,EAAE,GAAG;gBACX,IAAI,EAAE,EAAE,KAAK,EAAE,mDAAmD,EAAE;aACpE,CAAC;QACH,CAAC;QAED,kCAAkC;QAClC,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QAC9C,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACnC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,2BAA2B,EAAE,EAAE,CAAC;QACtE,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,MAAM,EAAE,KAAK,CAAC;QAC3D,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAEjE,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC;QACvD,6EAA6E;QAC7E,mFAAmF;QACnF,MAAM,WAAW,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACxC,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,SAAS,EAAE,IAAI,CAAC,SAAS;SACzB,CAAC,CAAC,CAAC;QACJ,OAAO;YACN,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC;YACxB,SAAS,EAAE,WAAW,CAAC,MAAM;YAC7B,KAAK,EAAE,WAAW;SAClB,CAAC;IACH,CAAC"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Knowledge Base Resource
3
+ *
4
+ * REST endpoint for managing knowledge base tenants.
5
+ * GET is public; POST, PUT, DELETE require team role.
6
+ *
7
+ * Routes:
8
+ * GET /KnowledgeBase/ — list all knowledge bases
9
+ * GET /KnowledgeBase/<id> — get a single knowledge base
10
+ * POST /KnowledgeBase/ — create a new knowledge base (team role)
11
+ * PUT /KnowledgeBase/<id> — update a knowledge base (team role)
12
+ * DELETE /KnowledgeBase/<id> — delete a knowledge base (team role)
13
+ */
14
+ declare const KnowledgeBaseResource_base: any;
15
+ export declare class KnowledgeBaseResource extends KnowledgeBaseResource_base {
16
+ static loadAsInstance: boolean;
17
+ /**
18
+ * GET /KnowledgeBase/<id> — return a single KB.
19
+ * GET /KnowledgeBase/ — list all KBs.
20
+ * PUBLIC — no auth required.
21
+ */
22
+ get(): Promise<import("../types.ts").KnowledgeBase | import("../types.ts").KnowledgeBase[] | {
23
+ status: number;
24
+ data: {
25
+ error: string;
26
+ };
27
+ }>;
28
+ /**
29
+ * POST /KnowledgeBase/ — create a new knowledge base.
30
+ * AUTH REQUIRED: team role only.
31
+ */
32
+ post(_target: any, data: any): Promise<import("../types.ts").KnowledgeBase | {
33
+ status: number;
34
+ data: {
35
+ error: string;
36
+ };
37
+ }>;
38
+ /**
39
+ * PUT /KnowledgeBase/<id> — update a knowledge base.
40
+ * AUTH REQUIRED: team role only.
41
+ */
42
+ put(_target: any, data: any): Promise<import("../types.ts").KnowledgeBase | {
43
+ status: number;
44
+ data: {
45
+ error: string;
46
+ };
47
+ }>;
48
+ /**
49
+ * DELETE /KnowledgeBase/<id> — delete a knowledge base.
50
+ * AUTH REQUIRED: team role only.
51
+ */
52
+ delete(): Promise<true | {
53
+ status: number;
54
+ data: {
55
+ error: string;
56
+ };
57
+ }>;
58
+ }
59
+ export {};
60
+ //# sourceMappingURL=KnowledgeBaseResource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KnowledgeBaseResource.d.ts","sourceRoot":"","sources":["../../src/resources/KnowledgeBaseResource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;;AAcH,qBAAa,qBAAsB,SAAQ,0BAAkB;IAC5D,MAAM,CAAC,cAAc,UAAS;IAE9B;;;;OAIG;IACG,GAAG;;;;;;IAaT;;;OAGG;IACG,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG;;;;;;IA0BlC;;;OAGG;IACG,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG;;;;;;IAwBjC;;;OAGG;IACG,MAAM;;;;;;CAwBZ"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Knowledge Base Resource
3
+ *
4
+ * REST endpoint for managing knowledge base tenants.
5
+ * GET is public; POST, PUT, DELETE require team role.
6
+ *
7
+ * Routes:
8
+ * GET /KnowledgeBase/ — list all knowledge bases
9
+ * GET /KnowledgeBase/<id> — get a single knowledge base
10
+ * POST /KnowledgeBase/ — create a new knowledge base (team role)
11
+ * PUT /KnowledgeBase/<id> — update a knowledge base (team role)
12
+ * DELETE /KnowledgeBase/<id> — delete a knowledge base (team role)
13
+ */
14
+ import { createKnowledgeBase, getKnowledgeBase, updateKnowledgeBase, deleteKnowledgeBase, listKnowledgeBases, } from "../core/knowledge-base.js";
15
+ function getResourceClass() {
16
+ return globalThis.Resource;
17
+ }
18
+ export class KnowledgeBaseResource extends getResourceClass() {
19
+ static loadAsInstance = false;
20
+ /**
21
+ * GET /KnowledgeBase/<id> — return a single KB.
22
+ * GET /KnowledgeBase/ — list all KBs.
23
+ * PUBLIC — no auth required.
24
+ */
25
+ async get() {
26
+ const id = this.getId();
27
+ if (id) {
28
+ const kb = await getKnowledgeBase(String(id));
29
+ if (!kb) {
30
+ return { status: 404, data: { error: 'Knowledge base not found' } };
31
+ }
32
+ return kb;
33
+ }
34
+ return listKnowledgeBases();
35
+ }
36
+ /**
37
+ * POST /KnowledgeBase/ — create a new knowledge base.
38
+ * AUTH REQUIRED: team role only.
39
+ */
40
+ async post(_target, data) {
41
+ const user = this.getCurrentUser();
42
+ if (!user) {
43
+ return { status: 401, data: { error: 'Authentication required' } };
44
+ }
45
+ if (user.role !== 'team') {
46
+ return { status: 403, data: { error: 'Team role required' } };
47
+ }
48
+ if (!data?.id || !data?.name) {
49
+ return { status: 400, data: { error: 'id and name are required' } };
50
+ }
51
+ try {
52
+ return await createKnowledgeBase({
53
+ ...data,
54
+ createdBy: user.username || user.id || 'unknown',
55
+ });
56
+ }
57
+ catch (error) {
58
+ if (error.message.includes('already exists')) {
59
+ return { status: 409, data: { error: error.message } };
60
+ }
61
+ throw error;
62
+ }
63
+ }
64
+ /**
65
+ * PUT /KnowledgeBase/<id> — update a knowledge base.
66
+ * AUTH REQUIRED: team role only.
67
+ */
68
+ async put(_target, data) {
69
+ const user = this.getCurrentUser();
70
+ if (!user) {
71
+ return { status: 401, data: { error: 'Authentication required' } };
72
+ }
73
+ if (user.role !== 'team') {
74
+ return { status: 403, data: { error: 'Team role required' } };
75
+ }
76
+ const id = this.getId();
77
+ if (!id) {
78
+ return { status: 400, data: { error: 'Knowledge base ID required' } };
79
+ }
80
+ try {
81
+ return await updateKnowledgeBase(String(id), data);
82
+ }
83
+ catch (error) {
84
+ if (error.message.includes('not found')) {
85
+ return { status: 404, data: { error: error.message } };
86
+ }
87
+ throw error;
88
+ }
89
+ }
90
+ /**
91
+ * DELETE /KnowledgeBase/<id> — delete a knowledge base.
92
+ * AUTH REQUIRED: team role only.
93
+ */
94
+ async delete() {
95
+ const user = this.getCurrentUser();
96
+ if (!user) {
97
+ return { status: 401, data: { error: 'Authentication required' } };
98
+ }
99
+ if (user.role !== 'team') {
100
+ return { status: 403, data: { error: 'Team role required' } };
101
+ }
102
+ const id = this.getId();
103
+ if (!id) {
104
+ return { status: 400, data: { error: 'Knowledge base ID required' } };
105
+ }
106
+ try {
107
+ await deleteKnowledgeBase(String(id));
108
+ return true;
109
+ }
110
+ catch (error) {
111
+ if (error.message.includes('not found')) {
112
+ return { status: 404, data: { error: error.message } };
113
+ }
114
+ throw error;
115
+ }
116
+ }
117
+ }
118
+ //# sourceMappingURL=KnowledgeBaseResource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KnowledgeBaseResource.js","sourceRoot":"","sources":["../../src/resources/KnowledgeBaseResource.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Knowledge Entry Resource
3
+ *
4
+ * REST endpoint for knowledge base entries.
5
+ * GET is public; POST, PUT, DELETE require authentication.
6
+ * All operations require kbId query parameter for tenant scoping.
7
+ *
8
+ * Routes:
9
+ * GET /Knowledge/<id>?kbId=.. — return single entry
10
+ * GET /Knowledge/?kbId=..&query=.. — search entries
11
+ * POST /Knowledge/?kbId=.. — create new entry (auth required)
12
+ * PUT /Knowledge/<id>?kbId=.. — update entry (auth required)
13
+ * DELETE /Knowledge/<id>?kbId=.. — deprecate entry (team role required)
14
+ */
15
+ declare const KnowledgeEntryResource_base: any;
16
+ export declare class KnowledgeEntryResource extends KnowledgeEntryResource_base {
17
+ static loadAsInstance: boolean;
18
+ /**
19
+ * GET /Knowledge/<id>?kbId=.. — return a single entry by ID.
20
+ * GET /Knowledge/?kbId=..&query=... — search the knowledge base.
21
+ * PUBLIC — no auth required. kbId required.
22
+ */
23
+ get(target?: any): Promise<Omit<import("../types.ts").KnowledgeEntry, "embedding"> | Omit<import("../types.ts").KnowledgeEntry, "embedding">[] | {
24
+ status: number;
25
+ data: {
26
+ error: string;
27
+ };
28
+ }>;
29
+ /**
30
+ * POST /Knowledge/?kbId=.. — create a new knowledge entry.
31
+ * AUTH REQUIRED. AI agents have their confidence forced to "ai-generated".
32
+ */
33
+ post(target: any, data: any): Promise<import("../types.ts").KnowledgeEntry | {
34
+ status: number;
35
+ data: {
36
+ error: string;
37
+ };
38
+ }>;
39
+ /**
40
+ * PUT /Knowledge/<id>?kbId=.. — create or update an entry.
41
+ * AUTH REQUIRED. AI agents have their confidence forced to "ai-generated".
42
+ */
43
+ put(target: any, data: any): Promise<import("../types.ts").KnowledgeEntry | {
44
+ status: number;
45
+ data: {
46
+ error: string;
47
+ };
48
+ }>;
49
+ /**
50
+ * DELETE /Knowledge/<id>?kbId=.. — deprecate an entry (soft delete).
51
+ * AUTH REQUIRED: team role only.
52
+ */
53
+ delete(target?: any): Promise<true | {
54
+ status: number;
55
+ data: {
56
+ error: string;
57
+ };
58
+ }>;
59
+ }
60
+ export {};
61
+ //# sourceMappingURL=KnowledgeEntryResource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KnowledgeEntryResource.d.ts","sourceRoot":"","sources":["../../src/resources/KnowledgeEntryResource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;;AAiBH,qBAAa,sBAAuB,SAAQ,2BAAkB;IAC7D,MAAM,CAAC,cAAc,UAAS;IAE9B;;;;OAIG;IACG,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG;;;;;;IAuDtB;;;OAGG;IACG,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG;;;;;;IAgCjC;;;OAGG;IACG,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG;;;;;;IA0ChC;;;OAGG;IACG,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG;;;;;;CAmCzB"}
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Knowledge Entry Resource
3
+ *
4
+ * REST endpoint for knowledge base entries.
5
+ * GET is public; POST, PUT, DELETE require authentication.
6
+ * All operations require kbId query parameter for tenant scoping.
7
+ *
8
+ * Routes:
9
+ * GET /Knowledge/<id>?kbId=.. — return single entry
10
+ * GET /Knowledge/?kbId=..&query=.. — search entries
11
+ * POST /Knowledge/?kbId=.. — create new entry (auth required)
12
+ * PUT /Knowledge/<id>?kbId=.. — update entry (auth required)
13
+ * DELETE /Knowledge/<id>?kbId=.. — deprecate entry (team role required)
14
+ */
15
+ import { createEntry, getEntry, updateEntry, deprecateEntry, stripEmbedding } from "../core/entries.js";
16
+ import { search, listEntries } from "../core/search.js";
17
+ function getResourceClass() {
18
+ return globalThis.Resource;
19
+ }
20
+ /**
21
+ * Extract kbId from query params (target).
22
+ */
23
+ function extractKbId(target) {
24
+ return target?.get?.('kbId') || target?.kbId || null;
25
+ }
26
+ export class KnowledgeEntryResource extends getResourceClass() {
27
+ static loadAsInstance = false;
28
+ /**
29
+ * GET /Knowledge/<id>?kbId=.. — return a single entry by ID.
30
+ * GET /Knowledge/?kbId=..&query=... — search the knowledge base.
31
+ * PUBLIC — no auth required. kbId required.
32
+ */
33
+ async get(target) {
34
+ const kbId = extractKbId(target);
35
+ if (!kbId) {
36
+ return { status: 400, data: { error: 'kbId query parameter is required' } };
37
+ }
38
+ const id = this.getId();
39
+ if (id) {
40
+ const entry = await getEntry(String(id));
41
+ if (!entry || entry.kbId !== kbId) {
42
+ return { status: 404, data: { error: 'Entry not found' } };
43
+ }
44
+ return stripEmbedding(entry);
45
+ }
46
+ // Search mode: extract query params from target
47
+ const query = target?.get?.('query') || target?.query;
48
+ const tagsParam = target?.get?.('tags') || target?.tags;
49
+ const limitParam = target?.get?.('limit') || target?.limit;
50
+ const tags = tagsParam ? String(tagsParam).split(',') : undefined;
51
+ const limit = limitParam ? parseInt(String(limitParam), 10) : undefined;
52
+ // Browse mode: query=* or no query — list entries without scoring
53
+ if (!query || String(query) === '*') {
54
+ return listEntries(kbId, tags, limit);
55
+ }
56
+ const contextParam = target?.get?.('context') || target?.context;
57
+ const modeParam = target?.get?.('mode') || target?.mode;
58
+ let context;
59
+ if (contextParam) {
60
+ try {
61
+ context = typeof contextParam === 'string' ? JSON.parse(contextParam) : contextParam;
62
+ }
63
+ catch {
64
+ return {
65
+ status: 400,
66
+ data: { error: 'Invalid context parameter: must be valid JSON' },
67
+ };
68
+ }
69
+ }
70
+ const params = {
71
+ kbId,
72
+ query: String(query),
73
+ tags,
74
+ limit,
75
+ context,
76
+ mode: modeParam,
77
+ };
78
+ const results = await search(params);
79
+ return results.map(stripEmbedding);
80
+ }
81
+ /**
82
+ * POST /Knowledge/?kbId=.. — create a new knowledge entry.
83
+ * AUTH REQUIRED. AI agents have their confidence forced to "ai-generated".
84
+ */
85
+ async post(target, data) {
86
+ const user = this.getCurrentUser();
87
+ if (!user) {
88
+ return { status: 401, data: { error: 'Authentication required' } };
89
+ }
90
+ const kbId = extractKbId(target) || data?.kbId;
91
+ if (!kbId) {
92
+ return { status: 400, data: { error: 'kbId is required' } };
93
+ }
94
+ if (!data?.title || !data?.content) {
95
+ return { status: 400, data: { error: 'title and content are required' } };
96
+ }
97
+ if (data.title.length > 500 || data.content.length > 100_000) {
98
+ return {
99
+ status: 400,
100
+ data: { error: 'Title max 500 chars, content max 100,000 chars' },
101
+ };
102
+ }
103
+ // Force ai-generated confidence for ai-agent role
104
+ if (user.role === 'ai-agent') {
105
+ data.confidence = 'ai-generated';
106
+ }
107
+ if (!data.addedBy) {
108
+ data.addedBy = user.username || user.id || 'unknown';
109
+ }
110
+ return createEntry({ ...data, kbId });
111
+ }
112
+ /**
113
+ * PUT /Knowledge/<id>?kbId=.. — create or update an entry.
114
+ * AUTH REQUIRED. AI agents have their confidence forced to "ai-generated".
115
+ */
116
+ async put(target, data) {
117
+ const user = this.getCurrentUser();
118
+ if (!user) {
119
+ return { status: 401, data: { error: 'Authentication required' } };
120
+ }
121
+ const id = this.getId();
122
+ if (!id) {
123
+ return { status: 400, data: { error: 'Entry ID required' } };
124
+ }
125
+ const kbId = extractKbId(target) || data?.kbId;
126
+ if (!kbId) {
127
+ return { status: 400, data: { error: 'kbId is required' } };
128
+ }
129
+ if (user.role === 'ai-agent') {
130
+ data.confidence = 'ai-generated';
131
+ }
132
+ if (!data.addedBy) {
133
+ data.addedBy = user.username || user.id || 'unknown';
134
+ }
135
+ // Upsert: try update first, create if not found
136
+ try {
137
+ const existing = await getEntry(String(id));
138
+ if (existing && existing.kbId !== kbId) {
139
+ return { status: 404, data: { error: 'Entry not found' } };
140
+ }
141
+ return await updateEntry(String(id), data);
142
+ }
143
+ catch (error) {
144
+ if (error.message.includes('not found')) {
145
+ // Entry doesn't exist — create if full data provided, otherwise 404
146
+ if (!data.title || !data.content) {
147
+ return { status: 404, data: { error: 'Entry not found' } };
148
+ }
149
+ return createEntry({ ...data, id: String(id), kbId });
150
+ }
151
+ throw error;
152
+ }
153
+ }
154
+ /**
155
+ * DELETE /Knowledge/<id>?kbId=.. — deprecate an entry (soft delete).
156
+ * AUTH REQUIRED: team role only.
157
+ */
158
+ async delete(target) {
159
+ const user = this.getCurrentUser();
160
+ if (!user) {
161
+ return { status: 401, data: { error: 'Authentication required' } };
162
+ }
163
+ if (user.role !== 'team') {
164
+ return { status: 403, data: { error: 'Team role required' } };
165
+ }
166
+ const id = this.getId();
167
+ if (!id) {
168
+ return { status: 400, data: { error: 'Entry ID required' } };
169
+ }
170
+ const kbId = extractKbId(target);
171
+ if (!kbId) {
172
+ return { status: 400, data: { error: 'kbId query parameter is required' } };
173
+ }
174
+ // Verify entry belongs to this KB
175
+ const existing = await getEntry(String(id));
176
+ if (!existing || existing.kbId !== kbId) {
177
+ return { status: 404, data: { error: 'Entry not found' } };
178
+ }
179
+ try {
180
+ await deprecateEntry(String(id));
181
+ return true;
182
+ }
183
+ catch (error) {
184
+ if (error.message.includes('not found')) {
185
+ return { status: 404, data: { error: error.message } };
186
+ }
187
+ throw error;
188
+ }
189
+ }
190
+ }
191
+ //# sourceMappingURL=KnowledgeEntryResource.js.map