memory-journal-mcp 6.1.2 → 6.2.1
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/README.md +44 -28
- package/dist/{chunk-X4SWFATC.js → chunk-BI4ZNSKA.js} +38 -24
- package/dist/{chunk-HCEWINSB.js → chunk-N6EBIDN7.js} +99 -102
- package/dist/cli.js +2 -2
- package/dist/index.js +2 -2
- package/dist/tools-WPRY5MJ6.js +2 -0
- package/package.json +10 -1
- package/skills/github-commander/SKILL.md +151 -0
- package/skills/github-commander/config/project-config.example.md +125 -0
- package/skills/github-commander/workflows/code-quality-audit.md +80 -0
- package/skills/github-commander/workflows/full-audit.md +134 -0
- package/skills/github-commander/workflows/issue-triage.md +239 -0
- package/skills/github-commander/workflows/milestone-sprint.md +81 -0
- package/skills/github-commander/workflows/perf-audit.md +142 -0
- package/skills/github-commander/workflows/pr-review.md +123 -0
- package/skills/github-commander/workflows/security-audit.md +170 -0
- package/skills/github-commander/workflows/update-deps.md +109 -0
- package/.dockerignore +0 -139
- package/.gitattributes +0 -20
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -95
- package/.github/ISSUE_TEMPLATE/config.yml +0 -11
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -110
- package/.github/ISSUE_TEMPLATE/question.md +0 -78
- package/.github/aw/actions-lock.json +0 -14
- package/.github/copilot-instructions.md +0 -122
- package/.github/dependabot.yml +0 -93
- package/.github/pull_request_template.md +0 -135
- package/.github/workflows/README.md +0 -133
- package/.github/workflows/agentics-maintenance.yml +0 -141
- package/.github/workflows/auto-release.yml +0 -68
- package/.github/workflows/ci-health-monitor.lock.yml +0 -1121
- package/.github/workflows/ci-health-monitor.md +0 -87
- package/.github/workflows/codeql.yml +0 -41
- package/.github/workflows/dependabot-auto-merge.yml +0 -42
- package/.github/workflows/dependency-maintenance.lock.yml +0 -1182
- package/.github/workflows/dependency-maintenance.md +0 -147
- package/.github/workflows/docker-publish.yml +0 -254
- package/.github/workflows/docs-drift-detector.lock.yml +0 -1142
- package/.github/workflows/docs-drift-detector.md +0 -115
- package/.github/workflows/lint-and-test.yml +0 -60
- package/.github/workflows/publish-npm.yml +0 -85
- package/.github/workflows/secrets-scanning.yml +0 -32
- package/.github/workflows/security-update.yml +0 -127
- package/.gitleaks.toml +0 -9
- package/.prettierignore +0 -21
- package/.prettierrc +0 -33
- package/.scout-ignore +0 -12
- package/.trivyignore +0 -21
- package/CHANGELOG.md +0 -1814
- package/CODE_OF_CONDUCT.md +0 -133
- package/CONTRIBUTING.md +0 -263
- package/DOCKER_README.md +0 -331
- package/Dockerfile +0 -128
- package/SECURITY.md +0 -227
- package/UNRELEASED.md +0 -1
- package/dist/tools-T4U5A3X4.js +0 -2
- package/docker-compose.yml +0 -71
- package/docs/README.md +0 -18
- package/docs/agentic-journal-synergy.md +0 -175
- package/docs/copilot-setup.md +0 -72
- package/eslint.config.js +0 -110
- package/mcp-config-example.json +0 -21
- package/playwright.config.ts +0 -35
- package/releases/v2.1.0.md +0 -220
- package/releases/v2.2.0.md +0 -168
- package/releases/v3.0.0.md +0 -237
- package/releases/v3.1.0.md +0 -104
- package/releases/v3.1.1.md +0 -42
- package/releases/v3.1.2.md +0 -40
- package/releases/v3.1.3.md +0 -64
- package/releases/v3.1.4.md +0 -32
- package/releases/v3.1.5.md +0 -44
- package/releases/v4.0.0.md +0 -71
- package/releases/v4.1.0.md +0 -88
- package/releases/v4.2.0.md +0 -90
- package/releases/v4.3.0.md +0 -92
- package/releases/v4.3.1.md +0 -69
- package/releases/v4.4.0.md +0 -120
- package/releases/v4.4.1.md +0 -33
- package/releases/v4.4.2.md +0 -31
- package/releases/v4.5.0.md +0 -116
- package/releases/v5.0.0.md +0 -105
- package/releases/v5.0.1.md +0 -25
- package/releases/v5.1.0.md +0 -83
- package/releases/v5.1.1.md +0 -10
- package/releases/v6.0.0.md +0 -48
- package/releases/v6.0.1.md +0 -36
- package/releases/v6.1.0.md +0 -68
- package/releases/v6.1.1.md +0 -30
- package/releases/v6.1.2.md +0 -23
- package/scripts/generate-server-instructions.ts +0 -306
- package/scripts/server-instructions-function-body.ts +0 -107
- package/scripts/server-instructions-gotchas.ts +0 -45
- package/server.json +0 -42
- package/social-preview.png +0 -0
- package/src/auth/auth-context.ts +0 -78
- package/src/auth/authorization-server-discovery.ts +0 -263
- package/src/auth/errors.ts +0 -215
- package/src/auth/index.ts +0 -58
- package/src/auth/middleware.ts +0 -392
- package/src/auth/oauth-resource-server.ts +0 -170
- package/src/auth/scope-map.ts +0 -46
- package/src/auth/scopes.ts +0 -256
- package/src/auth/token-validator.ts +0 -293
- package/src/auth/transport-agnostic.ts +0 -164
- package/src/auth/types.ts +0 -372
- package/src/cli.ts +0 -279
- package/src/codemode/api-constants.ts +0 -263
- package/src/codemode/api.ts +0 -302
- package/src/codemode/auto-return.ts +0 -65
- package/src/codemode/index.ts +0 -47
- package/src/codemode/sandbox-factory.ts +0 -144
- package/src/codemode/sandbox.ts +0 -220
- package/src/codemode/security.ts +0 -155
- package/src/codemode/types.ts +0 -228
- package/src/codemode/worker-sandbox.ts +0 -277
- package/src/codemode/worker-script.ts +0 -239
- package/src/constants/icons.ts +0 -183
- package/src/constants/server-instructions.md +0 -166
- package/src/constants/server-instructions.ts +0 -514
- package/src/database/adapter-factory.ts +0 -16
- package/src/database/core/entry-columns.ts +0 -10
- package/src/database/core/interfaces.ts +0 -188
- package/src/database/core/schema.ts +0 -152
- package/src/database/sqlite-adapter/backup.ts +0 -167
- package/src/database/sqlite-adapter/entries/crud.ts +0 -233
- package/src/database/sqlite-adapter/entries/importance.ts +0 -76
- package/src/database/sqlite-adapter/entries/index.ts +0 -142
- package/src/database/sqlite-adapter/entries/search.ts +0 -294
- package/src/database/sqlite-adapter/entries/shared.ts +0 -102
- package/src/database/sqlite-adapter/entries/statistics.ts +0 -162
- package/src/database/sqlite-adapter/index.ts +0 -265
- package/src/database/sqlite-adapter/native-connection.ts +0 -301
- package/src/database/sqlite-adapter/relationships.ts +0 -70
- package/src/database/sqlite-adapter/tags.ts +0 -182
- package/src/filtering/tool-filter.ts +0 -312
- package/src/github/github-integration/client.ts +0 -114
- package/src/github/github-integration/index.ts +0 -297
- package/src/github/github-integration/insights.ts +0 -155
- package/src/github/github-integration/issues.ts +0 -213
- package/src/github/github-integration/milestones.ts +0 -262
- package/src/github/github-integration/projects.ts +0 -414
- package/src/github/github-integration/pull-requests.ts +0 -235
- package/src/github/github-integration/repository.ts +0 -110
- package/src/github/github-integration/types.ts +0 -43
- package/src/handlers/prompts/github.ts +0 -210
- package/src/handlers/prompts/index.ts +0 -97
- package/src/handlers/prompts/workflow.ts +0 -361
- package/src/handlers/resources/core/briefing/context-section.ts +0 -182
- package/src/handlers/resources/core/briefing/github-section.ts +0 -354
- package/src/handlers/resources/core/briefing/index.ts +0 -106
- package/src/handlers/resources/core/briefing/user-message.ts +0 -114
- package/src/handlers/resources/core/health.ts +0 -75
- package/src/handlers/resources/core/index.ts +0 -31
- package/src/handlers/resources/core/instructions.ts +0 -45
- package/src/handlers/resources/core/utilities.ts +0 -310
- package/src/handlers/resources/github.ts +0 -340
- package/src/handlers/resources/graph.ts +0 -218
- package/src/handlers/resources/help.ts +0 -410
- package/src/handlers/resources/index.ts +0 -143
- package/src/handlers/resources/shared.ts +0 -219
- package/src/handlers/resources/team.ts +0 -134
- package/src/handlers/resources/templates.ts +0 -334
- package/src/handlers/tools/admin.ts +0 -351
- package/src/handlers/tools/analytics.ts +0 -346
- package/src/handlers/tools/backup.ts +0 -272
- package/src/handlers/tools/codemode.ts +0 -188
- package/src/handlers/tools/core.ts +0 -359
- package/src/handlers/tools/error-fields-mixin.ts +0 -10
- package/src/handlers/tools/export.ts +0 -150
- package/src/handlers/tools/github/copilot-tools.ts +0 -72
- package/src/handlers/tools/github/helpers.ts +0 -125
- package/src/handlers/tools/github/insights-tools.ts +0 -112
- package/src/handlers/tools/github/issue-tools.ts +0 -442
- package/src/handlers/tools/github/kanban-tools.ts +0 -153
- package/src/handlers/tools/github/milestone-tools.ts +0 -371
- package/src/handlers/tools/github/mutation-tools.ts +0 -17
- package/src/handlers/tools/github/read-tools.ts +0 -302
- package/src/handlers/tools/github/schemas.ts +0 -435
- package/src/handlers/tools/github.ts +0 -39
- package/src/handlers/tools/index.ts +0 -255
- package/src/handlers/tools/relationships.ts +0 -390
- package/src/handlers/tools/schemas.ts +0 -165
- package/src/handlers/tools/search.ts +0 -448
- package/src/handlers/tools/team/admin-tools.ts +0 -164
- package/src/handlers/tools/team/analytics-tools.ts +0 -233
- package/src/handlers/tools/team/backup-tools.ts +0 -83
- package/src/handlers/tools/team/core-tools.ts +0 -197
- package/src/handlers/tools/team/export-tools.ts +0 -130
- package/src/handlers/tools/team/helpers.ts +0 -66
- package/src/handlers/tools/team/index.ts +0 -45
- package/src/handlers/tools/team/relationship-tools.ts +0 -219
- package/src/handlers/tools/team/schemas.ts +0 -558
- package/src/handlers/tools/team/search-tools.ts +0 -145
- package/src/handlers/tools/team/vector-tools.ts +0 -261
- package/src/index.ts +0 -57
- package/src/server/mcp-server.ts +0 -446
- package/src/server/registration.ts +0 -141
- package/src/server/scheduler.ts +0 -283
- package/src/transports/http/handlers.ts +0 -78
- package/src/transports/http/index.ts +0 -8
- package/src/transports/http/security.ts +0 -147
- package/src/transports/http/server/index.ts +0 -397
- package/src/transports/http/server/legacy-sse.ts +0 -87
- package/src/transports/http/server/stateful.ts +0 -222
- package/src/transports/http/server/stateless.ts +0 -42
- package/src/transports/http/types.ts +0 -132
- package/src/types/entities.ts +0 -145
- package/src/types/error-types.ts +0 -92
- package/src/types/errors.ts +0 -200
- package/src/types/filtering.ts +0 -55
- package/src/types/github.ts +0 -216
- package/src/types/index.ts +0 -348
- package/src/utils/error-helpers.ts +0 -78
- package/src/utils/errors/error-response-fields.ts +0 -29
- package/src/utils/errors/suggestions.ts +0 -94
- package/src/utils/github-helpers.ts +0 -33
- package/src/utils/logger.ts +0 -107
- package/src/utils/mcp-logger.ts +0 -155
- package/src/utils/progress-utils.ts +0 -100
- package/src/utils/query-helpers.ts +0 -78
- package/src/utils/resource-annotations.ts +0 -75
- package/src/utils/security-utils.ts +0 -198
- package/src/utils/vector-index-helpers.ts +0 -24
- package/src/vector/vector-search-manager.ts +0 -409
- package/src/version.ts +0 -15
- package/test-server/README.md +0 -193
- package/test-server/code-map.md +0 -399
- package/test-server/test-agent-experience.md +0 -213
- package/test-server/test-filter-instructions.mjs +0 -295
- package/test-server/test-instruction-levels.mjs +0 -102
- package/test-server/test-preflight.md +0 -55
- package/test-server/test-prompts.mjs +0 -185
- package/test-server/test-scheduler.mjs +0 -174
- package/test-server/test-tool-annotations.mjs +0 -115
- package/test-server/test-tools-codemode.md +0 -632
- package/test-server/test-tools-codemode2.md +0 -1218
- package/test-server/test-tools-team.md +0 -215
- package/test-server/test-tools.md +0 -429
- package/test-server/test-tools2.md +0 -361
- package/test-server/test-tools3.md +0 -396
- package/test-server/tool-reference.md +0 -231
- package/tests/README.md +0 -54
- package/tests/auth/auth-context.test.ts +0 -162
- package/tests/auth/authorization-server-discovery.test.ts +0 -265
- package/tests/auth/errors.test.ts +0 -170
- package/tests/auth/middleware.test.ts +0 -585
- package/tests/auth/oauth-resource-server.test.ts +0 -173
- package/tests/auth/scope-map.test.ts +0 -66
- package/tests/auth/scopes.test.ts +0 -347
- package/tests/auth/token-validator.test.ts +0 -271
- package/tests/codemode/api.test.ts +0 -396
- package/tests/codemode/auto-return.test.ts +0 -167
- package/tests/codemode/codemode-tool-handlers.test.ts +0 -197
- package/tests/codemode/sandbox-factory.test.ts +0 -152
- package/tests/codemode/sandbox.test.ts +0 -190
- package/tests/codemode/security.test.ts +0 -242
- package/tests/codemode/worker-sandbox.test.ts +0 -106
- package/tests/constants/icons.test.ts +0 -101
- package/tests/constants/server-instructions.test.ts +0 -514
- package/tests/database/crud-workflow-branches.test.ts +0 -418
- package/tests/database/database-branches.test.ts +0 -132
- package/tests/database/entries-auth-branches.test.ts +0 -390
- package/tests/database/native-connection.test.ts +0 -249
- package/tests/database/shared-helpers.test.ts +0 -103
- package/tests/database/sqlite-adapter.bench.ts +0 -63
- package/tests/database/sqlite-adapter.test.ts +0 -690
- package/tests/database/tags.test.ts +0 -134
- package/tests/e2e/README.md +0 -39
- package/tests/e2e/auth.spec.ts +0 -106
- package/tests/e2e/codemode-abuse.spec.ts +0 -75
- package/tests/e2e/health.spec.ts +0 -63
- package/tests/e2e/helpers.ts +0 -139
- package/tests/e2e/oauth-discovery.spec.ts +0 -102
- package/tests/e2e/oauth-scopes.spec.ts +0 -222
- package/tests/e2e/payloads-admin.spec.ts +0 -76
- package/tests/e2e/payloads-analytics.spec.ts +0 -37
- package/tests/e2e/payloads-backup-restore.spec.ts +0 -102
- package/tests/e2e/payloads-backup.spec.ts +0 -44
- package/tests/e2e/payloads-codemode-api.spec.ts +0 -131
- package/tests/e2e/payloads-codemode-readonly.spec.ts +0 -116
- package/tests/e2e/payloads-codemode.spec.ts +0 -116
- package/tests/e2e/payloads-core.spec.ts +0 -82
- package/tests/e2e/payloads-error-contracts.spec.ts +0 -159
- package/tests/e2e/payloads-export.spec.ts +0 -46
- package/tests/e2e/payloads-github-degradation.spec.ts +0 -73
- package/tests/e2e/payloads-github.spec.ts +0 -176
- package/tests/e2e/payloads-relationships.spec.ts +0 -56
- package/tests/e2e/payloads-search.spec.ts +0 -64
- package/tests/e2e/payloads-team-happy.spec.ts +0 -231
- package/tests/e2e/payloads-team.spec.ts +0 -174
- package/tests/e2e/prompts-expanded.spec.ts +0 -137
- package/tests/e2e/prompts.spec.ts +0 -62
- package/tests/e2e/protocols.spec.ts +0 -134
- package/tests/e2e/rate-limiting.spec.ts +0 -291
- package/tests/e2e/resources-briefing-env.spec.ts +0 -106
- package/tests/e2e/resources-complete.spec.ts +0 -180
- package/tests/e2e/resources-expanded.spec.ts +0 -83
- package/tests/e2e/resources-instructions-levels.spec.ts +0 -145
- package/tests/e2e/resources-templates.spec.ts +0 -123
- package/tests/e2e/resources.spec.ts +0 -103
- package/tests/e2e/scheduler.spec.ts +0 -79
- package/tests/e2e/security.spec.ts +0 -112
- package/tests/e2e/session-advanced.spec.ts +0 -152
- package/tests/e2e/sessions.spec.ts +0 -95
- package/tests/e2e/stateless.spec.ts +0 -79
- package/tests/e2e/streaming.spec.ts +0 -176
- package/tests/e2e/tool-filtering-presets.spec.ts +0 -192
- package/tests/e2e/tool-filtering.spec.ts +0 -77
- package/tests/e2e/tools.spec.ts +0 -111
- package/tests/filtering/tool-filter.test.ts +0 -314
- package/tests/github/client-issues-errors.test.ts +0 -433
- package/tests/github/github-integration-branches.test.ts +0 -490
- package/tests/github/github-integration.test.ts +0 -1015
- package/tests/github/github-managers-branches.test.ts +0 -907
- package/tests/github/pull-requests.test.ts +0 -334
- package/tests/handlers/analytics-branches.test.ts +0 -222
- package/tests/handlers/backup-branches.test.ts +0 -270
- package/tests/handlers/briefing-context-section.test.ts +0 -388
- package/tests/handlers/briefing-github-section.test.ts +0 -392
- package/tests/handlers/briefing-user-message.test.ts +0 -405
- package/tests/handlers/codemode-tools.test.ts +0 -85
- package/tests/handlers/copilot-tools.test.ts +0 -126
- package/tests/handlers/error-path-coverage.test.ts +0 -324
- package/tests/handlers/export-tools.test.ts +0 -203
- package/tests/handlers/github-resource-handlers.test.ts +0 -929
- package/tests/handlers/github-tool-handlers.test.ts +0 -1452
- package/tests/handlers/handler-error-branches.test.ts +0 -346
- package/tests/handlers/help-resource.test.ts +0 -92
- package/tests/handlers/prompt-handler-coverage.test.ts +0 -108
- package/tests/handlers/prompt-handlers.test.ts +0 -131
- package/tests/handlers/resource-handler-coverage.test.ts +0 -281
- package/tests/handlers/resource-handlers.test.ts +0 -357
- package/tests/handlers/resource-prompt-branches.test.ts +0 -495
- package/tests/handlers/search-tool-handlers.test.ts +0 -379
- package/tests/handlers/targeted-gap-closure.test.ts +0 -387
- package/tests/handlers/team-admin.test.ts +0 -291
- package/tests/handlers/team-analytics.test.ts +0 -220
- package/tests/handlers/team-core.test.ts +0 -148
- package/tests/handlers/team-data.test.ts +0 -198
- package/tests/handlers/team-relationships.test.ts +0 -271
- package/tests/handlers/team-resource-handlers.test.ts +0 -161
- package/tests/handlers/team-search.test.ts +0 -134
- package/tests/handlers/team-tool-handlers.test.ts +0 -301
- package/tests/handlers/team-vector.test.ts +0 -213
- package/tests/handlers/template-github-branches.test.ts +0 -676
- package/tests/handlers/tool-annotations.test.ts +0 -90
- package/tests/handlers/tool-handler-coverage.test.ts +0 -514
- package/tests/handlers/tool-handlers.test.ts +0 -510
- package/tests/handlers/tool-output-schemas.test.ts +0 -116
- package/tests/handlers/vector-tool-handlers.test.ts +0 -238
- package/tests/security/sql-injection.test.ts +0 -284
- package/tests/server/mcp-server.bench.ts +0 -55
- package/tests/server/mcp-server.test.ts +0 -1326
- package/tests/server/scheduler.test.ts +0 -400
- package/tests/transports/http-legacy-sse.test.ts +0 -275
- package/tests/transports/http-security.test.ts +0 -322
- package/tests/transports/http-stateful.test.ts +0 -487
- package/tests/transports/http-transport-server.test.ts +0 -301
- package/tests/transports/http-transport.test.ts +0 -771
- package/tests/utils/github-helpers.test.ts +0 -58
- package/tests/utils/logger.test.ts +0 -180
- package/tests/utils/mcp-logger.test.ts +0 -211
- package/tests/utils/progress-utils.test.ts +0 -156
- package/tests/utils/query-helpers.test.ts +0 -80
- package/tests/utils/security-utils.test.ts +0 -82
- package/tests/vector/vector-search-branches.test.ts +0 -111
- package/tests/vector/vector-search-manager.test.ts +0 -375
- package/tests/vector/vector-search.bench.ts +0 -48
- package/tsconfig.json +0 -42
- package/tsup.config.ts +0 -19
- package/vitest.config.ts +0 -25
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* memory-journal-mcp — Token Validator Unit Tests
|
|
3
|
-
*
|
|
4
|
-
* Tests for JWT token validation including error handling,
|
|
5
|
-
* scope parsing, and JWKS integration.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
9
|
-
import { TokenValidator, createTokenValidator } from '../../src/auth/token-validator.js'
|
|
10
|
-
import type { TokenValidatorConfig } from '../../src/auth/types.js'
|
|
11
|
-
import { AUTH_ERROR_CODES } from '../../src/auth/errors.js'
|
|
12
|
-
|
|
13
|
-
// Mock jose to avoid real JWKS fetching
|
|
14
|
-
vi.mock('jose', () => ({
|
|
15
|
-
createRemoteJWKSet: vi.fn(() => vi.fn()),
|
|
16
|
-
jwtVerify: vi.fn(),
|
|
17
|
-
errors: {
|
|
18
|
-
JWTExpired: class JWTExpired extends Error {
|
|
19
|
-
constructor() {
|
|
20
|
-
super('JWT expired')
|
|
21
|
-
this.name = 'JWTExpired'
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
JWKSNoMatchingKey: class JWKSNoMatchingKey extends Error {
|
|
25
|
-
constructor() {
|
|
26
|
-
super('No matching key')
|
|
27
|
-
this.name = 'JWKSNoMatchingKey'
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
JWSSignatureVerificationFailed: class JWSSignatureVerificationFailed extends Error {
|
|
31
|
-
constructor() {
|
|
32
|
-
super('Signature failed')
|
|
33
|
-
this.name = 'JWSSignatureVerificationFailed'
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
JWTClaimValidationFailed: class JWTClaimValidationFailed extends Error {
|
|
37
|
-
constructor() {
|
|
38
|
-
super('Claim validation failed')
|
|
39
|
-
this.name = 'JWTClaimValidationFailed'
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
}))
|
|
44
|
-
|
|
45
|
-
describe('TokenValidator', () => {
|
|
46
|
-
let config: TokenValidatorConfig
|
|
47
|
-
|
|
48
|
-
beforeEach(() => {
|
|
49
|
-
vi.clearAllMocks()
|
|
50
|
-
config = {
|
|
51
|
-
jwksUri: 'https://auth.example.com/.well-known/jwks.json',
|
|
52
|
-
issuer: 'https://auth.example.com',
|
|
53
|
-
audience: 'memory-journal-mcp',
|
|
54
|
-
}
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
describe('construction', () => {
|
|
58
|
-
it('should create instance with config', () => {
|
|
59
|
-
const validator = new TokenValidator(config)
|
|
60
|
-
expect(validator).toBeInstanceOf(TokenValidator)
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
it('should apply default clockTolerance', () => {
|
|
64
|
-
const validator = new TokenValidator(config)
|
|
65
|
-
expect(validator).toBeDefined()
|
|
66
|
-
})
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
describe('createTokenValidator factory', () => {
|
|
70
|
-
it('should create TokenValidator instance', () => {
|
|
71
|
-
const validator = createTokenValidator(config)
|
|
72
|
-
expect(validator).toBeInstanceOf(TokenValidator)
|
|
73
|
-
})
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
describe('validate', () => {
|
|
77
|
-
it('should validate token and return claims on success', async () => {
|
|
78
|
-
const { jwtVerify } = await import('jose')
|
|
79
|
-
const mockVerify = vi.mocked(jwtVerify)
|
|
80
|
-
|
|
81
|
-
const mockPayload = {
|
|
82
|
-
sub: 'user-1',
|
|
83
|
-
iss: 'https://auth.example.com',
|
|
84
|
-
aud: 'memory-journal-mcp',
|
|
85
|
-
exp: Math.floor(Date.now() / 1000) + 3600,
|
|
86
|
-
iat: Math.floor(Date.now() / 1000),
|
|
87
|
-
scope: 'read write',
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
mockVerify.mockResolvedValueOnce({
|
|
91
|
-
payload: mockPayload,
|
|
92
|
-
protectedHeader: { alg: 'RS256' },
|
|
93
|
-
} as never)
|
|
94
|
-
|
|
95
|
-
const validator = new TokenValidator(config)
|
|
96
|
-
const result = await validator.validate('valid-jwt-token')
|
|
97
|
-
|
|
98
|
-
expect(result.valid).toBe(true)
|
|
99
|
-
expect(result.claims).toBeDefined()
|
|
100
|
-
expect(result.claims?.sub).toBe('user-1')
|
|
101
|
-
expect(result.claims?.scopes).toEqual(['read', 'write'])
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
it('should return invalid for expired tokens', async () => {
|
|
105
|
-
const { jwtVerify, errors } = await import('jose')
|
|
106
|
-
const mockVerify = vi.mocked(jwtVerify)
|
|
107
|
-
|
|
108
|
-
const mockError = Object.create(errors.JWTExpired.prototype) as Error
|
|
109
|
-
mockError.message = 'JWT expired'
|
|
110
|
-
mockError.name = 'JWTExpired'
|
|
111
|
-
|
|
112
|
-
mockVerify.mockRejectedValueOnce(mockError)
|
|
113
|
-
|
|
114
|
-
const validator = new TokenValidator(config)
|
|
115
|
-
const result = await validator.validate('expired-token')
|
|
116
|
-
|
|
117
|
-
expect(result.valid).toBe(false)
|
|
118
|
-
expect(result.error).toBeDefined()
|
|
119
|
-
expect(result.errorCode).toBe(AUTH_ERROR_CODES.TOKEN_EXPIRED)
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
it('should handle signature verification failure', async () => {
|
|
123
|
-
const { jwtVerify, errors } = await import('jose')
|
|
124
|
-
const mockVerify = vi.mocked(jwtVerify)
|
|
125
|
-
|
|
126
|
-
const mockError = Object.create(
|
|
127
|
-
errors.JWSSignatureVerificationFailed.prototype
|
|
128
|
-
) as Error
|
|
129
|
-
mockError.message = 'Signature failed'
|
|
130
|
-
mockError.name = 'JWSSignatureVerificationFailed'
|
|
131
|
-
|
|
132
|
-
mockVerify.mockRejectedValueOnce(mockError)
|
|
133
|
-
|
|
134
|
-
const validator = new TokenValidator(config)
|
|
135
|
-
const result = await validator.validate('bad-sig-token')
|
|
136
|
-
|
|
137
|
-
expect(result.valid).toBe(false)
|
|
138
|
-
expect(result.errorCode).toBe(AUTH_ERROR_CODES.SIGNATURE_INVALID)
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
it('should handle claim validation failure', async () => {
|
|
142
|
-
const { jwtVerify, errors } = await import('jose')
|
|
143
|
-
const mockVerify = vi.mocked(jwtVerify)
|
|
144
|
-
|
|
145
|
-
const mockError = Object.create(errors.JWTClaimValidationFailed.prototype) as Error
|
|
146
|
-
mockError.message = 'Claim validation failed'
|
|
147
|
-
mockError.name = 'JWTClaimValidationFailed'
|
|
148
|
-
|
|
149
|
-
mockVerify.mockRejectedValueOnce(mockError)
|
|
150
|
-
|
|
151
|
-
const validator = new TokenValidator(config)
|
|
152
|
-
const result = await validator.validate('bad-claims-token')
|
|
153
|
-
|
|
154
|
-
expect(result.valid).toBe(false)
|
|
155
|
-
expect(result.errorCode).toBe(AUTH_ERROR_CODES.TOKEN_INVALID)
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
it('should handle no matching key in JWKS', async () => {
|
|
159
|
-
const { jwtVerify, errors } = await import('jose')
|
|
160
|
-
const mockVerify = vi.mocked(jwtVerify)
|
|
161
|
-
|
|
162
|
-
const mockError = Object.create(errors.JWKSNoMatchingKey.prototype) as Error
|
|
163
|
-
mockError.message = 'No matching key'
|
|
164
|
-
mockError.name = 'JWKSNoMatchingKey'
|
|
165
|
-
|
|
166
|
-
mockVerify.mockRejectedValueOnce(mockError)
|
|
167
|
-
|
|
168
|
-
const validator = new TokenValidator(config)
|
|
169
|
-
const result = await validator.validate('no-matching-key-token')
|
|
170
|
-
|
|
171
|
-
expect(result.valid).toBe(false)
|
|
172
|
-
expect(result.errorCode).toBe(AUTH_ERROR_CODES.TOKEN_INVALID)
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
it('should handle unknown errors', async () => {
|
|
176
|
-
const { jwtVerify } = await import('jose')
|
|
177
|
-
const mockVerify = vi.mocked(jwtVerify)
|
|
178
|
-
|
|
179
|
-
mockVerify.mockRejectedValueOnce(new Error('Unknown error'))
|
|
180
|
-
|
|
181
|
-
const validator = new TokenValidator(config)
|
|
182
|
-
const result = await validator.validate('unknown-error-token')
|
|
183
|
-
|
|
184
|
-
expect(result.valid).toBe(false)
|
|
185
|
-
expect(result.errorCode).toBe(AUTH_ERROR_CODES.TOKEN_INVALID)
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
it('should parse scope claim as string', async () => {
|
|
189
|
-
const { jwtVerify } = await import('jose')
|
|
190
|
-
const mockVerify = vi.mocked(jwtVerify)
|
|
191
|
-
|
|
192
|
-
mockVerify.mockResolvedValueOnce({
|
|
193
|
-
payload: {
|
|
194
|
-
sub: 'user-1',
|
|
195
|
-
scope: 'read admin',
|
|
196
|
-
exp: Math.floor(Date.now() / 1000) + 3600,
|
|
197
|
-
iat: Math.floor(Date.now() / 1000),
|
|
198
|
-
},
|
|
199
|
-
protectedHeader: { alg: 'RS256' },
|
|
200
|
-
} as never)
|
|
201
|
-
|
|
202
|
-
const validator = new TokenValidator(config)
|
|
203
|
-
const result = await validator.validate('scope-token')
|
|
204
|
-
|
|
205
|
-
expect(result.valid).toBe(true)
|
|
206
|
-
expect(result.claims?.scopes).toEqual(['read', 'admin'])
|
|
207
|
-
})
|
|
208
|
-
|
|
209
|
-
it('should parse scopes claim as array', async () => {
|
|
210
|
-
const { jwtVerify } = await import('jose')
|
|
211
|
-
const mockVerify = vi.mocked(jwtVerify)
|
|
212
|
-
|
|
213
|
-
mockVerify.mockResolvedValueOnce({
|
|
214
|
-
payload: {
|
|
215
|
-
sub: 'user-2',
|
|
216
|
-
scopes: ['write', 'admin'],
|
|
217
|
-
exp: Math.floor(Date.now() / 1000) + 3600,
|
|
218
|
-
iat: Math.floor(Date.now() / 1000),
|
|
219
|
-
},
|
|
220
|
-
protectedHeader: { alg: 'RS256' },
|
|
221
|
-
} as never)
|
|
222
|
-
|
|
223
|
-
const validator = new TokenValidator(config)
|
|
224
|
-
const result = await validator.validate('array-scope-token')
|
|
225
|
-
|
|
226
|
-
expect(result.valid).toBe(true)
|
|
227
|
-
expect(result.claims?.scopes).toEqual(['write', 'admin'])
|
|
228
|
-
})
|
|
229
|
-
})
|
|
230
|
-
|
|
231
|
-
describe('cache management', () => {
|
|
232
|
-
it('should clear cache', () => {
|
|
233
|
-
const validator = new TokenValidator(config)
|
|
234
|
-
expect(() => validator.clearCache()).not.toThrow()
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
it('should refresh JWKS', () => {
|
|
238
|
-
const validator = new TokenValidator(config)
|
|
239
|
-
expect(() => validator.refreshJwks()).not.toThrow()
|
|
240
|
-
})
|
|
241
|
-
})
|
|
242
|
-
|
|
243
|
-
describe('toOAuthError', () => {
|
|
244
|
-
it('should convert expired error code to TokenExpiredError', () => {
|
|
245
|
-
const error = TokenValidator.toOAuthError({
|
|
246
|
-
valid: false,
|
|
247
|
-
error: 'Token has expired',
|
|
248
|
-
errorCode: AUTH_ERROR_CODES.TOKEN_EXPIRED,
|
|
249
|
-
})
|
|
250
|
-
expect(error.name).toBe('TokenExpiredError')
|
|
251
|
-
})
|
|
252
|
-
|
|
253
|
-
it('should convert signature error code to InvalidSignatureError', () => {
|
|
254
|
-
const error = TokenValidator.toOAuthError({
|
|
255
|
-
valid: false,
|
|
256
|
-
error: 'Signature failed',
|
|
257
|
-
errorCode: AUTH_ERROR_CODES.SIGNATURE_INVALID,
|
|
258
|
-
})
|
|
259
|
-
expect(error.name).toBe('InvalidSignatureError')
|
|
260
|
-
})
|
|
261
|
-
|
|
262
|
-
it('should convert generic error to InvalidTokenError', () => {
|
|
263
|
-
const error = TokenValidator.toOAuthError({
|
|
264
|
-
valid: false,
|
|
265
|
-
error: 'Something went wrong',
|
|
266
|
-
errorCode: AUTH_ERROR_CODES.TOKEN_INVALID,
|
|
267
|
-
})
|
|
268
|
-
expect(error.name).toBe('InvalidTokenError')
|
|
269
|
-
})
|
|
270
|
-
})
|
|
271
|
-
})
|
|
@@ -1,396 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Code Mode API Bridge Tests
|
|
3
|
-
*
|
|
4
|
-
* Tests for JournalApi, toolNameToMethodName, and createSandboxBindings:
|
|
5
|
-
* - Tool name → camelCase conversion
|
|
6
|
-
* - Group API creation
|
|
7
|
-
* - Positional argument support
|
|
8
|
-
* - Method aliases
|
|
9
|
-
* - help() discoverability
|
|
10
|
-
* - Top-level aliases
|
|
11
|
-
* - Codemode tool exclusion (no recursion)
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
15
|
-
import { JournalApi, toolNameToMethodName, createJournalApi } from '../../src/codemode/api.js'
|
|
16
|
-
import type { ToolDefinition } from '../../src/types/index.js'
|
|
17
|
-
|
|
18
|
-
// =============================================================================
|
|
19
|
-
// Test Fixtures
|
|
20
|
-
// =============================================================================
|
|
21
|
-
|
|
22
|
-
function createMockTool(
|
|
23
|
-
name: string,
|
|
24
|
-
group: string,
|
|
25
|
-
handler?: (params: unknown) => unknown
|
|
26
|
-
): ToolDefinition {
|
|
27
|
-
return {
|
|
28
|
-
name,
|
|
29
|
-
title: name,
|
|
30
|
-
description: `Test tool: ${name}`,
|
|
31
|
-
group: group as ToolDefinition['group'],
|
|
32
|
-
inputSchema: {} as ToolDefinition['inputSchema'],
|
|
33
|
-
outputSchema: {} as ToolDefinition['outputSchema'],
|
|
34
|
-
annotations: { readOnlyHint: true },
|
|
35
|
-
handler: handler ?? ((params: unknown) => Promise.resolve({ success: true, params })),
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function createMinimalToolSet(): ToolDefinition[] {
|
|
40
|
-
return [
|
|
41
|
-
createMockTool('create_entry', 'core'),
|
|
42
|
-
createMockTool('create_entry_minimal', 'core'),
|
|
43
|
-
createMockTool('get_entry_by_id', 'core'),
|
|
44
|
-
createMockTool('get_recent_entries', 'core'),
|
|
45
|
-
createMockTool('search_entries', 'search'),
|
|
46
|
-
createMockTool('semantic_search', 'search'),
|
|
47
|
-
createMockTool('get_statistics', 'analytics'),
|
|
48
|
-
createMockTool('link_entries', 'relationships'),
|
|
49
|
-
createMockTool('export_entries', 'export'),
|
|
50
|
-
createMockTool('update_entry', 'admin'),
|
|
51
|
-
createMockTool('delete_entry', 'admin'),
|
|
52
|
-
createMockTool('get_github_issues', 'github'),
|
|
53
|
-
createMockTool('backup_journal', 'backup'),
|
|
54
|
-
createMockTool('team_create_entry', 'team'),
|
|
55
|
-
]
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// =============================================================================
|
|
59
|
-
// toolNameToMethodName
|
|
60
|
-
// =============================================================================
|
|
61
|
-
|
|
62
|
-
describe('toolNameToMethodName', () => {
|
|
63
|
-
it('should convert snake_case to camelCase', () => {
|
|
64
|
-
expect(toolNameToMethodName('create_entry', 'core')).toBe('createEntry')
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
it('should handle multi-word names', () => {
|
|
68
|
-
expect(toolNameToMethodName('get_recent_entries', 'core')).toBe('getRecentEntries')
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
it('should handle single-word names', () => {
|
|
72
|
-
expect(toolNameToMethodName('export_entries', 'export')).toBe('exportEntries')
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
it('should keep prefix for github tools', () => {
|
|
76
|
-
expect(toolNameToMethodName('get_github_issues', 'github')).toBe('getGithubIssues')
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
it('should keep prefix for team tools', () => {
|
|
80
|
-
expect(toolNameToMethodName('team_create_entry', 'team')).toBe('teamCreateEntry')
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
it('should handle search tools', () => {
|
|
84
|
-
expect(toolNameToMethodName('search_entries', 'search')).toBe('searchEntries')
|
|
85
|
-
expect(toolNameToMethodName('semantic_search', 'search')).toBe('semanticSearch')
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
it('should handle admin tools', () => {
|
|
89
|
-
expect(toolNameToMethodName('update_entry', 'admin')).toBe('updateEntry')
|
|
90
|
-
expect(toolNameToMethodName('delete_entry', 'admin')).toBe('deleteEntry')
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
it('should handle backup tools', () => {
|
|
94
|
-
expect(toolNameToMethodName('backup_journal', 'backup')).toBe('backupJournal')
|
|
95
|
-
expect(toolNameToMethodName('list_backups', 'backup')).toBe('listBackups')
|
|
96
|
-
})
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
// =============================================================================
|
|
100
|
-
// JournalApi
|
|
101
|
-
// =============================================================================
|
|
102
|
-
|
|
103
|
-
describe('JournalApi', () => {
|
|
104
|
-
let api: JournalApi
|
|
105
|
-
|
|
106
|
-
beforeEach(() => {
|
|
107
|
-
api = new JournalApi(createMinimalToolSet())
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
// =========================================================================
|
|
111
|
-
// Group Creation
|
|
112
|
-
// =========================================================================
|
|
113
|
-
|
|
114
|
-
describe('group creation', () => {
|
|
115
|
-
it('should create all 9 group namespaces', () => {
|
|
116
|
-
expect(api.core).toBeDefined()
|
|
117
|
-
expect(api.search).toBeDefined()
|
|
118
|
-
expect(api.analytics).toBeDefined()
|
|
119
|
-
expect(api.relationships).toBeDefined()
|
|
120
|
-
expect(api.export).toBeDefined()
|
|
121
|
-
expect(api.admin).toBeDefined()
|
|
122
|
-
expect(api.github).toBeDefined()
|
|
123
|
-
expect(api.backup).toBeDefined()
|
|
124
|
-
expect(api.team).toBeDefined()
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
it('should populate groups with methods', () => {
|
|
128
|
-
expect(typeof api.core['createEntry']).toBe('function')
|
|
129
|
-
expect(typeof api.search['searchEntries']).toBe('function')
|
|
130
|
-
expect(typeof api.analytics['getStatistics']).toBe('function')
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
it('should exclude codemode tools', () => {
|
|
134
|
-
const toolsWithCodemode = [
|
|
135
|
-
...createMinimalToolSet(),
|
|
136
|
-
createMockTool('mj_execute_code', 'codemode'),
|
|
137
|
-
]
|
|
138
|
-
const apiWithCodemode = new JournalApi(toolsWithCodemode)
|
|
139
|
-
// Codemode group should not appear in groups
|
|
140
|
-
expect(apiWithCodemode.getGroups()).not.toContain('codemode')
|
|
141
|
-
})
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
// =========================================================================
|
|
145
|
-
// Method Invocation
|
|
146
|
-
// =========================================================================
|
|
147
|
-
|
|
148
|
-
describe('method invocation', () => {
|
|
149
|
-
it('should call handler with object params', async () => {
|
|
150
|
-
const result = await api.core['createEntry']!({ content: 'test' })
|
|
151
|
-
expect(result).toBeDefined()
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
it('should call handler with positional string arg', async () => {
|
|
155
|
-
const handler = vi.fn().mockResolvedValue({ success: true })
|
|
156
|
-
const tools = [createMockTool('create_entry', 'core', handler)]
|
|
157
|
-
const testApi = new JournalApi(tools)
|
|
158
|
-
await testApi.core['createEntry']!('My note')
|
|
159
|
-
expect(handler).toHaveBeenCalledWith({ content: 'My note' })
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
it('should call handler with positional number arg', async () => {
|
|
163
|
-
const handler = vi.fn().mockResolvedValue({ success: true })
|
|
164
|
-
const tools = [createMockTool('get_entry_by_id', 'core', handler)]
|
|
165
|
-
const testApi = new JournalApi(tools)
|
|
166
|
-
await testApi.core['getEntryById']!(42)
|
|
167
|
-
expect(handler).toHaveBeenCalledWith({ entry_id: 42 })
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
it('should pass through empty params for no-arg calls', async () => {
|
|
171
|
-
const handler = vi.fn().mockResolvedValue({ success: true })
|
|
172
|
-
const tools = [createMockTool('get_statistics', 'analytics', handler)]
|
|
173
|
-
const testApi = new JournalApi(tools)
|
|
174
|
-
await testApi.analytics['getStatistics']!()
|
|
175
|
-
expect(handler).toHaveBeenCalledWith({})
|
|
176
|
-
})
|
|
177
|
-
|
|
178
|
-
it('should handle boolean positional args mapped properly', async () => {
|
|
179
|
-
const handler = vi.fn().mockResolvedValue({ success: true })
|
|
180
|
-
const tools = [createMockTool('test_boolean', 'core', handler)] // assume no mapped param, fallback to arg
|
|
181
|
-
const testApi = new JournalApi(tools)
|
|
182
|
-
await testApi.core['testBoolean']!(true)
|
|
183
|
-
expect(handler).toHaveBeenCalledWith(true) // Fallback when no POSITIONAL_PARAM_MAP exists
|
|
184
|
-
})
|
|
185
|
-
|
|
186
|
-
it('should handle positional array mapping with length > 0 for a single arg', async () => {
|
|
187
|
-
const handler = vi.fn().mockResolvedValue({ success: true })
|
|
188
|
-
const tools = [createMockTool('search_by_date_range', 'search', handler)]
|
|
189
|
-
const testApi = new JournalApi(tools)
|
|
190
|
-
// searchByDateRange -> ['start_date', 'end_date']
|
|
191
|
-
// Passing 1 arg should map just 'start_date'
|
|
192
|
-
await testApi.search['searchByDateRange']!('2026-03-01')
|
|
193
|
-
expect(handler).toHaveBeenCalledWith({ start_date: '2026-03-01' })
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
it('should fallback to {content, query} for unmapped string args', async () => {
|
|
197
|
-
const handler = vi.fn().mockResolvedValue({ success: true })
|
|
198
|
-
const tools = [createMockTool('unknown_string_tool', 'core', handler)]
|
|
199
|
-
const testApi = new JournalApi(tools)
|
|
200
|
-
await testApi.core['unknownStringTool']!('some query string')
|
|
201
|
-
expect(handler).toHaveBeenCalledWith({
|
|
202
|
-
content: 'some query string',
|
|
203
|
-
query: 'some query string',
|
|
204
|
-
})
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
it('should return arg[0] if mapping is undefined for multi-arg calls', async () => {
|
|
208
|
-
const handler = vi.fn().mockResolvedValue({ success: true })
|
|
209
|
-
const tools = [createMockTool('unknown_multi_tool', 'core', handler)]
|
|
210
|
-
const testApi = new JournalApi(tools)
|
|
211
|
-
await testApi.core['unknownMultiTool']!('arg1', 'arg2', 'arg3')
|
|
212
|
-
expect(handler).toHaveBeenCalledWith('arg1')
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
it('should map multiple positional args correctly using Array mapping', async () => {
|
|
216
|
-
const handler = vi.fn().mockResolvedValue({ success: true })
|
|
217
|
-
const tools = [createMockTool('link_entries', 'relationships', handler)]
|
|
218
|
-
const testApi = new JournalApi(tools)
|
|
219
|
-
// POSITIONAL_PARAM_MAP['link_entries'] is ['from_entry_id', 'to_entry_id', 'relationship_type']
|
|
220
|
-
await testApi.relationships['linkEntries']!(1, 2, 'blocks', {
|
|
221
|
-
description: 'test options',
|
|
222
|
-
})
|
|
223
|
-
expect(handler).toHaveBeenCalledWith({
|
|
224
|
-
from_entry_id: 1,
|
|
225
|
-
to_entry_id: 2,
|
|
226
|
-
relationship_type: 'blocks',
|
|
227
|
-
description: 'test options',
|
|
228
|
-
})
|
|
229
|
-
})
|
|
230
|
-
|
|
231
|
-
it('should merge trailing options correctly for single string mapping with multi-args', async () => {
|
|
232
|
-
const handler = vi.fn().mockResolvedValue({ success: true })
|
|
233
|
-
const tools = [createMockTool('search_entries', 'search', handler)]
|
|
234
|
-
const testApi = new JournalApi(tools)
|
|
235
|
-
await testApi.search['searchEntries']!('query text', { limit: 10 })
|
|
236
|
-
expect(handler).toHaveBeenCalledWith({ query: 'query text', limit: 10 })
|
|
237
|
-
})
|
|
238
|
-
|
|
239
|
-
it('should merge trailing options object for multi-arg calls', async () => {
|
|
240
|
-
const handler = vi.fn().mockResolvedValue({ success: true })
|
|
241
|
-
const tools = [createMockTool('search_entries', 'search', handler)]
|
|
242
|
-
const testApi = new JournalApi(tools)
|
|
243
|
-
// search_entries maps first pos arg to "query"
|
|
244
|
-
await testApi.search['searchEntries']!('test', { tags: ['a'] })
|
|
245
|
-
expect(handler).toHaveBeenCalledWith({ query: 'test', tags: ['a'] })
|
|
246
|
-
})
|
|
247
|
-
|
|
248
|
-
it('should handle normalizeParams edge cases with arrays', async () => {
|
|
249
|
-
const handler = vi.fn().mockResolvedValue({ success: true })
|
|
250
|
-
const tools = [createMockTool('search_entries', 'search', handler)]
|
|
251
|
-
const testApi = new JournalApi(tools)
|
|
252
|
-
await testApi.search['searchEntries']!([
|
|
253
|
-
'array arg does not become query',
|
|
254
|
-
'or options merge in certain branches',
|
|
255
|
-
])
|
|
256
|
-
// The first argument is an array, so positional checks might just pass it or fail gracefully. Wait, search_entries maps first arg to "query", but if arg is an array, it skips single-primitive checks and tries to merge if there is a positional param map string.
|
|
257
|
-
// For a single array arg, it just passes it through right?
|
|
258
|
-
expect(handler).toHaveBeenCalled()
|
|
259
|
-
})
|
|
260
|
-
})
|
|
261
|
-
|
|
262
|
-
// =========================================================================
|
|
263
|
-
// Aliases
|
|
264
|
-
// =========================================================================
|
|
265
|
-
|
|
266
|
-
describe('method aliases', () => {
|
|
267
|
-
it('should have core aliases', () => {
|
|
268
|
-
expect(api.core['create']).toBeDefined()
|
|
269
|
-
expect(api.core['create']).toBe(api.core['createEntry'])
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
it('should have search aliases', () => {
|
|
273
|
-
expect(api.search['find']).toBeDefined()
|
|
274
|
-
expect(api.search['find']).toBe(api.search['searchEntries'])
|
|
275
|
-
})
|
|
276
|
-
|
|
277
|
-
it('should have backup aliases', () => {
|
|
278
|
-
expect(api.backup['save']).toBeDefined()
|
|
279
|
-
expect(api.backup['save']).toBe(api.backup['backupJournal'])
|
|
280
|
-
})
|
|
281
|
-
})
|
|
282
|
-
|
|
283
|
-
// =========================================================================
|
|
284
|
-
// help()
|
|
285
|
-
// =========================================================================
|
|
286
|
-
|
|
287
|
-
describe('help()', () => {
|
|
288
|
-
it('should provide group-level help', async () => {
|
|
289
|
-
const help = (await api.core['help']!()) as {
|
|
290
|
-
group: string
|
|
291
|
-
methods: string[]
|
|
292
|
-
examples: string[]
|
|
293
|
-
}
|
|
294
|
-
expect(help.group).toBe('core')
|
|
295
|
-
expect(help.methods).toContain('createEntry')
|
|
296
|
-
expect(help.methods).not.toContain('help') // help itself is excluded
|
|
297
|
-
})
|
|
298
|
-
|
|
299
|
-
it('should include examples in help output', async () => {
|
|
300
|
-
const help = (await api.core['help']!()) as { examples: string[] }
|
|
301
|
-
expect(help.examples.length).toBeGreaterThan(0)
|
|
302
|
-
expect(help.examples.some((e) => e.includes('createEntry'))).toBe(true)
|
|
303
|
-
})
|
|
304
|
-
})
|
|
305
|
-
|
|
306
|
-
// =========================================================================
|
|
307
|
-
// getGroups / getGroupMethods
|
|
308
|
-
// =========================================================================
|
|
309
|
-
|
|
310
|
-
describe('getGroups', () => {
|
|
311
|
-
it('should return sorted group names', () => {
|
|
312
|
-
const groups = api.getGroups()
|
|
313
|
-
expect(groups.length).toBeGreaterThan(0)
|
|
314
|
-
expect(groups).toContain('core')
|
|
315
|
-
expect(groups).toContain('search')
|
|
316
|
-
// Verify sorted
|
|
317
|
-
const sorted = [...groups].sort()
|
|
318
|
-
expect(groups).toEqual(sorted)
|
|
319
|
-
})
|
|
320
|
-
})
|
|
321
|
-
|
|
322
|
-
describe('getGroupMethods', () => {
|
|
323
|
-
it('should return method names for a group', () => {
|
|
324
|
-
const methods = api.getGroupMethods('core')
|
|
325
|
-
expect(methods).toContain('createEntry')
|
|
326
|
-
expect(methods).not.toContain('help')
|
|
327
|
-
})
|
|
328
|
-
|
|
329
|
-
it('should return empty for unknown group', () => {
|
|
330
|
-
const methods = api.getGroupMethods('nonexistent' as 'core')
|
|
331
|
-
expect(methods).toEqual([])
|
|
332
|
-
})
|
|
333
|
-
})
|
|
334
|
-
|
|
335
|
-
// =========================================================================
|
|
336
|
-
// createSandboxBindings
|
|
337
|
-
// =========================================================================
|
|
338
|
-
|
|
339
|
-
describe('createSandboxBindings', () => {
|
|
340
|
-
it('should include all group namespaces', () => {
|
|
341
|
-
const bindings = api.createSandboxBindings()
|
|
342
|
-
expect(bindings['core']).toBeDefined()
|
|
343
|
-
expect(bindings['search']).toBeDefined()
|
|
344
|
-
expect(bindings['analytics']).toBeDefined()
|
|
345
|
-
expect(bindings['relationships']).toBeDefined()
|
|
346
|
-
expect(bindings['export']).toBeDefined()
|
|
347
|
-
expect(bindings['admin']).toBeDefined()
|
|
348
|
-
expect(bindings['github']).toBeDefined()
|
|
349
|
-
expect(bindings['backup']).toBeDefined()
|
|
350
|
-
expect(bindings['team']).toBeDefined()
|
|
351
|
-
})
|
|
352
|
-
|
|
353
|
-
it('should include top-level convenience aliases', () => {
|
|
354
|
-
const bindings = api.createSandboxBindings()
|
|
355
|
-
expect(typeof bindings['createEntry']).toBe('function')
|
|
356
|
-
expect(typeof bindings['getRecentEntries']).toBe('function')
|
|
357
|
-
expect(typeof bindings['searchEntries']).toBe('function')
|
|
358
|
-
expect(typeof bindings['getStatistics']).toBe('function')
|
|
359
|
-
})
|
|
360
|
-
|
|
361
|
-
it('should include top-level help()', () => {
|
|
362
|
-
const bindings = api.createSandboxBindings()
|
|
363
|
-
expect(typeof bindings['help']).toBe('function')
|
|
364
|
-
})
|
|
365
|
-
|
|
366
|
-
it('should return top-level help with groups and totalMethods', async () => {
|
|
367
|
-
const bindings = api.createSandboxBindings()
|
|
368
|
-
const help = (await (bindings['help'] as () => Promise<unknown>)()) as {
|
|
369
|
-
groups: string[]
|
|
370
|
-
totalMethods: number
|
|
371
|
-
usage: string
|
|
372
|
-
}
|
|
373
|
-
expect(help.groups.length).toBeGreaterThan(0)
|
|
374
|
-
expect(help.totalMethods).toBeGreaterThan(0)
|
|
375
|
-
expect(help.usage).toContain('mj.')
|
|
376
|
-
})
|
|
377
|
-
})
|
|
378
|
-
})
|
|
379
|
-
|
|
380
|
-
// =============================================================================
|
|
381
|
-
// createJournalApi factory
|
|
382
|
-
// =============================================================================
|
|
383
|
-
|
|
384
|
-
describe('createJournalApi', () => {
|
|
385
|
-
it('should create a JournalApi instance', () => {
|
|
386
|
-
const api = createJournalApi(createMinimalToolSet())
|
|
387
|
-
expect(api).toBeInstanceOf(JournalApi)
|
|
388
|
-
})
|
|
389
|
-
|
|
390
|
-
it('should work identically to constructor', () => {
|
|
391
|
-
const tools = createMinimalToolSet()
|
|
392
|
-
const api1 = new JournalApi(tools)
|
|
393
|
-
const api2 = createJournalApi(tools)
|
|
394
|
-
expect(api1.getGroups()).toEqual(api2.getGroups())
|
|
395
|
-
})
|
|
396
|
-
})
|