comisai 1.0.11 → 1.0.13
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/node_modules/@comis/agent/dist/model/operation-model-defaults.js +1 -0
- package/node_modules/@comis/agent/dist/session/comis-session-manager.js +9 -9
- package/node_modules/@comis/agent/package.json +1 -1
- package/node_modules/@comis/channels/package.json +1 -1
- package/node_modules/@comis/cli/package.json +1 -1
- package/node_modules/@comis/core/dist/event-bus/events-infra.d.ts +2 -0
- package/node_modules/@comis/core/package.json +1 -1
- package/node_modules/@comis/daemon/dist/wiring/setup-channels.js +12 -1
- package/node_modules/@comis/daemon/dist/wiring/setup-gateway.js +1 -0
- package/node_modules/@comis/daemon/dist/wiring/setup-schedulers.js +1 -0
- package/node_modules/@comis/daemon/package.json +1 -1
- package/node_modules/@comis/gateway/package.json +1 -1
- package/node_modules/@comis/infra/package.json +1 -1
- package/node_modules/@comis/memory/package.json +1 -1
- package/node_modules/@comis/scheduler/dist/cron/cron-types.d.ts +6 -0
- package/node_modules/@comis/scheduler/dist/cron/cron-types.js +2 -0
- package/node_modules/@comis/scheduler/package.json +1 -1
- package/node_modules/@comis/shared/package.json +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/gateway-tool.d.ts +1 -1
- package/node_modules/@comis/skills/package.json +1 -1
- package/package.json +18 -18
- package/node_modules/@comis/core/dist/approval/approval-gate.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/approval/approval-gate.test.js +0 -1003
- package/node_modules/@comis/core/dist/bootstrap.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/bootstrap.test.js +0 -150
- package/node_modules/@comis/core/dist/config/backup.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/backup.test.js +0 -160
- package/node_modules/@comis/core/dist/config/env-substitution.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/env-substitution.test.js +0 -259
- package/node_modules/@comis/core/dist/config/field-metadata.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/field-metadata.test.js +0 -72
- package/node_modules/@comis/core/dist/config/git-manager.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/git-manager.test.js +0 -1042
- package/node_modules/@comis/core/dist/config/immutable-keys.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/immutable-keys.test.js +0 -283
- package/node_modules/@comis/core/dist/config/include-resolver.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/include-resolver.test.js +0 -292
- package/node_modules/@comis/core/dist/config/layered.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/layered.test.js +0 -211
- package/node_modules/@comis/core/dist/config/loader.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/loader.test.js +0 -300
- package/node_modules/@comis/core/dist/config/migrate.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/migrate.test.js +0 -244
- package/node_modules/@comis/core/dist/config/partial-validator.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/partial-validator.test.js +0 -98
- package/node_modules/@comis/core/dist/config/schema-agent-model.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-agent-model.test.js +0 -279
- package/node_modules/@comis/core/dist/config/schema-agent-session.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-agent-session.test.js +0 -242
- package/node_modules/@comis/core/dist/config/schema-agent.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-agent.test.js +0 -645
- package/node_modules/@comis/core/dist/config/schema-channel.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-channel.test.js +0 -341
- package/node_modules/@comis/core/dist/config/schema-coalescer.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-coalescer.test.js +0 -51
- package/node_modules/@comis/core/dist/config/schema-context-engine.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-context-engine.test.js +0 -797
- package/node_modules/@comis/core/dist/config/schema-context-guard.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-context-guard.test.js +0 -111
- package/node_modules/@comis/core/dist/config/schema-daemon.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-daemon.test.js +0 -107
- package/node_modules/@comis/core/dist/config/schema-delivery-timing.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-delivery-timing.test.js +0 -51
- package/node_modules/@comis/core/dist/config/schema-documentation.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-documentation.test.js +0 -63
- package/node_modules/@comis/core/dist/config/schema-gateway.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-gateway.test.js +0 -219
- package/node_modules/@comis/core/dist/config/schema-gemini-cache.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-gemini-cache.test.js +0 -41
- package/node_modules/@comis/core/dist/config/schema-integrations.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-integrations.test.js +0 -92
- package/node_modules/@comis/core/dist/config/schema-lifecycle-reactions.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-lifecycle-reactions.test.js +0 -61
- package/node_modules/@comis/core/dist/config/schema-misc.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-misc.test.js +0 -394
- package/node_modules/@comis/core/dist/config/schema-observability.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-observability.test.js +0 -76
- package/node_modules/@comis/core/dist/config/schema-providers.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-providers.test.js +0 -294
- package/node_modules/@comis/core/dist/config/schema-queue.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-queue.test.js +0 -234
- package/node_modules/@comis/core/dist/config/schema-response-prefix.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-response-prefix.test.js +0 -36
- package/node_modules/@comis/core/dist/config/schema-security.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-security.test.js +0 -54
- package/node_modules/@comis/core/dist/config/schema-sender-trust-display.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-sender-trust-display.test.js +0 -60
- package/node_modules/@comis/core/dist/config/schema-serializer.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-serializer.test.js +0 -73
- package/node_modules/@comis/core/dist/config/schema-telegram-file-guard.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/config/schema-telegram-file-guard.test.js +0 -39
- package/node_modules/@comis/core/dist/context/context.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/context/context.test.js +0 -276
- package/node_modules/@comis/core/dist/domain/agent-response.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/domain/agent-response.test.js +0 -159
- package/node_modules/@comis/core/dist/domain/credential-mapping.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/domain/credential-mapping.test.js +0 -135
- package/node_modules/@comis/core/dist/domain/delivery-origin.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/domain/delivery-origin.test.js +0 -68
- package/node_modules/@comis/core/dist/domain/execution-graph.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/domain/execution-graph.test.js +0 -441
- package/node_modules/@comis/core/dist/domain/memory-entry.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/domain/memory-entry.test.js +0 -193
- package/node_modules/@comis/core/dist/domain/normalized-message.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/domain/normalized-message.test.js +0 -255
- package/node_modules/@comis/core/dist/domain/session-key.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/domain/session-key.test.js +0 -291
- package/node_modules/@comis/core/dist/domain/subagent-context-config.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/domain/subagent-context-config.test.js +0 -131
- package/node_modules/@comis/core/dist/domain/subagent-context-types.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/domain/subagent-context-types.test.js +0 -182
- package/node_modules/@comis/core/dist/event-bus/bus.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/event-bus/bus.test.js +0 -152
- package/node_modules/@comis/core/dist/event-bus/events-agent.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/event-bus/events-agent.test.js +0 -409
- package/node_modules/@comis/core/dist/event-bus/events-channel.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/event-bus/events-channel.test.js +0 -240
- package/node_modules/@comis/core/dist/event-bus/events-infra.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/event-bus/events-infra.test.js +0 -416
- package/node_modules/@comis/core/dist/event-bus/events-messaging.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/event-bus/events-messaging.test.js +0 -433
- package/node_modules/@comis/core/dist/event-bus/events.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/event-bus/events.test.js +0 -93
- package/node_modules/@comis/core/dist/hooks/hook-runner-global.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/hooks/hook-runner-global.test.js +0 -29
- package/node_modules/@comis/core/dist/hooks/hook-runner.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/hooks/hook-runner.test.js +0 -490
- package/node_modules/@comis/core/dist/hooks/hook-strategies.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/hooks/hook-strategies.test.js +0 -209
- package/node_modules/@comis/core/dist/hooks/integration.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/hooks/integration.test.js +0 -235
- package/node_modules/@comis/core/dist/hooks/plugin-registry.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/hooks/plugin-registry.test.js +0 -470
- package/node_modules/@comis/core/dist/load-env.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/load-env.test.js +0 -21
- package/node_modules/@comis/core/dist/security/action-classifier.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/action-classifier.test.js +0 -298
- package/node_modules/@comis/core/dist/security/audit-aggregator.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/audit-aggregator.test.js +0 -128
- package/node_modules/@comis/core/dist/security/audit.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/audit.test.js +0 -154
- package/node_modules/@comis/core/dist/security/canary-token.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/canary-token.test.js +0 -45
- package/node_modules/@comis/core/dist/security/config-redaction.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/config-redaction.test.js +0 -107
- package/node_modules/@comis/core/dist/security/external-content.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/external-content.test.js +0 -210
- package/node_modules/@comis/core/dist/security/injection-patterns.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/injection-patterns.test.js +0 -213
- package/node_modules/@comis/core/dist/security/injection-rate-limiter.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/injection-rate-limiter.test.js +0 -194
- package/node_modules/@comis/core/dist/security/input-guard.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/input-guard.test.js +0 -215
- package/node_modules/@comis/core/dist/security/input-security-guard.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/input-security-guard.test.js +0 -215
- package/node_modules/@comis/core/dist/security/input-validator.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/input-validator.test.js +0 -133
- package/node_modules/@comis/core/dist/security/log-sanitizer.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/log-sanitizer.test.js +0 -260
- package/node_modules/@comis/core/dist/security/memory-write-validator.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/memory-write-validator.test.js +0 -62
- package/node_modules/@comis/core/dist/security/output-guard.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/output-guard.test.js +0 -397
- package/node_modules/@comis/core/dist/security/safe-path.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/safe-path.test.js +0 -95
- package/node_modules/@comis/core/dist/security/scoped-secret-manager.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/scoped-secret-manager.test.js +0 -231
- package/node_modules/@comis/core/dist/security/secret-access.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/secret-access.test.js +0 -41
- package/node_modules/@comis/core/dist/security/secret-crypto.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/secret-crypto.test.js +0 -113
- package/node_modules/@comis/core/dist/security/secret-manager.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/secret-manager.test.js +0 -394
- package/node_modules/@comis/core/dist/security/secret-ref-resolver.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/secret-ref-resolver.test.js +0 -268
- package/node_modules/@comis/core/dist/security/secrets-audit.test.d.ts +0 -10
- package/node_modules/@comis/core/dist/security/secrets-audit.test.js +0 -295
- package/node_modules/@comis/core/dist/security/ssrf-guard.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/ssrf-guard.test.js +0 -127
- package/node_modules/@comis/core/dist/security/token-generator.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/security/token-generator.test.js +0 -35
- package/node_modules/@comis/core/dist/tool-metadata.test.d.ts +0 -1
- package/node_modules/@comis/core/dist/tool-metadata.test.js +0 -112
- package/node_modules/@comis/memory/dist/compaction.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/compaction.test.js +0 -298
- package/node_modules/@comis/memory/dist/context-schema.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/context-schema.test.js +0 -246
- package/node_modules/@comis/memory/dist/context-store.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/context-store.test.js +0 -708
- package/node_modules/@comis/memory/dist/credential-mapping-schema.test.d.ts +0 -7
- package/node_modules/@comis/memory/dist/credential-mapping-schema.test.js +0 -73
- package/node_modules/@comis/memory/dist/credential-mapping-store.test.d.ts +0 -8
- package/node_modules/@comis/memory/dist/credential-mapping-store.test.js +0 -340
- package/node_modules/@comis/memory/dist/delivery-mirror-adapter.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/delivery-mirror-adapter.test.js +0 -165
- package/node_modules/@comis/memory/dist/delivery-queue-adapter.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/delivery-queue-adapter.test.js +0 -263
- package/node_modules/@comis/memory/dist/embedding-batch-indexer.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/embedding-batch-indexer.test.js +0 -202
- package/node_modules/@comis/memory/dist/embedding-cache-lru.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/embedding-cache-lru.test.js +0 -241
- package/node_modules/@comis/memory/dist/embedding-cache-sqlite.test.d.ts +0 -8
- package/node_modules/@comis/memory/dist/embedding-cache-sqlite.test.js +0 -678
- package/node_modules/@comis/memory/dist/embedding-cache.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/embedding-cache.test.js +0 -213
- package/node_modules/@comis/memory/dist/embedding-fingerprint.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/embedding-fingerprint.test.js +0 -87
- package/node_modules/@comis/memory/dist/embedding-hash.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/embedding-hash.test.js +0 -31
- package/node_modules/@comis/memory/dist/embedding-integration.test.d.ts +0 -8
- package/node_modules/@comis/memory/dist/embedding-integration.test.js +0 -232
- package/node_modules/@comis/memory/dist/embedding-provider-factory.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/embedding-provider-factory.test.js +0 -176
- package/node_modules/@comis/memory/dist/embedding-provider-local.test.d.ts +0 -8
- package/node_modules/@comis/memory/dist/embedding-provider-local.test.js +0 -76
- package/node_modules/@comis/memory/dist/embedding-provider-openai.test.d.ts +0 -8
- package/node_modules/@comis/memory/dist/embedding-provider-openai.test.js +0 -100
- package/node_modules/@comis/memory/dist/embedding-queue.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/embedding-queue.test.js +0 -236
- package/node_modules/@comis/memory/dist/hybrid-search.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/hybrid-search.test.js +0 -476
- package/node_modules/@comis/memory/dist/identity-link-store.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/identity-link-store.test.js +0 -88
- package/node_modules/@comis/memory/dist/memory-api.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/memory-api.test.js +0 -495
- package/node_modules/@comis/memory/dist/memory-concurrency.test.d.ts +0 -20
- package/node_modules/@comis/memory/dist/memory-concurrency.test.js +0 -222
- package/node_modules/@comis/memory/dist/named-graph-store.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/named-graph-store.test.js +0 -227
- package/node_modules/@comis/memory/dist/observability-store.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/observability-store.test.js +0 -704
- package/node_modules/@comis/memory/dist/row-mapper.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/row-mapper.test.js +0 -409
- package/node_modules/@comis/memory/dist/schema.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/schema.test.js +0 -240
- package/node_modules/@comis/memory/dist/secret-store-schema.test.d.ts +0 -7
- package/node_modules/@comis/memory/dist/secret-store-schema.test.js +0 -90
- package/node_modules/@comis/memory/dist/session-store.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/session-store.test.js +0 -262
- package/node_modules/@comis/memory/dist/setup-secrets.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/setup-secrets.test.js +0 -140
- package/node_modules/@comis/memory/dist/sqlite-memory-adapter.test.d.ts +0 -1
- package/node_modules/@comis/memory/dist/sqlite-memory-adapter.test.js +0 -888
- package/node_modules/@comis/memory/dist/sqlite-secret-store.test.d.ts +0 -8
- package/node_modules/@comis/memory/dist/sqlite-secret-store.test.js +0 -245
- package/node_modules/@comis/shared/dist/abort.test.d.ts +0 -1
- package/node_modules/@comis/shared/dist/abort.test.js +0 -71
- package/node_modules/@comis/shared/dist/result.test.d.ts +0 -1
- package/node_modules/@comis/shared/dist/result.test.js +0 -178
- package/node_modules/@comis/shared/dist/suppress-error.test.d.ts +0 -1
- package/node_modules/@comis/shared/dist/suppress-error.test.js +0 -50
- package/node_modules/@comis/shared/dist/timeout.test.d.ts +0 -1
- package/node_modules/@comis/shared/dist/timeout.test.js +0 -75
- package/node_modules/@comis/shared/dist/ttl-cache.test.d.ts +0 -1
- package/node_modules/@comis/shared/dist/ttl-cache.test.js +0 -81
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for SqliteSecretStore — SecretStorePort implementation with
|
|
3
|
-
* AES-256-GCM encrypted BLOB storage in SQLite.
|
|
4
|
-
*
|
|
5
|
-
* Uses real crypto (no mocks) and temp files for persistence testing.
|
|
6
|
-
* Each test gets a unique temp DB path cleaned up in afterEach.
|
|
7
|
-
*/
|
|
8
|
-
export {};
|
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for SqliteSecretStore — SecretStorePort implementation with
|
|
3
|
-
* AES-256-GCM encrypted BLOB storage in SQLite.
|
|
4
|
-
*
|
|
5
|
-
* Uses real crypto (no mocks) and temp files for persistence testing.
|
|
6
|
-
* Each test gets a unique temp DB path cleaned up in afterEach.
|
|
7
|
-
*/
|
|
8
|
-
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
9
|
-
import Database from "better-sqlite3";
|
|
10
|
-
import { randomBytes } from "node:crypto";
|
|
11
|
-
import * as fs from "node:fs";
|
|
12
|
-
import * as os from "node:os";
|
|
13
|
-
import { createSecretsCrypto } from "@comis/core";
|
|
14
|
-
import { createSqliteSecretStore } from "./sqlite-secret-store.js";
|
|
15
|
-
function makeCrypto() {
|
|
16
|
-
return createSecretsCrypto(randomBytes(32));
|
|
17
|
-
}
|
|
18
|
-
function tempDbPath() {
|
|
19
|
-
const dir = os.tmpdir();
|
|
20
|
-
const name = `comis-test-secrets-${randomBytes(8).toString("hex")}.db`;
|
|
21
|
-
return `${dir}/${name}`;
|
|
22
|
-
}
|
|
23
|
-
/** Unwrap a Result or fail the test. */
|
|
24
|
-
function unwrap(result) {
|
|
25
|
-
if (!result.ok) {
|
|
26
|
-
throw new Error(`Expected ok result, got error: ${result.error.message}`);
|
|
27
|
-
}
|
|
28
|
-
return result.value;
|
|
29
|
-
}
|
|
30
|
-
describe("createSqliteSecretStore", () => {
|
|
31
|
-
let dbPath;
|
|
32
|
-
let crypto;
|
|
33
|
-
beforeEach(() => {
|
|
34
|
-
dbPath = tempDbPath();
|
|
35
|
-
crypto = makeCrypto();
|
|
36
|
-
});
|
|
37
|
-
afterEach(() => {
|
|
38
|
-
// Clean up temp database files
|
|
39
|
-
for (const suffix of ["", "-wal", "-shm"]) {
|
|
40
|
-
try {
|
|
41
|
-
fs.unlinkSync(dbPath + suffix);
|
|
42
|
-
}
|
|
43
|
-
catch {
|
|
44
|
-
// File may not exist
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
describe("set + getDecrypted round-trip", () => {
|
|
49
|
-
it("stores and retrieves a secret", () => {
|
|
50
|
-
const store = createSqliteSecretStore(dbPath, crypto);
|
|
51
|
-
const setResult = store.set("API_KEY", "sk-secret-123");
|
|
52
|
-
expect(setResult.ok).toBe(true);
|
|
53
|
-
const plaintext = unwrap(store.getDecrypted("API_KEY"));
|
|
54
|
-
expect(plaintext).toBe("sk-secret-123");
|
|
55
|
-
store.close();
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
describe("UPSERT behavior", () => {
|
|
59
|
-
it("preserves created_at on update, changes updated_at", () => {
|
|
60
|
-
const store = createSqliteSecretStore(dbPath, crypto);
|
|
61
|
-
store.set("MY_SECRET", "original-value");
|
|
62
|
-
// Get metadata before update
|
|
63
|
-
const beforeItems = unwrap(store.list());
|
|
64
|
-
const beforeMeta = beforeItems.find((m) => m.name === "MY_SECRET");
|
|
65
|
-
expect(beforeMeta).toBeDefined();
|
|
66
|
-
const createdBefore = beforeMeta.createdAt;
|
|
67
|
-
// Small delay to ensure timestamp difference
|
|
68
|
-
const now = Date.now();
|
|
69
|
-
while (Date.now() === now) {
|
|
70
|
-
// busy-wait for at least 1ms
|
|
71
|
-
}
|
|
72
|
-
store.set("MY_SECRET", "updated-value");
|
|
73
|
-
const afterItems = unwrap(store.list());
|
|
74
|
-
const afterMeta = afterItems.find((m) => m.name === "MY_SECRET");
|
|
75
|
-
expect(afterMeta).toBeDefined();
|
|
76
|
-
// created_at preserved
|
|
77
|
-
expect(afterMeta.createdAt).toBe(createdBefore);
|
|
78
|
-
// updated_at changed
|
|
79
|
-
expect(afterMeta.updatedAt).toBeGreaterThanOrEqual(createdBefore);
|
|
80
|
-
// Value updated
|
|
81
|
-
const plaintext = unwrap(store.getDecrypted("MY_SECRET"));
|
|
82
|
-
expect(plaintext).toBe("updated-value");
|
|
83
|
-
store.close();
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
describe("getDecrypted", () => {
|
|
87
|
-
it("returns ok(undefined) for missing secret", () => {
|
|
88
|
-
const store = createSqliteSecretStore(dbPath, crypto);
|
|
89
|
-
const plaintext = unwrap(store.getDecrypted("NONEXISTENT"));
|
|
90
|
-
expect(plaintext).toBeUndefined();
|
|
91
|
-
store.close();
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
describe("decryptAll", () => {
|
|
95
|
-
it("returns all stored secrets as Map", () => {
|
|
96
|
-
const store = createSqliteSecretStore(dbPath, crypto);
|
|
97
|
-
store.set("KEY_A", "value-a");
|
|
98
|
-
store.set("KEY_B", "value-b");
|
|
99
|
-
store.set("KEY_C", "value-c");
|
|
100
|
-
const map = unwrap(store.decryptAll());
|
|
101
|
-
expect(map.size).toBe(3);
|
|
102
|
-
expect(map.get("KEY_A")).toBe("value-a");
|
|
103
|
-
expect(map.get("KEY_B")).toBe("value-b");
|
|
104
|
-
expect(map.get("KEY_C")).toBe("value-c");
|
|
105
|
-
store.close();
|
|
106
|
-
});
|
|
107
|
-
it("returns empty Map on empty store", () => {
|
|
108
|
-
const store = createSqliteSecretStore(dbPath, crypto);
|
|
109
|
-
const map = unwrap(store.decryptAll());
|
|
110
|
-
expect(map.size).toBe(0);
|
|
111
|
-
store.close();
|
|
112
|
-
});
|
|
113
|
-
it("excludes canary from results", () => {
|
|
114
|
-
const store = createSqliteSecretStore(dbPath, crypto);
|
|
115
|
-
store.set("USER_SECRET", "my-value");
|
|
116
|
-
const map = unwrap(store.decryptAll());
|
|
117
|
-
// Should only contain user secret, not canary
|
|
118
|
-
expect(map.has("__comis_canary__")).toBe(false);
|
|
119
|
-
expect(map.size).toBe(1);
|
|
120
|
-
expect(map.get("USER_SECRET")).toBe("my-value");
|
|
121
|
-
store.close();
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
describe("exists", () => {
|
|
125
|
-
it("returns true for stored secret, false for missing", () => {
|
|
126
|
-
const store = createSqliteSecretStore(dbPath, crypto);
|
|
127
|
-
expect(store.exists("ABSENT")).toBe(false);
|
|
128
|
-
store.set("PRESENT", "value");
|
|
129
|
-
expect(store.exists("PRESENT")).toBe(true);
|
|
130
|
-
store.close();
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
describe("list", () => {
|
|
134
|
-
it("returns metadata without secret values", () => {
|
|
135
|
-
const store = createSqliteSecretStore(dbPath, crypto);
|
|
136
|
-
store.set("DB_PASSWORD", "secret123", {
|
|
137
|
-
provider: "postgres",
|
|
138
|
-
description: "Main database password",
|
|
139
|
-
});
|
|
140
|
-
const items = unwrap(store.list());
|
|
141
|
-
expect(items).toHaveLength(1);
|
|
142
|
-
const item = items[0];
|
|
143
|
-
expect(item.name).toBe("DB_PASSWORD");
|
|
144
|
-
expect(item.provider).toBe("postgres");
|
|
145
|
-
expect(item.description).toBe("Main database password");
|
|
146
|
-
expect(item.usageCount).toBe(0);
|
|
147
|
-
expect(item.createdAt).toBeTypeOf("number");
|
|
148
|
-
expect(item.updatedAt).toBeTypeOf("number");
|
|
149
|
-
// No secret value in metadata
|
|
150
|
-
expect(item).not.toHaveProperty("ciphertext");
|
|
151
|
-
expect(item).not.toHaveProperty("iv");
|
|
152
|
-
expect(item).not.toHaveProperty("authTag");
|
|
153
|
-
expect(item).not.toHaveProperty("salt");
|
|
154
|
-
expect(item).not.toHaveProperty("plaintext");
|
|
155
|
-
store.close();
|
|
156
|
-
});
|
|
157
|
-
it("excludes canary from list results", () => {
|
|
158
|
-
const store = createSqliteSecretStore(dbPath, crypto);
|
|
159
|
-
store.set("VISIBLE_SECRET", "hello");
|
|
160
|
-
const items = unwrap(store.list());
|
|
161
|
-
const names = items.map((i) => i.name);
|
|
162
|
-
expect(names).not.toContain("__comis_canary__");
|
|
163
|
-
expect(names).toContain("VISIBLE_SECRET");
|
|
164
|
-
store.close();
|
|
165
|
-
});
|
|
166
|
-
});
|
|
167
|
-
describe("delete", () => {
|
|
168
|
-
it("returns ok(true) for existing secret", () => {
|
|
169
|
-
const store = createSqliteSecretStore(dbPath, crypto);
|
|
170
|
-
store.set("TO_DELETE", "value");
|
|
171
|
-
const deleted = unwrap(store.delete("TO_DELETE"));
|
|
172
|
-
expect(deleted).toBe(true);
|
|
173
|
-
// Confirm deleted
|
|
174
|
-
expect(store.exists("TO_DELETE")).toBe(false);
|
|
175
|
-
store.close();
|
|
176
|
-
});
|
|
177
|
-
it("returns ok(false) for non-existent secret", () => {
|
|
178
|
-
const store = createSqliteSecretStore(dbPath, crypto);
|
|
179
|
-
const deleted = unwrap(store.delete("DOES_NOT_EXIST"));
|
|
180
|
-
expect(deleted).toBe(false);
|
|
181
|
-
store.close();
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
describe("recordUsage", () => {
|
|
185
|
-
it("increments usage_count and updates last_used_at", () => {
|
|
186
|
-
const store = createSqliteSecretStore(dbPath, crypto);
|
|
187
|
-
store.set("TRACKED", "value");
|
|
188
|
-
// Initial state
|
|
189
|
-
const beforeItems = unwrap(store.list());
|
|
190
|
-
const before = beforeItems.find((m) => m.name === "TRACKED");
|
|
191
|
-
expect(before.usageCount).toBe(0);
|
|
192
|
-
expect(before.lastUsedAt).toBeUndefined();
|
|
193
|
-
// Record usage
|
|
194
|
-
store.recordUsage("TRACKED");
|
|
195
|
-
const afterItems = unwrap(store.list());
|
|
196
|
-
const after = afterItems.find((m) => m.name === "TRACKED");
|
|
197
|
-
expect(after.usageCount).toBe(1);
|
|
198
|
-
expect(after.lastUsedAt).toBeTypeOf("number");
|
|
199
|
-
// Record again
|
|
200
|
-
store.recordUsage("TRACKED");
|
|
201
|
-
const finalItems = unwrap(store.list());
|
|
202
|
-
const final = finalItems.find((m) => m.name === "TRACKED");
|
|
203
|
-
expect(final.usageCount).toBe(2);
|
|
204
|
-
store.close();
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
describe("close", () => {
|
|
208
|
-
it("does not throw", () => {
|
|
209
|
-
const store = createSqliteSecretStore(dbPath, crypto);
|
|
210
|
-
expect(() => store.close()).not.toThrow();
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
describe("WAL mode", () => {
|
|
214
|
-
it("enables WAL journal mode", () => {
|
|
215
|
-
const store = createSqliteSecretStore(dbPath, crypto);
|
|
216
|
-
// Open a new connection to verify WAL mode persists
|
|
217
|
-
const db = new Database(dbPath);
|
|
218
|
-
const row = db.prepare("PRAGMA journal_mode").get();
|
|
219
|
-
expect(row.journal_mode).toBe("wal");
|
|
220
|
-
db.close();
|
|
221
|
-
store.close();
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
describe("file permissions", () => {
|
|
225
|
-
it("sets 0o600 on secrets.db", () => {
|
|
226
|
-
const store = createSqliteSecretStore(dbPath, crypto);
|
|
227
|
-
const stat = fs.statSync(dbPath);
|
|
228
|
-
// Check file mode (lower 9 bits)
|
|
229
|
-
const mode = stat.mode & 0o777;
|
|
230
|
-
expect(mode).toBe(0o600);
|
|
231
|
-
store.close();
|
|
232
|
-
});
|
|
233
|
-
});
|
|
234
|
-
describe("persistence", () => {
|
|
235
|
-
it("survives close and reopen", () => {
|
|
236
|
-
const store1 = createSqliteSecretStore(dbPath, crypto);
|
|
237
|
-
store1.set("PERSIST_KEY", "persist-value");
|
|
238
|
-
store1.close();
|
|
239
|
-
const store2 = createSqliteSecretStore(dbPath, crypto);
|
|
240
|
-
const plaintext = unwrap(store2.getDecrypted("PERSIST_KEY"));
|
|
241
|
-
expect(plaintext).toBe("persist-value");
|
|
242
|
-
store2.close();
|
|
243
|
-
});
|
|
244
|
-
});
|
|
245
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { checkAborted } from "./abort.js";
|
|
3
|
-
describe("checkAborted", () => {
|
|
4
|
-
it("returns ok when signal is undefined", () => {
|
|
5
|
-
const result = checkAborted(undefined);
|
|
6
|
-
expect(result.ok).toBe(true);
|
|
7
|
-
if (result.ok) {
|
|
8
|
-
expect(result.value).toBeUndefined();
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
it("returns ok when signal is not aborted", () => {
|
|
12
|
-
const controller = new AbortController();
|
|
13
|
-
const result = checkAborted(controller.signal);
|
|
14
|
-
expect(result.ok).toBe(true);
|
|
15
|
-
if (result.ok) {
|
|
16
|
-
expect(result.value).toBeUndefined();
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
it("returns err when signal is aborted", () => {
|
|
20
|
-
const controller = new AbortController();
|
|
21
|
-
controller.abort("custom reason");
|
|
22
|
-
const result = checkAborted(controller.signal);
|
|
23
|
-
expect(result.ok).toBe(false);
|
|
24
|
-
if (!result.ok) {
|
|
25
|
-
expect(result.error).toBeInstanceOf(Error);
|
|
26
|
-
expect(result.error.message).toBe("custom reason");
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
it("preserves Error reason directly when signal.reason is an Error", () => {
|
|
30
|
-
const controller = new AbortController();
|
|
31
|
-
const originalError = new Error("specific abort reason");
|
|
32
|
-
controller.abort(originalError);
|
|
33
|
-
const result = checkAborted(controller.signal);
|
|
34
|
-
expect(result.ok).toBe(false);
|
|
35
|
-
if (!result.ok) {
|
|
36
|
-
expect(result.error).toBe(originalError);
|
|
37
|
-
expect(result.error.message).toBe("specific abort reason");
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
it("wraps string reason in Error", () => {
|
|
41
|
-
const controller = new AbortController();
|
|
42
|
-
controller.abort("string reason");
|
|
43
|
-
const result = checkAborted(controller.signal);
|
|
44
|
-
expect(result.ok).toBe(false);
|
|
45
|
-
if (!result.ok) {
|
|
46
|
-
expect(result.error).toBeInstanceOf(Error);
|
|
47
|
-
expect(result.error.message).toBe("string reason");
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
it("defaults to 'Aborted' when no reason is set", () => {
|
|
51
|
-
const controller = new AbortController();
|
|
52
|
-
controller.abort();
|
|
53
|
-
const result = checkAborted(controller.signal);
|
|
54
|
-
expect(result.ok).toBe(false);
|
|
55
|
-
if (!result.ok) {
|
|
56
|
-
expect(result.error).toBeInstanceOf(Error);
|
|
57
|
-
// AbortController.abort() without args sets reason to a DOMException
|
|
58
|
-
// in Node.js, but our function handles the general case
|
|
59
|
-
expect(result.error.message).toBeTruthy();
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
it("returns err immediately for pre-aborted signal (AbortSignal.abort())", () => {
|
|
63
|
-
const signal = AbortSignal.abort("pre-aborted");
|
|
64
|
-
const result = checkAborted(signal);
|
|
65
|
-
expect(result.ok).toBe(false);
|
|
66
|
-
if (!result.ok) {
|
|
67
|
-
expect(result.error).toBeInstanceOf(Error);
|
|
68
|
-
expect(result.error.message).toBe("pre-aborted");
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { ok, err, tryCatch, fromPromise } from "./result.js";
|
|
3
|
-
describe("Result<T, E>", () => {
|
|
4
|
-
describe("ok()", () => {
|
|
5
|
-
it("returns { ok: true, value: T }", () => {
|
|
6
|
-
const result = ok(42);
|
|
7
|
-
expect(result).toEqual({ ok: true, value: 42 });
|
|
8
|
-
});
|
|
9
|
-
it("allows access to .value when narrowed via ok === true", () => {
|
|
10
|
-
const result = ok(42);
|
|
11
|
-
if (result.ok) {
|
|
12
|
-
// TypeScript narrows to { ok: true, value: number }
|
|
13
|
-
expect(result.value).toBe(42);
|
|
14
|
-
}
|
|
15
|
-
else {
|
|
16
|
-
throw new Error("Should not reach here");
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
it("works with complex types", () => {
|
|
20
|
-
const result = ok({ name: "test", count: 3 });
|
|
21
|
-
expect(result.ok).toBe(true);
|
|
22
|
-
if (result.ok) {
|
|
23
|
-
expect(result.value.name).toBe("test");
|
|
24
|
-
expect(result.value.count).toBe(3);
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
describe("err()", () => {
|
|
29
|
-
it("returns { ok: false, error: E }", () => {
|
|
30
|
-
const error = new Error("fail");
|
|
31
|
-
const result = err(error);
|
|
32
|
-
expect(result).toEqual({ ok: false, error });
|
|
33
|
-
});
|
|
34
|
-
it("allows access to .error when narrowed via ok === false", () => {
|
|
35
|
-
const result = err(new Error("fail"));
|
|
36
|
-
if (!result.ok) {
|
|
37
|
-
// TypeScript narrows to { ok: false, error: Error }
|
|
38
|
-
expect(result.error.message).toBe("fail");
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
throw new Error("Should not reach here");
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
it("works with custom error types", () => {
|
|
45
|
-
const result = err({ code: "NOT_FOUND", message: "not found" });
|
|
46
|
-
expect(result.ok).toBe(false);
|
|
47
|
-
if (!result.ok) {
|
|
48
|
-
expect(result.error.code).toBe("NOT_FOUND");
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
describe("tryCatch()", () => {
|
|
53
|
-
it("returns ok(value) when function succeeds", () => {
|
|
54
|
-
const result = tryCatch(() => 42);
|
|
55
|
-
expect(result).toEqual({ ok: true, value: 42 });
|
|
56
|
-
});
|
|
57
|
-
it("returns err(Error) when function throws Error", () => {
|
|
58
|
-
const result = tryCatch(() => {
|
|
59
|
-
throw new Error("boom");
|
|
60
|
-
});
|
|
61
|
-
expect(result.ok).toBe(false);
|
|
62
|
-
if (!result.ok) {
|
|
63
|
-
expect(result.error).toBeInstanceOf(Error);
|
|
64
|
-
expect(result.error.message).toBe("boom");
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
it("wraps non-Error thrown values in Error", () => {
|
|
68
|
-
const result = tryCatch(() => {
|
|
69
|
-
throw "string error";
|
|
70
|
-
});
|
|
71
|
-
expect(result.ok).toBe(false);
|
|
72
|
-
if (!result.ok) {
|
|
73
|
-
expect(result.error).toBeInstanceOf(Error);
|
|
74
|
-
expect(result.error.message).toBe("string error");
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
it("wraps thrown numbers in Error", () => {
|
|
78
|
-
const result = tryCatch(() => {
|
|
79
|
-
throw 404;
|
|
80
|
-
});
|
|
81
|
-
expect(result.ok).toBe(false);
|
|
82
|
-
if (!result.ok) {
|
|
83
|
-
expect(result.error).toBeInstanceOf(Error);
|
|
84
|
-
expect(result.error.message).toBe("404");
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
it("handles malicious object with toString() that throws", () => {
|
|
88
|
-
const malicious = {
|
|
89
|
-
toString() {
|
|
90
|
-
throw new Error("toString attack");
|
|
91
|
-
},
|
|
92
|
-
};
|
|
93
|
-
const result = tryCatch(() => {
|
|
94
|
-
throw malicious;
|
|
95
|
-
});
|
|
96
|
-
expect(result.ok).toBe(false);
|
|
97
|
-
if (!result.ok) {
|
|
98
|
-
expect(result.error).toBeInstanceOf(Error);
|
|
99
|
-
expect(result.error.message).toBe("[non-stringifiable value]");
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
describe("fromPromise()", () => {
|
|
104
|
-
it("returns ok(value) when promise resolves", async () => {
|
|
105
|
-
const result = await fromPromise(Promise.resolve(42));
|
|
106
|
-
expect(result).toEqual({ ok: true, value: 42 });
|
|
107
|
-
});
|
|
108
|
-
it("returns err(Error) when promise rejects with Error", async () => {
|
|
109
|
-
const result = await fromPromise(Promise.reject(new Error("boom")));
|
|
110
|
-
expect(result.ok).toBe(false);
|
|
111
|
-
if (!result.ok) {
|
|
112
|
-
expect(result.error).toBeInstanceOf(Error);
|
|
113
|
-
expect(result.error.message).toBe("boom");
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
it("wraps non-Error rejection in Error", async () => {
|
|
117
|
-
const result = await fromPromise(Promise.reject("string"));
|
|
118
|
-
expect(result.ok).toBe(false);
|
|
119
|
-
if (!result.ok) {
|
|
120
|
-
expect(result.error).toBeInstanceOf(Error);
|
|
121
|
-
expect(result.error.message).toBe("string");
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
it("wraps null rejection in Error", async () => {
|
|
125
|
-
const result = await fromPromise(Promise.reject(null));
|
|
126
|
-
expect(result.ok).toBe(false);
|
|
127
|
-
if (!result.ok) {
|
|
128
|
-
expect(result.error).toBeInstanceOf(Error);
|
|
129
|
-
expect(result.error.message).toBe("null");
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
it("handles malicious object with toString() that throws", async () => {
|
|
133
|
-
const malicious = {
|
|
134
|
-
toString() {
|
|
135
|
-
throw new Error("toString attack");
|
|
136
|
-
},
|
|
137
|
-
};
|
|
138
|
-
const result = await fromPromise(Promise.reject(malicious));
|
|
139
|
-
expect(result.ok).toBe(false);
|
|
140
|
-
if (!result.ok) {
|
|
141
|
-
expect(result.error).toBeInstanceOf(Error);
|
|
142
|
-
expect(result.error.message).toBe("[non-stringifiable value]");
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
it("wraps undefined rejection in Error", async () => {
|
|
146
|
-
const result = await fromPromise(Promise.reject(undefined));
|
|
147
|
-
expect(result.ok).toBe(false);
|
|
148
|
-
if (!result.ok) {
|
|
149
|
-
expect(result.error).toBeInstanceOf(Error);
|
|
150
|
-
expect(result.error.message).toBe("undefined");
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
describe("tryCatch() - undefined edge cases", () => {
|
|
155
|
-
it("wraps thrown undefined in Error", () => {
|
|
156
|
-
const result = tryCatch(() => {
|
|
157
|
-
throw undefined;
|
|
158
|
-
});
|
|
159
|
-
expect(result.ok).toBe(false);
|
|
160
|
-
if (!result.ok) {
|
|
161
|
-
expect(result.error).toBeInstanceOf(Error);
|
|
162
|
-
expect(result.error.message).toBe("undefined");
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
it("wraps thrown void (undefined) in Error", () => {
|
|
166
|
-
// eslint-disable-next-line @typescript-eslint/no-throw-literal
|
|
167
|
-
const result = tryCatch(() => {
|
|
168
|
-
// This explicitly tests the edge case of a void throw
|
|
169
|
-
throw void 0;
|
|
170
|
-
});
|
|
171
|
-
expect(result.ok).toBe(false);
|
|
172
|
-
if (!result.ok) {
|
|
173
|
-
expect(result.error).toBeInstanceOf(Error);
|
|
174
|
-
expect(result.error.message).toBe("undefined");
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from "vitest";
|
|
2
|
-
import { suppressError } from "./suppress-error.js";
|
|
3
|
-
describe("suppressError()", () => {
|
|
4
|
-
it("does not throw when promise rejects", () => {
|
|
5
|
-
expect(() => {
|
|
6
|
-
suppressError(Promise.reject(new Error("test")), "cleanup");
|
|
7
|
-
}).not.toThrow();
|
|
8
|
-
});
|
|
9
|
-
it("logs the error reason at debug level when no logger provided", async () => {
|
|
10
|
-
const debugSpy = vi.spyOn(console, "debug").mockImplementation(() => { });
|
|
11
|
-
suppressError(Promise.reject(new Error("test error")), "cleanup task");
|
|
12
|
-
// Wait for the microtask queue to flush
|
|
13
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
14
|
-
expect(debugSpy).toHaveBeenCalledWith("Suppressed error (cleanup task): test error");
|
|
15
|
-
expect(debugSpy).toHaveBeenCalledTimes(1);
|
|
16
|
-
debugSpy.mockRestore();
|
|
17
|
-
});
|
|
18
|
-
it("uses custom logger when provided", async () => {
|
|
19
|
-
const debugSpy = vi.spyOn(console, "debug").mockImplementation(() => { });
|
|
20
|
-
const customLogger = vi.fn();
|
|
21
|
-
suppressError(Promise.reject(new Error("custom error")), "custom task", customLogger);
|
|
22
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
23
|
-
expect(customLogger).toHaveBeenCalledTimes(1);
|
|
24
|
-
expect(customLogger).toHaveBeenCalledWith("Suppressed error (custom task): custom error");
|
|
25
|
-
// console.debug should NOT be called when custom logger is provided
|
|
26
|
-
expect(debugSpy).not.toHaveBeenCalled();
|
|
27
|
-
debugSpy.mockRestore();
|
|
28
|
-
});
|
|
29
|
-
it("passes formatted error message string to custom logger", async () => {
|
|
30
|
-
const customLogger = vi.fn();
|
|
31
|
-
suppressError(Promise.reject(new Error("something broke")), "retry cleanup", customLogger);
|
|
32
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
33
|
-
expect(customLogger).toHaveBeenCalledWith("Suppressed error (retry cleanup): something broke");
|
|
34
|
-
});
|
|
35
|
-
it("handles non-Error rejection with custom logger", async () => {
|
|
36
|
-
const customLogger = vi.fn();
|
|
37
|
-
suppressError(Promise.reject("plain string rejection"), "string reject", customLogger);
|
|
38
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
39
|
-
expect(customLogger).toHaveBeenCalledWith("Suppressed error (string reject): plain string rejection");
|
|
40
|
-
});
|
|
41
|
-
it("does not cause unhandled rejection", async () => {
|
|
42
|
-
const unhandledHandler = vi.fn();
|
|
43
|
-
process.on("unhandledRejection", unhandledHandler);
|
|
44
|
-
suppressError(Promise.reject(new Error("should be caught")), "test");
|
|
45
|
-
// Wait enough for unhandledRejection to fire if it were going to
|
|
46
|
-
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
47
|
-
expect(unhandledHandler).not.toHaveBeenCalled();
|
|
48
|
-
process.removeListener("unhandledRejection", unhandledHandler);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from "vitest";
|
|
2
|
-
import { withTimeout, TimeoutError } from "./timeout.js";
|
|
3
|
-
describe("TimeoutError", () => {
|
|
4
|
-
it("has name set to 'TimeoutError'", () => {
|
|
5
|
-
const error = new TimeoutError(5000);
|
|
6
|
-
expect(error.name).toBe("TimeoutError");
|
|
7
|
-
});
|
|
8
|
-
it("is instanceof Error", () => {
|
|
9
|
-
const error = new TimeoutError(5000);
|
|
10
|
-
expect(error).toBeInstanceOf(Error);
|
|
11
|
-
});
|
|
12
|
-
it("has correct timeoutMs property", () => {
|
|
13
|
-
const error = new TimeoutError(3000);
|
|
14
|
-
expect(error.timeoutMs).toBe(3000);
|
|
15
|
-
});
|
|
16
|
-
it("formats message with label", () => {
|
|
17
|
-
const error = new TimeoutError(5000, "MCP connect");
|
|
18
|
-
expect(error.message).toBe("MCP connect timed out after 5000ms");
|
|
19
|
-
});
|
|
20
|
-
it("formats message without label", () => {
|
|
21
|
-
const error = new TimeoutError(5000);
|
|
22
|
-
expect(error.message).toBe("Operation timed out after 5000ms");
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
describe("withTimeout", () => {
|
|
26
|
-
it("resolves when promise completes before timeout", async () => {
|
|
27
|
-
const result = await withTimeout(Promise.resolve(42), 1000);
|
|
28
|
-
expect(result).toBe(42);
|
|
29
|
-
});
|
|
30
|
-
it("rejects with TimeoutError when timeout fires first", async () => {
|
|
31
|
-
const neverResolves = new Promise(() => { });
|
|
32
|
-
await expect(withTimeout(neverResolves, 10, "test op")).rejects.toThrow(TimeoutError);
|
|
33
|
-
});
|
|
34
|
-
it("TimeoutError has correct timeoutMs on rejection", async () => {
|
|
35
|
-
const neverResolves = new Promise(() => { });
|
|
36
|
-
try {
|
|
37
|
-
await withTimeout(neverResolves, 25, "test op");
|
|
38
|
-
throw new Error("Should not reach here");
|
|
39
|
-
}
|
|
40
|
-
catch (e) {
|
|
41
|
-
expect(e).toBeInstanceOf(TimeoutError);
|
|
42
|
-
expect(e.timeoutMs).toBe(25);
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
it("timer is cleaned up on success", async () => {
|
|
46
|
-
vi.useFakeTimers();
|
|
47
|
-
try {
|
|
48
|
-
const promise = Promise.resolve("ok");
|
|
49
|
-
await withTimeout(promise, 60_000);
|
|
50
|
-
// After resolution, advancing time should not cause issues
|
|
51
|
-
// (timer was cleared, no pending timers)
|
|
52
|
-
expect(vi.getTimerCount()).toBe(0);
|
|
53
|
-
}
|
|
54
|
-
finally {
|
|
55
|
-
vi.useRealTimers();
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
it("propagates original error when promise rejects before timeout", async () => {
|
|
59
|
-
const originalError = new Error("original failure");
|
|
60
|
-
const failing = Promise.reject(originalError);
|
|
61
|
-
await expect(withTimeout(failing, 5000)).rejects.toThrow("original failure");
|
|
62
|
-
await expect(withTimeout(Promise.reject(originalError), 5000)).rejects.not.toBeInstanceOf(TimeoutError);
|
|
63
|
-
});
|
|
64
|
-
it("no unhandled rejection when original promise rejects after timeout", async () => {
|
|
65
|
-
// Create a promise that rejects after a short delay
|
|
66
|
-
const delayedReject = new Promise((_resolve, reject) => {
|
|
67
|
-
setTimeout(() => reject(new Error("late rejection")), 50);
|
|
68
|
-
});
|
|
69
|
-
// The timeout fires first (10ms < 50ms)
|
|
70
|
-
await expect(withTimeout(delayedReject, 10, "test")).rejects.toThrow(TimeoutError);
|
|
71
|
-
// Wait for the delayed rejection to fire -- if unhandled rejection
|
|
72
|
-
// suppression is missing, this would crash the test runner
|
|
73
|
-
await new Promise((r) => setTimeout(r, 100));
|
|
74
|
-
});
|
|
75
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|