@collage-dam/mcp-server 0.1.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/.env.example +56 -0
- package/CHANGELOG.md +90 -0
- package/LICENSE +21 -0
- package/README.md +512 -0
- package/dist/client.d.ts +497 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +1162 -0
- package/dist/client.js.map +1 -0
- package/dist/conventions/confirmation.d.ts +89 -0
- package/dist/conventions/confirmation.d.ts.map +1 -0
- package/dist/conventions/confirmation.js +132 -0
- package/dist/conventions/confirmation.js.map +1 -0
- package/dist/conventions/dry-run/batch-executor.d.ts +36 -0
- package/dist/conventions/dry-run/batch-executor.d.ts.map +1 -0
- package/dist/conventions/dry-run/batch-executor.js +89 -0
- package/dist/conventions/dry-run/batch-executor.js.map +1 -0
- package/dist/conventions/dry-run/diff-renderer.d.ts +34 -0
- package/dist/conventions/dry-run/diff-renderer.d.ts.map +1 -0
- package/dist/conventions/dry-run/diff-renderer.js +158 -0
- package/dist/conventions/dry-run/diff-renderer.js.map +1 -0
- package/dist/conventions/dry-run/index.d.ts +13 -0
- package/dist/conventions/dry-run/index.d.ts.map +1 -0
- package/dist/conventions/dry-run/index.js +10 -0
- package/dist/conventions/dry-run/index.js.map +1 -0
- package/dist/conventions/dry-run/mutating-tool.d.ts +64 -0
- package/dist/conventions/dry-run/mutating-tool.d.ts.map +1 -0
- package/dist/conventions/dry-run/mutating-tool.js +88 -0
- package/dist/conventions/dry-run/mutating-tool.js.map +1 -0
- package/dist/conventions/dry-run/summary.d.ts +66 -0
- package/dist/conventions/dry-run/summary.d.ts.map +1 -0
- package/dist/conventions/dry-run/summary.js +185 -0
- package/dist/conventions/dry-run/summary.js.map +1 -0
- package/dist/conventions/dry-run/types.d.ts +597 -0
- package/dist/conventions/dry-run/types.d.ts.map +1 -0
- package/dist/conventions/dry-run/types.js +108 -0
- package/dist/conventions/dry-run/types.js.map +1 -0
- package/dist/conventions/dry-run/with-dry-run.d.ts +66 -0
- package/dist/conventions/dry-run/with-dry-run.d.ts.map +1 -0
- package/dist/conventions/dry-run/with-dry-run.js +219 -0
- package/dist/conventions/dry-run/with-dry-run.js.map +1 -0
- package/dist/conventions/env.d.ts +49 -0
- package/dist/conventions/env.d.ts.map +1 -0
- package/dist/conventions/env.js +84 -0
- package/dist/conventions/env.js.map +1 -0
- package/dist/conventions/errors.d.ts +68 -0
- package/dist/conventions/errors.d.ts.map +1 -0
- package/dist/conventions/errors.js +81 -0
- package/dist/conventions/errors.js.map +1 -0
- package/dist/conventions/logger.d.ts +28 -0
- package/dist/conventions/logger.d.ts.map +1 -0
- package/dist/conventions/logger.js +105 -0
- package/dist/conventions/logger.js.map +1 -0
- package/dist/conventions/pagination.d.ts +37 -0
- package/dist/conventions/pagination.d.ts.map +1 -0
- package/dist/conventions/pagination.js +53 -0
- package/dist/conventions/pagination.js.map +1 -0
- package/dist/conventions/rate-limiter.d.ts +54 -0
- package/dist/conventions/rate-limiter.d.ts.map +1 -0
- package/dist/conventions/rate-limiter.js +143 -0
- package/dist/conventions/rate-limiter.js.map +1 -0
- package/dist/conventions/response-budget.d.ts +66 -0
- package/dist/conventions/response-budget.d.ts.map +1 -0
- package/dist/conventions/response-budget.js +89 -0
- package/dist/conventions/response-budget.js.map +1 -0
- package/dist/conventions/schema-version.d.ts +27 -0
- package/dist/conventions/schema-version.d.ts.map +1 -0
- package/dist/conventions/schema-version.js +29 -0
- package/dist/conventions/schema-version.js.map +1 -0
- package/dist/conventions/state-store-redis.d.ts +32 -0
- package/dist/conventions/state-store-redis.d.ts.map +1 -0
- package/dist/conventions/state-store-redis.js +77 -0
- package/dist/conventions/state-store-redis.js.map +1 -0
- package/dist/conventions/state-store.d.ts +46 -0
- package/dist/conventions/state-store.d.ts.map +1 -0
- package/dist/conventions/state-store.js +105 -0
- package/dist/conventions/state-store.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +421 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/collection-audit.d.ts +13 -0
- package/dist/prompts/collection-audit.d.ts.map +1 -0
- package/dist/prompts/collection-audit.js +168 -0
- package/dist/prompts/collection-audit.js.map +1 -0
- package/dist/prompts/create-distribution.d.ts +15 -0
- package/dist/prompts/create-distribution.d.ts.map +1 -0
- package/dist/prompts/create-distribution.js +111 -0
- package/dist/prompts/create-distribution.js.map +1 -0
- package/dist/prompts/helpers.d.ts +20 -0
- package/dist/prompts/helpers.d.ts.map +1 -0
- package/dist/prompts/helpers.js +53 -0
- package/dist/prompts/helpers.js.map +1 -0
- package/dist/prompts/library-health-audit.d.ts +13 -0
- package/dist/prompts/library-health-audit.d.ts.map +1 -0
- package/dist/prompts/library-health-audit.js +131 -0
- package/dist/prompts/library-health-audit.js.map +1 -0
- package/dist/prompts/usage-insights.d.ts +13 -0
- package/dist/prompts/usage-insights.d.ts.map +1 -0
- package/dist/prompts/usage-insights.js +98 -0
- package/dist/prompts/usage-insights.js.map +1 -0
- package/dist/prompts/wrap-prompt-as-tool.d.ts +48 -0
- package/dist/prompts/wrap-prompt-as-tool.d.ts.map +1 -0
- package/dist/prompts/wrap-prompt-as-tool.js +61 -0
- package/dist/prompts/wrap-prompt-as-tool.js.map +1 -0
- package/dist/resources/asset-by-id.d.ts +4 -0
- package/dist/resources/asset-by-id.d.ts.map +1 -0
- package/dist/resources/asset-by-id.js +27 -0
- package/dist/resources/asset-by-id.js.map +1 -0
- package/dist/resources/collections.d.ts +5 -0
- package/dist/resources/collections.d.ts.map +1 -0
- package/dist/resources/collections.js +48 -0
- package/dist/resources/collections.js.map +1 -0
- package/dist/resources/custom-fields.d.ts +4 -0
- package/dist/resources/custom-fields.d.ts.map +1 -0
- package/dist/resources/custom-fields.js +30 -0
- package/dist/resources/custom-fields.js.map +1 -0
- package/dist/resources/folders.d.ts +5 -0
- package/dist/resources/folders.d.ts.map +1 -0
- package/dist/resources/folders.js +73 -0
- package/dist/resources/folders.js.map +1 -0
- package/dist/resources/helpers.d.ts +17 -0
- package/dist/resources/helpers.d.ts.map +1 -0
- package/dist/resources/helpers.js +59 -0
- package/dist/resources/helpers.js.map +1 -0
- package/dist/resources/portals.d.ts +5 -0
- package/dist/resources/portals.d.ts.map +1 -0
- package/dist/resources/portals.js +81 -0
- package/dist/resources/portals.js.map +1 -0
- package/dist/resources/recent-and-dashboard.d.ts +5 -0
- package/dist/resources/recent-and-dashboard.d.ts.map +1 -0
- package/dist/resources/recent-and-dashboard.js +42 -0
- package/dist/resources/recent-and-dashboard.js.map +1 -0
- package/dist/tools/asset-selection.d.ts +102 -0
- package/dist/tools/asset-selection.d.ts.map +1 -0
- package/dist/tools/asset-selection.js +133 -0
- package/dist/tools/asset-selection.js.map +1 -0
- package/dist/tools/audit/audit-folder-structure.d.ts +108 -0
- package/dist/tools/audit/audit-folder-structure.d.ts.map +1 -0
- package/dist/tools/audit/audit-folder-structure.js +260 -0
- package/dist/tools/audit/audit-folder-structure.js.map +1 -0
- package/dist/tools/audit/audit-naming-conventions.d.ts +83 -0
- package/dist/tools/audit/audit-naming-conventions.d.ts.map +1 -0
- package/dist/tools/audit/audit-naming-conventions.js +238 -0
- package/dist/tools/audit/audit-naming-conventions.js.map +1 -0
- package/dist/tools/audit/audit-tagging-hygiene.d.ts +77 -0
- package/dist/tools/audit/audit-tagging-hygiene.d.ts.map +1 -0
- package/dist/tools/audit/audit-tagging-hygiene.js +402 -0
- package/dist/tools/audit/audit-tagging-hygiene.js.map +1 -0
- package/dist/tools/audit/detect-duplicates.d.ts +62 -0
- package/dist/tools/audit/detect-duplicates.d.ts.map +1 -0
- package/dist/tools/audit/detect-duplicates.js +0 -0
- package/dist/tools/audit/detect-duplicates.js.map +1 -0
- package/dist/tools/audit/types.d.ts +526 -0
- package/dist/tools/audit/types.d.ts.map +1 -0
- package/dist/tools/audit/types.js +188 -0
- package/dist/tools/audit/types.js.map +1 -0
- package/dist/tools/bulk-move-assets.d.ts +78 -0
- package/dist/tools/bulk-move-assets.d.ts.map +1 -0
- package/dist/tools/bulk-move-assets.js +122 -0
- package/dist/tools/bulk-move-assets.js.map +1 -0
- package/dist/tools/bulk-normalize-filenames.d.ts +62 -0
- package/dist/tools/bulk-normalize-filenames.d.ts.map +1 -0
- package/dist/tools/bulk-normalize-filenames.js +237 -0
- package/dist/tools/bulk-normalize-filenames.js.map +1 -0
- package/dist/tools/bulk-rename-assets.d.ts +79 -0
- package/dist/tools/bulk-rename-assets.d.ts.map +1 -0
- package/dist/tools/bulk-rename-assets.js +139 -0
- package/dist/tools/bulk-rename-assets.js.map +1 -0
- package/dist/tools/bulk-tags.d.ts +107 -0
- package/dist/tools/bulk-tags.d.ts.map +1 -0
- package/dist/tools/bulk-tags.js +220 -0
- package/dist/tools/bulk-tags.js.map +1 -0
- package/dist/tools/client-adapters.d.ts +76 -0
- package/dist/tools/client-adapters.d.ts.map +1 -0
- package/dist/tools/client-adapters.js +648 -0
- package/dist/tools/client-adapters.js.map +1 -0
- package/dist/tools/collection-membership.d.ts +90 -0
- package/dist/tools/collection-membership.d.ts.map +1 -0
- package/dist/tools/collection-membership.js +195 -0
- package/dist/tools/collection-membership.js.map +1 -0
- package/dist/tools/create-collection.d.ts +63 -0
- package/dist/tools/create-collection.d.ts.map +1 -0
- package/dist/tools/create-collection.js +151 -0
- package/dist/tools/create-collection.js.map +1 -0
- package/dist/tools/create-folder.d.ts +46 -0
- package/dist/tools/create-folder.d.ts.map +1 -0
- package/dist/tools/create-folder.js +83 -0
- package/dist/tools/create-folder.js.map +1 -0
- package/dist/tools/create-share-link.d.ts +107 -0
- package/dist/tools/create-share-link.d.ts.map +1 -0
- package/dist/tools/create-share-link.js +239 -0
- package/dist/tools/create-share-link.js.map +1 -0
- package/dist/tools/get-asset-details.d.ts +401 -0
- package/dist/tools/get-asset-details.d.ts.map +1 -0
- package/dist/tools/get-asset-details.js +56 -0
- package/dist/tools/get-asset-details.js.map +1 -0
- package/dist/tools/get-collection.d.ts +126 -0
- package/dist/tools/get-collection.d.ts.map +1 -0
- package/dist/tools/get-collection.js +52 -0
- package/dist/tools/get-collection.js.map +1 -0
- package/dist/tools/get-embed-code.d.ts +195 -0
- package/dist/tools/get-embed-code.d.ts.map +1 -0
- package/dist/tools/get-embed-code.js +214 -0
- package/dist/tools/get-embed-code.js.map +1 -0
- package/dist/tools/insights/analyze-share-links.d.ts +159 -0
- package/dist/tools/insights/analyze-share-links.d.ts.map +1 -0
- package/dist/tools/insights/analyze-share-links.js +314 -0
- package/dist/tools/insights/analyze-share-links.js.map +1 -0
- package/dist/tools/insights/insight-cache.d.ts +36 -0
- package/dist/tools/insights/insight-cache.d.ts.map +1 -0
- package/dist/tools/insights/insight-cache.js +98 -0
- package/dist/tools/insights/insight-cache.js.map +1 -0
- package/dist/tools/insights/report-asset-activation.d.ts +149 -0
- package/dist/tools/insights/report-asset-activation.d.ts.map +1 -0
- package/dist/tools/insights/report-asset-activation.js +380 -0
- package/dist/tools/insights/report-asset-activation.js.map +1 -0
- package/dist/tools/insights/report-stale-assets.d.ts +120 -0
- package/dist/tools/insights/report-stale-assets.d.ts.map +1 -0
- package/dist/tools/insights/report-stale-assets.js +281 -0
- package/dist/tools/insights/report-stale-assets.js.map +1 -0
- package/dist/tools/insights/report-top-assets.d.ts +139 -0
- package/dist/tools/insights/report-top-assets.d.ts.map +1 -0
- package/dist/tools/insights/report-top-assets.js +407 -0
- package/dist/tools/insights/report-top-assets.js.map +1 -0
- package/dist/tools/list-categories.d.ts +127 -0
- package/dist/tools/list-categories.d.ts.map +1 -0
- package/dist/tools/list-categories.js +68 -0
- package/dist/tools/list-categories.js.map +1 -0
- package/dist/tools/list-collections.d.ts +127 -0
- package/dist/tools/list-collections.d.ts.map +1 -0
- package/dist/tools/list-collections.js +53 -0
- package/dist/tools/list-collections.js.map +1 -0
- package/dist/tools/list-custom-fields.d.ts +125 -0
- package/dist/tools/list-custom-fields.d.ts.map +1 -0
- package/dist/tools/list-custom-fields.js +51 -0
- package/dist/tools/list-custom-fields.js.map +1 -0
- package/dist/tools/list-share-links.d.ts +192 -0
- package/dist/tools/list-share-links.d.ts.map +1 -0
- package/dist/tools/list-share-links.js +92 -0
- package/dist/tools/list-share-links.js.map +1 -0
- package/dist/tools/list-workspaces.d.ts +88 -0
- package/dist/tools/list-workspaces.d.ts.map +1 -0
- package/dist/tools/list-workspaces.js +71 -0
- package/dist/tools/list-workspaces.js.map +1 -0
- package/dist/tools/move-asset.d.ts +48 -0
- package/dist/tools/move-asset.d.ts.map +1 -0
- package/dist/tools/move-asset.js +85 -0
- package/dist/tools/move-asset.js.map +1 -0
- package/dist/tools/rename-asset.d.ts +88 -0
- package/dist/tools/rename-asset.d.ts.map +1 -0
- package/dist/tools/rename-asset.js +100 -0
- package/dist/tools/rename-asset.js.map +1 -0
- package/dist/tools/rename-folder.d.ts +55 -0
- package/dist/tools/rename-folder.d.ts.map +1 -0
- package/dist/tools/rename-folder.js +101 -0
- package/dist/tools/rename-folder.js.map +1 -0
- package/dist/tools/revoke-share-link.d.ts +55 -0
- package/dist/tools/revoke-share-link.d.ts.map +1 -0
- package/dist/tools/revoke-share-link.js +77 -0
- package/dist/tools/revoke-share-link.js.map +1 -0
- package/dist/tools/search/facets.d.ts +34 -0
- package/dist/tools/search/facets.d.ts.map +1 -0
- package/dist/tools/search/facets.js +147 -0
- package/dist/tools/search/facets.js.map +1 -0
- package/dist/tools/search/filter-builder.d.ts +33 -0
- package/dist/tools/search/filter-builder.d.ts.map +1 -0
- package/dist/tools/search/filter-builder.js +111 -0
- package/dist/tools/search/filter-builder.js.map +1 -0
- package/dist/tools/search/search-assets.d.ts +41 -0
- package/dist/tools/search/search-assets.d.ts.map +1 -0
- package/dist/tools/search/search-assets.js +162 -0
- package/dist/tools/search/search-assets.js.map +1 -0
- package/dist/tools/search/search-collections.d.ts +35 -0
- package/dist/tools/search/search-collections.d.ts.map +1 -0
- package/dist/tools/search/search-collections.js +103 -0
- package/dist/tools/search/search-collections.js.map +1 -0
- package/dist/tools/search/types.d.ts +1047 -0
- package/dist/tools/search/types.d.ts.map +1 -0
- package/dist/tools/search/types.js +216 -0
- package/dist/tools/search/types.js.map +1 -0
- package/dist/tools/update-asset-metadata.d.ts +78 -0
- package/dist/tools/update-asset-metadata.d.ts.map +1 -0
- package/dist/tools/update-asset-metadata.js +203 -0
- package/dist/tools/update-asset-metadata.js.map +1 -0
- package/dist/tools/update-collection.d.ts +69 -0
- package/dist/tools/update-collection.d.ts.map +1 -0
- package/dist/tools/update-collection.js +142 -0
- package/dist/tools/update-collection.js.map +1 -0
- package/dist/tools/view-category-contents.d.ts +231 -0
- package/dist/tools/view-category-contents.d.ts.map +1 -0
- package/dist/tools/view-category-contents.js +97 -0
- package/dist/tools/view-category-contents.js.map +1 -0
- package/dist/types.d.ts +1326 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +288 -0
- package/dist/types.js.map +1 -0
- package/dist/typesense.d.ts +84 -0
- package/dist/typesense.d.ts.map +1 -0
- package/dist/typesense.js +243 -0
- package/dist/typesense.js.map +1 -0
- package/docs/api-field-verification.md +244 -0
- package/docs/deployment-runbook.md +446 -0
- package/docs/security-review.md +195 -0
- package/docs/typesense-filter-schema.md +262 -0
- package/docs/verified-endpoints.md +38 -0
- package/package.json +72 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Canonical error codes for all MCP tool responses.
|
|
4
|
+
*/
|
|
5
|
+
const ERROR_CODES = [
|
|
6
|
+
'UNAUTHORIZED',
|
|
7
|
+
'FORBIDDEN',
|
|
8
|
+
'NOT_FOUND',
|
|
9
|
+
'VALIDATION',
|
|
10
|
+
'RATE_LIMITED',
|
|
11
|
+
'UPSTREAM',
|
|
12
|
+
'CONFIRMATION_STALE',
|
|
13
|
+
'CONFIRMATION_MISSING',
|
|
14
|
+
'CONFIRMATION_STATE_DIVERGED',
|
|
15
|
+
'ENTITLEMENT',
|
|
16
|
+
'INTERNAL',
|
|
17
|
+
];
|
|
18
|
+
/**
|
|
19
|
+
* Error codes that are retriable by default.
|
|
20
|
+
*/
|
|
21
|
+
const RETRIABLE_CODES = new Set([
|
|
22
|
+
'RATE_LIMITED',
|
|
23
|
+
'UPSTREAM',
|
|
24
|
+
'INTERNAL',
|
|
25
|
+
]);
|
|
26
|
+
export const ErrorCodeSchema = z.enum(ERROR_CODES);
|
|
27
|
+
export const McpToolErrorCauseSchema = z
|
|
28
|
+
.object({
|
|
29
|
+
upstream_status: z.number().int().optional(),
|
|
30
|
+
request_id: z.string().optional(),
|
|
31
|
+
})
|
|
32
|
+
.passthrough();
|
|
33
|
+
export const McpToolErrorSchema = z.object({
|
|
34
|
+
code: ErrorCodeSchema,
|
|
35
|
+
message: z.string(),
|
|
36
|
+
retriable: z.boolean(),
|
|
37
|
+
cause: McpToolErrorCauseSchema.optional(),
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* Returns whether the given error code is retriable by default.
|
|
41
|
+
*/
|
|
42
|
+
export function isRetriable(code) {
|
|
43
|
+
return RETRIABLE_CODES.has(code);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Create a validated McpToolError.
|
|
47
|
+
* If `retriable` is not provided, it defaults based on the error code.
|
|
48
|
+
*/
|
|
49
|
+
export function createToolError(code, message, opts) {
|
|
50
|
+
const error = {
|
|
51
|
+
code,
|
|
52
|
+
message,
|
|
53
|
+
retriable: opts?.retriable ?? isRetriable(code),
|
|
54
|
+
...(opts?.cause !== undefined ? { cause: opts.cause } : {}),
|
|
55
|
+
};
|
|
56
|
+
return McpToolErrorSchema.parse(error);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Map an HTTP status code to the corresponding McpToolError code.
|
|
60
|
+
*/
|
|
61
|
+
export function mapHttpStatusToErrorCode(status) {
|
|
62
|
+
switch (status) {
|
|
63
|
+
case 401:
|
|
64
|
+
return 'UNAUTHORIZED';
|
|
65
|
+
case 403:
|
|
66
|
+
return 'FORBIDDEN';
|
|
67
|
+
case 404:
|
|
68
|
+
return 'NOT_FOUND';
|
|
69
|
+
case 422:
|
|
70
|
+
return 'VALIDATION';
|
|
71
|
+
case 429:
|
|
72
|
+
return 'RATE_LIMITED';
|
|
73
|
+
default: {
|
|
74
|
+
if (status >= 500 && status < 600) {
|
|
75
|
+
return 'UPSTREAM';
|
|
76
|
+
}
|
|
77
|
+
return 'INTERNAL';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/conventions/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,MAAM,WAAW,GAAG;IAClB,cAAc;IACd,WAAW;IACX,WAAW;IACX,YAAY;IACZ,cAAc;IACd,UAAU;IACV,oBAAoB;IACpB,sBAAsB;IACtB,6BAA6B;IAC7B,aAAa;IACb,UAAU;CACF,CAAC;AAEX;;GAEG;AACH,MAAM,eAAe,GAA2B,IAAI,GAAG,CAAC;IACtD,cAAc;IACd,UAAU;IACV,UAAU;CACX,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;AAGnD,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC;KACrC,MAAM,CAAC;IACN,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAC5C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAClC,CAAC;KACD,WAAW,EAAE,CAAC;AAEjB,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,IAAI,EAAE,eAAe;IACrB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;IACtB,KAAK,EAAE,uBAAuB,CAAC,QAAQ,EAAE;CAC1C,CAAC,CAAC;AAIH;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAe;IACzC,OAAO,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC;AAWD;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAe,EACf,OAAe,EACf,IAA0B;IAE1B,MAAM,KAAK,GAAiB;QAC1B,IAAI;QACJ,OAAO;QACP,SAAS,EAAE,IAAI,EAAE,SAAS,IAAI,WAAW,CAAC,IAAI,CAAC;QAC/C,GAAG,CAAC,IAAI,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5D,CAAC;IACF,OAAO,kBAAkB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CAAC,MAAc;IACrD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,GAAG;YACN,OAAO,cAAc,CAAC;QACxB,KAAK,GAAG;YACN,OAAO,WAAW,CAAC;QACrB,KAAK,GAAG;YACN,OAAO,WAAW,CAAC;QACrB,KAAK,GAAG;YACN,OAAO,YAAY,CAAC;QACtB,KAAK,GAAG;YACN,OAAO,cAAc,CAAC;QACxB,OAAO,CAAC,CAAC,CAAC;YACR,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;gBAClC,OAAO,UAAU,CAAC;YACpB,CAAC;YACD,OAAO,UAAU,CAAC;QACpB,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
/**
|
|
3
|
+
* Create a pino logger configured per project conventions:
|
|
4
|
+
* - JSON output written to **stderr** (stdout is reserved for MCP stdio framing)
|
|
5
|
+
* - ISO timestamp in `ts` field
|
|
6
|
+
* - Redaction of credential-bearing paths
|
|
7
|
+
* - Level from LOG_LEVEL env var (default: info)
|
|
8
|
+
*/
|
|
9
|
+
export declare function createLogger(): pino.Logger;
|
|
10
|
+
/**
|
|
11
|
+
* Generate a ULID suitable for use as a request identifier.
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateRequestId(): string;
|
|
14
|
+
/**
|
|
15
|
+
* Create a child logger bound with tool context and a fresh request_id.
|
|
16
|
+
*/
|
|
17
|
+
export declare function createToolLogger(parentLogger: pino.Logger, toolName: string, workspaceId: string): pino.Logger;
|
|
18
|
+
/**
|
|
19
|
+
* Strip sensitive field values from an object before it is logged.
|
|
20
|
+
*
|
|
21
|
+
* Keys matching common filename / metadata patterns are replaced
|
|
22
|
+
* with `[REDACTED]`. Nested objects are processed recursively.
|
|
23
|
+
* The original object is not mutated; a shallow-ish copy is returned.
|
|
24
|
+
*/
|
|
25
|
+
export declare function redactSensitiveFields(obj: Record<string, unknown>): Record<string, unknown>;
|
|
26
|
+
/** Singleton logger instance created once on import. */
|
|
27
|
+
export declare const logger: pino.Logger;
|
|
28
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/conventions/logger.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAiCxB;;;;;;GAMG;AACH,wBAAgB,YAAY,IAAI,IAAI,CAAC,MAAM,CA4B1C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,IAAI,CAAC,MAAM,EACzB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,IAAI,CAAC,MAAM,CAMb;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAYzB;AAMD,wDAAwD;AACxD,eAAO,MAAM,MAAM,EAAE,IAAI,CAAC,MAAuB,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
import { ulid } from 'ulid';
|
|
3
|
+
/**
|
|
4
|
+
* Keys whose values should be replaced with [REDACTED] when logging
|
|
5
|
+
* request/response bodies to avoid leaking filenames and metadata.
|
|
6
|
+
*/
|
|
7
|
+
const SENSITIVE_BODY_KEYS = new Set([
|
|
8
|
+
'file_name',
|
|
9
|
+
'display_file_name',
|
|
10
|
+
'filename',
|
|
11
|
+
'description',
|
|
12
|
+
'custom_fields',
|
|
13
|
+
'metadata',
|
|
14
|
+
]);
|
|
15
|
+
const VALID_LEVELS = new Set([
|
|
16
|
+
'debug',
|
|
17
|
+
'info',
|
|
18
|
+
'warn',
|
|
19
|
+
'error',
|
|
20
|
+
]);
|
|
21
|
+
function resolveLogLevel() {
|
|
22
|
+
const env = process.env['LOG_LEVEL'];
|
|
23
|
+
if (env && VALID_LEVELS.has(env)) {
|
|
24
|
+
return env;
|
|
25
|
+
}
|
|
26
|
+
return 'info';
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Create a pino logger configured per project conventions:
|
|
30
|
+
* - JSON output written to **stderr** (stdout is reserved for MCP stdio framing)
|
|
31
|
+
* - ISO timestamp in `ts` field
|
|
32
|
+
* - Redaction of credential-bearing paths
|
|
33
|
+
* - Level from LOG_LEVEL env var (default: info)
|
|
34
|
+
*/
|
|
35
|
+
export function createLogger() {
|
|
36
|
+
return pino({
|
|
37
|
+
level: resolveLogLevel(),
|
|
38
|
+
timestamp: () => `,"ts":"${new Date().toISOString()}"`,
|
|
39
|
+
redact: {
|
|
40
|
+
paths: [
|
|
41
|
+
'*.api_key',
|
|
42
|
+
'*.apiKey',
|
|
43
|
+
'*.token',
|
|
44
|
+
'*.signed_token',
|
|
45
|
+
'*.confirmation_token',
|
|
46
|
+
'*.password',
|
|
47
|
+
'*.secret',
|
|
48
|
+
'*.authorization',
|
|
49
|
+
'*.Authorization',
|
|
50
|
+
'*.bearer',
|
|
51
|
+
'*.COLLAGE_API_KEY',
|
|
52
|
+
'*.TYPESENSE_API_KEY',
|
|
53
|
+
'*.MCP_CONFIRMATION_SECRET',
|
|
54
|
+
],
|
|
55
|
+
censor: '[REDACTED]',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
// fd 2 = stderr. Required for stdio transport — anything on stdout
|
|
59
|
+
// corrupts JSON-RPC framing and the MCP client will disconnect.
|
|
60
|
+
pino.destination({ fd: 2, sync: false }));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Generate a ULID suitable for use as a request identifier.
|
|
64
|
+
*/
|
|
65
|
+
export function generateRequestId() {
|
|
66
|
+
return ulid();
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Create a child logger bound with tool context and a fresh request_id.
|
|
70
|
+
*/
|
|
71
|
+
export function createToolLogger(parentLogger, toolName, workspaceId) {
|
|
72
|
+
return parentLogger.child({
|
|
73
|
+
tool: toolName,
|
|
74
|
+
workspace_id: workspaceId,
|
|
75
|
+
request_id: generateRequestId(),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Strip sensitive field values from an object before it is logged.
|
|
80
|
+
*
|
|
81
|
+
* Keys matching common filename / metadata patterns are replaced
|
|
82
|
+
* with `[REDACTED]`. Nested objects are processed recursively.
|
|
83
|
+
* The original object is not mutated; a shallow-ish copy is returned.
|
|
84
|
+
*/
|
|
85
|
+
export function redactSensitiveFields(obj) {
|
|
86
|
+
const result = {};
|
|
87
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
88
|
+
if (SENSITIVE_BODY_KEYS.has(key)) {
|
|
89
|
+
result[key] = '[REDACTED]';
|
|
90
|
+
}
|
|
91
|
+
else if (isRecord(value)) {
|
|
92
|
+
result[key] = redactSensitiveFields(value);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
result[key] = value;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
function isRecord(value) {
|
|
101
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
102
|
+
}
|
|
103
|
+
/** Singleton logger instance created once on import. */
|
|
104
|
+
export const logger = createLogger();
|
|
105
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/conventions/logger.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B;;;GAGG;AACH,MAAM,mBAAmB,GAAwB,IAAI,GAAG,CAAC;IACvD,WAAW;IACX,mBAAmB;IACnB,UAAU;IACV,aAAa;IACb,eAAe;IACf,UAAU;CACX,CAAC,CAAC;AAIH,MAAM,YAAY,GAAwB,IAAI,GAAG,CAAS;IACxD,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;CACR,CAAC,CAAC;AAEH,SAAS,eAAe;IACtB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACrC,IAAI,GAAG,IAAI,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QACjC,OAAO,GAAe,CAAC;IACzB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,CACT;QACE,KAAK,EAAE,eAAe,EAAE;QACxB,SAAS,EAAE,GAAG,EAAE,CAAC,UAAU,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,GAAG;QACtD,MAAM,EAAE;YACN,KAAK,EAAE;gBACL,WAAW;gBACX,UAAU;gBACV,SAAS;gBACT,gBAAgB;gBAChB,sBAAsB;gBACtB,YAAY;gBACZ,UAAU;gBACV,iBAAiB;gBACjB,iBAAiB;gBACjB,UAAU;gBACV,mBAAmB;gBACnB,qBAAqB;gBACrB,2BAA2B;aAC5B;YACD,MAAM,EAAE,YAAY;SACrB;KACF;IACD,mEAAmE;IACnE,gEAAgE;IAChE,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CACzC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,IAAI,EAAE,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC9B,YAAyB,EACzB,QAAgB,EAChB,WAAmB;IAEnB,OAAO,YAAY,CAAC,KAAK,CAAC;QACxB,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,WAAW;QACzB,UAAU,EAAE,iBAAiB,EAAE;KAChC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CACnC,GAA4B;IAE5B,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/C,IAAI,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACjC,MAAM,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC;QAC7B,CAAC;aAAM,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,CAAC,GAAG,CAAC,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAC7C,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACtB,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,wDAAwD;AACxD,MAAM,CAAC,MAAM,MAAM,GAAgB,YAAY,EAAE,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const DEFAULT_PAGE_SIZE = 50;
|
|
3
|
+
export declare const MAX_PAGE_SIZE = 500;
|
|
4
|
+
export declare const PaginationParamsSchema: z.ZodObject<{
|
|
5
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
6
|
+
page_size: z.ZodDefault<z.ZodNumber>;
|
|
7
|
+
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
page_size: number;
|
|
9
|
+
cursor?: string | undefined;
|
|
10
|
+
}, {
|
|
11
|
+
cursor?: string | undefined;
|
|
12
|
+
page_size?: number | undefined;
|
|
13
|
+
}>;
|
|
14
|
+
export type PaginationParams = z.infer<typeof PaginationParamsSchema>;
|
|
15
|
+
export declare function paginatedResponseSchema<T extends z.ZodTypeAny>(itemSchema: T): z.ZodObject<{
|
|
16
|
+
items: z.ZodArray<T, "many">;
|
|
17
|
+
next_cursor: z.ZodNullable<z.ZodString>;
|
|
18
|
+
total_estimate: z.ZodNullable<z.ZodNumber>;
|
|
19
|
+
}, "strip", z.ZodTypeAny, {
|
|
20
|
+
items: T["_output"][];
|
|
21
|
+
next_cursor: string | null;
|
|
22
|
+
total_estimate: number | null;
|
|
23
|
+
}, {
|
|
24
|
+
items: T["_input"][];
|
|
25
|
+
next_cursor: string | null;
|
|
26
|
+
total_estimate: number | null;
|
|
27
|
+
}>;
|
|
28
|
+
export type PaginatedResponse<T> = {
|
|
29
|
+
items: T[];
|
|
30
|
+
next_cursor: string | null;
|
|
31
|
+
total_estimate: number | null;
|
|
32
|
+
};
|
|
33
|
+
export declare function encodeCursor(offset: number): string;
|
|
34
|
+
export declare function decodeCursor(cursor: string): number;
|
|
35
|
+
export declare function clampPageSize(requested: number | undefined): number;
|
|
36
|
+
export declare function buildPaginatedResponse<T>(items: T[], offset: number, pageSize: number, totalEstimate: number | null): PaginatedResponse<T>;
|
|
37
|
+
//# sourceMappingURL=pagination.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../src/conventions/pagination.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,aAAa,MAAM,CAAC;AAGjC,eAAO,MAAM,sBAAsB;;;;;;;;;EAGjC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAGtE,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC;;;;;;;;;;;;GAM5E;AAED,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAAI;IACjC,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,CAAC;AAGF,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAWnD;AAGD,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAKnE;AAGD,wBAAgB,sBAAsB,CAAC,CAAC,EACtC,KAAK,EAAE,CAAC,EAAE,EACV,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GAAG,IAAI,GAC3B,iBAAiB,CAAC,CAAC,CAAC,CAWtB"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// ── Constants ──────────────────────────────────────────────────────────
|
|
3
|
+
export const DEFAULT_PAGE_SIZE = 50;
|
|
4
|
+
export const MAX_PAGE_SIZE = 500;
|
|
5
|
+
// ── Input schema ───────────────────────────────────────────────────────
|
|
6
|
+
export const PaginationParamsSchema = z.object({
|
|
7
|
+
cursor: z.string().optional(),
|
|
8
|
+
page_size: z.number().int().min(1).max(MAX_PAGE_SIZE).default(DEFAULT_PAGE_SIZE),
|
|
9
|
+
});
|
|
10
|
+
// ── Response schema factory ────────────────────────────────────────────
|
|
11
|
+
export function paginatedResponseSchema(itemSchema) {
|
|
12
|
+
return z.object({
|
|
13
|
+
items: z.array(itemSchema),
|
|
14
|
+
next_cursor: z.string().nullable(),
|
|
15
|
+
total_estimate: z.number().nullable(),
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
// ── Cursor helpers ─────────────────────────────────────────────────────
|
|
19
|
+
export function encodeCursor(offset) {
|
|
20
|
+
return Buffer.from(String(offset), "utf-8").toString("base64");
|
|
21
|
+
}
|
|
22
|
+
export function decodeCursor(cursor) {
|
|
23
|
+
try {
|
|
24
|
+
const decoded = Buffer.from(cursor, "base64").toString("utf-8");
|
|
25
|
+
const parsed = Number(decoded);
|
|
26
|
+
if (!Number.isFinite(parsed) || parsed < 0 || !Number.isInteger(parsed)) {
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
return parsed;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return 0;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// ── Page-size clamping ─────────────────────────────────────────────────
|
|
36
|
+
export function clampPageSize(requested) {
|
|
37
|
+
if (requested === undefined) {
|
|
38
|
+
return DEFAULT_PAGE_SIZE;
|
|
39
|
+
}
|
|
40
|
+
return Math.max(1, Math.min(requested, MAX_PAGE_SIZE));
|
|
41
|
+
}
|
|
42
|
+
// ── Response builder ───────────────────────────────────────────────────
|
|
43
|
+
export function buildPaginatedResponse(items, offset, pageSize, totalEstimate) {
|
|
44
|
+
const hasMore = totalEstimate !== null
|
|
45
|
+
? offset + pageSize < totalEstimate
|
|
46
|
+
: items.length === pageSize;
|
|
47
|
+
return {
|
|
48
|
+
items,
|
|
49
|
+
next_cursor: hasMore ? encodeCursor(offset + pageSize) : null,
|
|
50
|
+
total_estimate: totalEstimate,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=pagination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../src/conventions/pagination.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,0EAA0E;AAC1E,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AACpC,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAC;AAEjC,0EAA0E;AAC1E,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC;CACjF,CAAC,CAAC;AAIH,0EAA0E;AAC1E,MAAM,UAAU,uBAAuB,CAAyB,UAAa;IAC3E,OAAO,CAAC,CAAC,MAAM,CAAC;QACd,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC;QAC1B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAClC,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KACtC,CAAC,CAAC;AACL,CAAC;AAQD,0EAA0E;AAC1E,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAChE,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YACxE,OAAO,CAAC,CAAC;QACX,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,aAAa,CAAC,SAA6B;IACzD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,sBAAsB,CACpC,KAAU,EACV,MAAc,EACd,QAAgB,EAChB,aAA4B;IAE5B,MAAM,OAAO,GACX,aAAa,KAAK,IAAI;QACpB,CAAC,CAAC,MAAM,GAAG,QAAQ,GAAG,aAAa;QACnC,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC;IAEhC,OAAO;QACL,KAAK;QACL,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI;QAC7D,cAAc,EAAE,aAAa;KAC9B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export interface RetryConfig {
|
|
2
|
+
maxRetries: number;
|
|
3
|
+
baseDelayMs: number;
|
|
4
|
+
maxDelayMs: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Thrown when an upstream 429 or 5xx is encountered.
|
|
8
|
+
* Carries an optional `retryAfterMs` so `withRetry` can honour
|
|
9
|
+
* the server's `Retry-After` header.
|
|
10
|
+
*/
|
|
11
|
+
export declare class RateLimitedError extends Error {
|
|
12
|
+
readonly retryAfterMs: number | undefined;
|
|
13
|
+
readonly statusCode: number;
|
|
14
|
+
constructor(message: string, opts: {
|
|
15
|
+
statusCode: number;
|
|
16
|
+
retryAfterMs?: number;
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A simple sliding-window rate limiter.
|
|
21
|
+
*
|
|
22
|
+
* Tracks timestamps of recent requests within a 1-second window.
|
|
23
|
+
* When the window is full (`maxRps` requests), `acquire()` delays
|
|
24
|
+
* until the oldest timestamp falls outside the window.
|
|
25
|
+
*/
|
|
26
|
+
export declare class TokenBucketRateLimiter {
|
|
27
|
+
private readonly maxRps;
|
|
28
|
+
private readonly timestamps;
|
|
29
|
+
constructor(opts?: {
|
|
30
|
+
maxRps?: number;
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* Wait until a token is available, then record the request.
|
|
34
|
+
*/
|
|
35
|
+
acquire(): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Clear all tracked timestamps (useful in tests).
|
|
38
|
+
*/
|
|
39
|
+
reset(): void;
|
|
40
|
+
/**
|
|
41
|
+
* Remove timestamps older than 1 second from the window.
|
|
42
|
+
*/
|
|
43
|
+
private prune;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Execute `fn`, retrying on retriable errors (429, 5xx) with
|
|
47
|
+
* exponential backoff and jitter.
|
|
48
|
+
*
|
|
49
|
+
* If the error carries a `retryAfterMs` value (from an upstream
|
|
50
|
+
* `Retry-After` header), that value is used instead of the
|
|
51
|
+
* computed backoff — unless it exceeds `maxDelayMs`.
|
|
52
|
+
*/
|
|
53
|
+
export declare function withRetry<T>(fn: () => Promise<T>, config?: Partial<RetryConfig>): Promise<T>;
|
|
54
|
+
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/conventions/rate-limiter.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAUD;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,SAAgB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjD,SAAgB,UAAU,EAAE,MAAM,CAAC;gBAGjC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE;CAOtD;AA2CD;;;;;;GAMG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;gBAE/B,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAItC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB9B;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,OAAO,CAAC,KAAK;CAMd;AAID;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAC5B,OAAO,CAAC,CAAC,CAAC,CA4BZ"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// ── Rate Limiter ─────────────────────────────────────────────────────
|
|
2
|
+
// Token-bucket rate limiter and retry logic for the Collage HTTP client.
|
|
3
|
+
// One limiter instance per workspace; no external dependencies.
|
|
4
|
+
const DEFAULT_RETRY_CONFIG = {
|
|
5
|
+
maxRetries: 3,
|
|
6
|
+
baseDelayMs: 500,
|
|
7
|
+
maxDelayMs: 30_000,
|
|
8
|
+
};
|
|
9
|
+
// ── RateLimitedError ──────────────────────────────────────────────────
|
|
10
|
+
/**
|
|
11
|
+
* Thrown when an upstream 429 or 5xx is encountered.
|
|
12
|
+
* Carries an optional `retryAfterMs` so `withRetry` can honour
|
|
13
|
+
* the server's `Retry-After` header.
|
|
14
|
+
*/
|
|
15
|
+
export class RateLimitedError extends Error {
|
|
16
|
+
retryAfterMs;
|
|
17
|
+
statusCode;
|
|
18
|
+
constructor(message, opts) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.name = 'RateLimitedError';
|
|
21
|
+
this.statusCode = opts.statusCode;
|
|
22
|
+
this.retryAfterMs = opts.retryAfterMs;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// ── Helpers ───────────────────────────────────────────────────────────
|
|
26
|
+
function isRetriableStatus(status) {
|
|
27
|
+
return status === 429 || (status >= 500 && status < 600);
|
|
28
|
+
}
|
|
29
|
+
function isRetriableError(err) {
|
|
30
|
+
return err instanceof RateLimitedError && isRetriableStatus(err.statusCode);
|
|
31
|
+
}
|
|
32
|
+
function delay(ms) {
|
|
33
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Compute jittered exponential backoff delay.
|
|
37
|
+
* Formula: min(baseDelay * 2^attempt + jitter, maxDelay)
|
|
38
|
+
* where jitter is a random value in [0, baseDelay).
|
|
39
|
+
*/
|
|
40
|
+
function computeBackoff(attempt, config) {
|
|
41
|
+
const exponential = config.baseDelayMs * Math.pow(2, attempt);
|
|
42
|
+
const jitter = Math.random() * config.baseDelayMs;
|
|
43
|
+
return Math.min(exponential + jitter, config.maxDelayMs);
|
|
44
|
+
}
|
|
45
|
+
// ── TokenBucketRateLimiter ────────────────────────────────────────────
|
|
46
|
+
function getDefaultMaxRps() {
|
|
47
|
+
const envVal = process.env['COLLAGE_MAX_RPS'];
|
|
48
|
+
if (envVal !== undefined && envVal !== '') {
|
|
49
|
+
const parsed = Number(envVal);
|
|
50
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
51
|
+
return parsed;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return 10;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* A simple sliding-window rate limiter.
|
|
58
|
+
*
|
|
59
|
+
* Tracks timestamps of recent requests within a 1-second window.
|
|
60
|
+
* When the window is full (`maxRps` requests), `acquire()` delays
|
|
61
|
+
* until the oldest timestamp falls outside the window.
|
|
62
|
+
*/
|
|
63
|
+
export class TokenBucketRateLimiter {
|
|
64
|
+
maxRps;
|
|
65
|
+
timestamps = [];
|
|
66
|
+
constructor(opts) {
|
|
67
|
+
this.maxRps = opts?.maxRps ?? getDefaultMaxRps();
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Wait until a token is available, then record the request.
|
|
71
|
+
*/
|
|
72
|
+
async acquire() {
|
|
73
|
+
const now = Date.now();
|
|
74
|
+
// Prune timestamps older than 1 second
|
|
75
|
+
this.prune(now);
|
|
76
|
+
if (this.timestamps.length < this.maxRps) {
|
|
77
|
+
this.timestamps.push(Date.now());
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
// Window is full — wait until the oldest timestamp expires
|
|
81
|
+
const oldest = this.timestamps[0];
|
|
82
|
+
if (oldest !== undefined) {
|
|
83
|
+
const waitMs = oldest + 1000 - now;
|
|
84
|
+
if (waitMs > 0) {
|
|
85
|
+
await delay(waitMs);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// After waiting, prune again and record
|
|
89
|
+
this.prune(Date.now());
|
|
90
|
+
this.timestamps.push(Date.now());
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Clear all tracked timestamps (useful in tests).
|
|
94
|
+
*/
|
|
95
|
+
reset() {
|
|
96
|
+
this.timestamps.length = 0;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Remove timestamps older than 1 second from the window.
|
|
100
|
+
*/
|
|
101
|
+
prune(now) {
|
|
102
|
+
const cutoff = now - 1000;
|
|
103
|
+
while (this.timestamps.length > 0 && (this.timestamps[0] ?? 0) <= cutoff) {
|
|
104
|
+
this.timestamps.shift();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// ── withRetry ─────────────────────────────────────────────────────────
|
|
109
|
+
/**
|
|
110
|
+
* Execute `fn`, retrying on retriable errors (429, 5xx) with
|
|
111
|
+
* exponential backoff and jitter.
|
|
112
|
+
*
|
|
113
|
+
* If the error carries a `retryAfterMs` value (from an upstream
|
|
114
|
+
* `Retry-After` header), that value is used instead of the
|
|
115
|
+
* computed backoff — unless it exceeds `maxDelayMs`.
|
|
116
|
+
*/
|
|
117
|
+
export async function withRetry(fn, config) {
|
|
118
|
+
const resolved = { ...DEFAULT_RETRY_CONFIG, ...config };
|
|
119
|
+
let lastError;
|
|
120
|
+
for (let attempt = 0; attempt <= resolved.maxRetries; attempt++) {
|
|
121
|
+
try {
|
|
122
|
+
return await fn();
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
lastError = err;
|
|
126
|
+
// If it's the last attempt or not retriable, stop retrying.
|
|
127
|
+
if (attempt >= resolved.maxRetries || !isRetriableError(err)) {
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
// Determine how long to wait.
|
|
131
|
+
let waitMs;
|
|
132
|
+
if (err.retryAfterMs !== undefined && err.retryAfterMs > 0) {
|
|
133
|
+
waitMs = Math.min(err.retryAfterMs, resolved.maxDelayMs);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
waitMs = computeBackoff(attempt, resolved);
|
|
137
|
+
}
|
|
138
|
+
await delay(waitMs);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
throw lastError;
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/conventions/rate-limiter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** Soft-warn threshold — log a warning when a single tool response exceeds this. */
|
|
3
|
+
export declare const SOFT_WARN_TOKENS = 4000;
|
|
4
|
+
/** Hard cap — automatically truncate responses that exceed this. */
|
|
5
|
+
export declare const HARD_CAP_TOKENS = 12000;
|
|
6
|
+
/**
|
|
7
|
+
* Rough token-count heuristic for English text.
|
|
8
|
+
*
|
|
9
|
+
* cl100k_base averages ~4 characters per token for typical English /
|
|
10
|
+
* JSON-serialised content. This avoids pulling in the full tiktoken
|
|
11
|
+
* dependency while remaining "good enough" for budget enforcement.
|
|
12
|
+
*/
|
|
13
|
+
export declare function estimateTokens(text: string): number;
|
|
14
|
+
/**
|
|
15
|
+
* Zod schema factory for a budget-wrapped response.
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* const schema = responseBudgetResultSchema(z.array(myItemSchema));
|
|
19
|
+
*/
|
|
20
|
+
export declare function responseBudgetResultSchema<S extends z.ZodTypeAny>(dataSchema: S): z.ZodObject<{
|
|
21
|
+
data: S;
|
|
22
|
+
token_estimate: z.ZodNumber;
|
|
23
|
+
truncated: z.ZodBoolean;
|
|
24
|
+
next_cursor: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
25
|
+
}, "strip", z.ZodTypeAny, z.objectUtil.addQuestionMarks<z.baseObjectOutputType<{
|
|
26
|
+
data: S;
|
|
27
|
+
token_estimate: z.ZodNumber;
|
|
28
|
+
truncated: z.ZodBoolean;
|
|
29
|
+
next_cursor: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
30
|
+
}>, any> extends infer T ? { [k in keyof T]: T[k]; } : never, z.baseObjectInputType<{
|
|
31
|
+
data: S;
|
|
32
|
+
token_estimate: z.ZodNumber;
|
|
33
|
+
truncated: z.ZodBoolean;
|
|
34
|
+
next_cursor: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
35
|
+
}> extends infer T_1 ? { [k_1 in keyof T_1]: T_1[k_1]; } : never>;
|
|
36
|
+
/** Generic type derived from the schema. */
|
|
37
|
+
export interface ResponseBudgetResult<T> {
|
|
38
|
+
data: T;
|
|
39
|
+
token_estimate: number;
|
|
40
|
+
truncated: boolean;
|
|
41
|
+
next_cursor?: string | null;
|
|
42
|
+
}
|
|
43
|
+
export interface ApplyResponseBudgetOpts<T> {
|
|
44
|
+
/** Serialise a single item to the string that will be measured. */
|
|
45
|
+
serialize: (item: T) => string;
|
|
46
|
+
/** Zero-based offset into the original list (for cursor calculation). */
|
|
47
|
+
offset: number;
|
|
48
|
+
/** Maximum number of items the caller originally requested. */
|
|
49
|
+
pageSize: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Walk through `items`, accumulating estimated tokens. If the running
|
|
53
|
+
* total would exceed {@link HARD_CAP_TOKENS}, stop early, mark the
|
|
54
|
+
* response as truncated, and attach a `next_cursor` so the caller can
|
|
55
|
+
* resume.
|
|
56
|
+
*/
|
|
57
|
+
export declare function applyResponseBudget<T>(items: T[], opts: ApplyResponseBudgetOpts<T>): ResponseBudgetResult<T[]>;
|
|
58
|
+
/**
|
|
59
|
+
* Log a warning to stderr when a response exceeds {@link SOFT_WARN_TOKENS}.
|
|
60
|
+
*
|
|
61
|
+
* This intentionally writes to `process.stderr` so it stays out of MCP
|
|
62
|
+
* stdout transport. Will be replaced with pino once the shared logger
|
|
63
|
+
* convention lands.
|
|
64
|
+
*/
|
|
65
|
+
export declare function warnIfOverBudget(tokenEstimate: number, toolName: string): void;
|
|
66
|
+
//# sourceMappingURL=response-budget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-budget.d.ts","sourceRoot":"","sources":["../../src/conventions/response-budget.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,oFAAoF;AACpF,eAAO,MAAM,gBAAgB,OAAQ,CAAC;AAEtC,oEAAoE;AACpE,eAAO,MAAM,eAAe,QAAS,CAAC;AAMtC;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAMD;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC;;;;;;;;;;;;;;;kEAO/E;AAED,4CAA4C;AAC5C,MAAM,WAAW,oBAAoB,CAAC,CAAC;IACrC,IAAI,EAAE,CAAC,CAAC;IACR,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAMD,MAAM,WAAW,uBAAuB,CAAC,CAAC;IACxC,mEAAmE;IACnE,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;IAC/B,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,KAAK,EAAE,CAAC,EAAE,EACV,IAAI,EAAE,uBAAuB,CAAC,CAAC,CAAC,GAC/B,oBAAoB,CAAC,CAAC,EAAE,CAAC,CAgC3B;AAMD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAO9E"}
|