@tstdl/base 0.93.182 → 0.93.183
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/api/server/api-request-token.provider.js +1 -1
- package/api/server/gateway.js +6 -1
- package/authentication/authentication.api.d.ts +13 -40
- package/authentication/authentication.api.js +5 -14
- package/authentication/client/authentication.service.d.ts +6 -14
- package/authentication/client/authentication.service.js +22 -4
- package/authentication/client/module.d.ts +1 -1
- package/authentication/client/module.js +4 -4
- package/authentication/models/index.d.ts +1 -0
- package/authentication/models/index.js +1 -0
- package/authentication/models/totp-results.model.d.ts +11 -0
- package/authentication/models/totp-results.model.js +37 -0
- package/authentication/server/authentication.api-controller.d.ts +3 -3
- package/authentication/server/authentication.api-controller.js +31 -4
- package/authentication/server/authentication.service.d.ts +5 -14
- package/authentication/server/authentication.service.js +6 -4
- package/core.d.ts +0 -5
- package/core.js +0 -8
- package/document-management/api/document-management.api.d.ts +2 -2
- package/document-management/service-models/document.service-model.d.ts +1 -1
- package/examples/config.d.ts +25 -0
- package/examples/config.js +26 -0
- package/notification/server/module.d.ts +1 -1
- package/notification/server/module.js +1 -1
- package/package.json +5 -5
- package/signals/api.d.ts +5 -1
- package/signals/api.js +3 -1
- package/signals/implementation/api.d.ts +13 -5
- package/signals/implementation/api.js +7 -1
- package/signals/implementation/asserts.d.ts +2 -2
- package/signals/implementation/asserts.js +3 -3
- package/signals/implementation/computed.d.ts +7 -34
- package/signals/implementation/computed.js +14 -83
- package/signals/implementation/configure.js +6 -2
- package/signals/implementation/effect.d.ts +65 -46
- package/signals/implementation/effect.js +97 -62
- package/signals/implementation/index.d.ts +2 -4
- package/signals/implementation/index.js +2 -4
- package/signals/implementation/linked_signal.d.ts +36 -0
- package/signals/implementation/linked_signal.js +34 -0
- package/signals/implementation/primitive/computed.d.ts +55 -0
- package/signals/implementation/primitive/computed.js +107 -0
- package/signals/implementation/primitive/effect.d.ts +26 -0
- package/signals/implementation/primitive/effect.js +31 -0
- package/signals/implementation/{equality.d.ts → primitive/equality.d.ts} +1 -1
- package/signals/implementation/{equality.js → primitive/equality.js} +1 -1
- package/signals/implementation/primitive/errors.d.ts +10 -0
- package/signals/implementation/{errors.js → primitive/errors.js} +3 -4
- package/signals/implementation/primitive/formatter.d.ts +19 -0
- package/signals/implementation/primitive/formatter.js +136 -0
- package/signals/implementation/{graph.d.ts → primitive/graph.d.ts} +68 -36
- package/signals/implementation/primitive/graph.js +386 -0
- package/signals/implementation/primitive/linked_signal.d.ts +46 -0
- package/signals/implementation/primitive/linked_signal.js +110 -0
- package/signals/implementation/primitive/signal.d.ts +31 -0
- package/signals/implementation/primitive/signal.js +80 -0
- package/signals/implementation/primitive/untracked.d.ts +12 -0
- package/signals/implementation/primitive/untracked.js +23 -0
- package/signals/implementation/{watch.d.ts → primitive/watch.d.ts} +1 -2
- package/signals/implementation/{watch.js → primitive/watch.js} +22 -16
- package/signals/implementation/resource/api.d.ts +275 -0
- package/signals/implementation/resource/api.js +26 -0
- package/signals/implementation/resource/debounce.d.ts +13 -0
- package/signals/implementation/resource/debounce.js +113 -0
- package/signals/implementation/resource/from_snapshots.d.ts +16 -0
- package/signals/implementation/resource/from_snapshots.js +44 -0
- package/signals/implementation/resource/index.d.ts +11 -0
- package/signals/implementation/resource/index.js +11 -0
- package/signals/implementation/resource/resource.d.ts +110 -0
- package/signals/implementation/resource/resource.js +402 -0
- package/signals/implementation/root_effect_scheduler.d.ts +50 -0
- package/signals/implementation/root_effect_scheduler.js +66 -0
- package/signals/implementation/signal.d.ts +42 -18
- package/signals/implementation/signal.js +29 -49
- package/signals/implementation/to-observable.d.ts +12 -5
- package/signals/implementation/to-observable.js +12 -2
- package/signals/implementation/to-signal.d.ts +9 -18
- package/signals/implementation/to-signal.js +46 -13
- package/signals/implementation/untracked.d.ts +1 -1
- package/signals/implementation/untracked.js +3 -11
- package/signals/operators/debounce.d.ts +8 -0
- package/signals/operators/debounce.js +19 -0
- package/signals/operators/derive-async.js +43 -15
- package/signals/operators/index.d.ts +2 -0
- package/signals/operators/index.js +2 -0
- package/signals/operators/throttle.d.ts +8 -0
- package/signals/operators/throttle.js +31 -0
- package/ai/genkit/tests/multi-region.test.d.ts +0 -2
- package/ai/genkit/tests/multi-region.test.js +0 -179
- package/ai/genkit/tests/token-limit-fallback.test.d.ts +0 -2
- package/ai/genkit/tests/token-limit-fallback.test.js +0 -209
- package/ai/prompts/tests/prompt-builder.test.d.ts +0 -1
- package/ai/prompts/tests/prompt-builder.test.js +0 -22
- package/ai/tests/instructions-formatter.test.d.ts +0 -1
- package/ai/tests/instructions-formatter.test.js +0 -116
- package/ai/tests/steering.test.d.ts +0 -1
- package/ai/tests/steering.test.js +0 -37
- package/api/client/tests/api-client.test.d.ts +0 -1
- package/api/client/tests/api-client.test.js +0 -194
- package/api/server/tests/csrf.middleware.test.d.ts +0 -1
- package/api/server/tests/csrf.middleware.test.js +0 -91
- package/authentication/tests/authentication-password-requirements.validator.test.d.ts +0 -1
- package/authentication/tests/authentication-password-requirements.validator.test.js +0 -29
- package/authentication/tests/authentication.api-controller.test.d.ts +0 -1
- package/authentication/tests/authentication.api-controller.test.js +0 -156
- package/authentication/tests/authentication.api-request-token.provider.test.d.ts +0 -1
- package/authentication/tests/authentication.api-request-token.provider.test.js +0 -48
- package/authentication/tests/authentication.client-error-handling.test.d.ts +0 -1
- package/authentication/tests/authentication.client-error-handling.test.js +0 -123
- package/authentication/tests/authentication.client-middleware.test.d.ts +0 -1
- package/authentication/tests/authentication.client-middleware.test.js +0 -118
- package/authentication/tests/authentication.client-service-methods.test.d.ts +0 -1
- package/authentication/tests/authentication.client-service-methods.test.js +0 -177
- package/authentication/tests/authentication.client-service-refresh.test.d.ts +0 -1
- package/authentication/tests/authentication.client-service-refresh.test.js +0 -153
- package/authentication/tests/authentication.client-service.test.d.ts +0 -1
- package/authentication/tests/authentication.client-service.test.js +0 -76
- package/authentication/tests/authentication.refresh-busy-loop.test.d.ts +0 -1
- package/authentication/tests/authentication.refresh-busy-loop.test.js +0 -84
- package/authentication/tests/authentication.service.test.d.ts +0 -1
- package/authentication/tests/authentication.service.test.js +0 -167
- package/authentication/tests/authentication.test-ancillary-service.d.ts +0 -9
- package/authentication/tests/authentication.test-ancillary-service.js +0 -27
- package/authentication/tests/brute-force-protection.test.d.ts +0 -1
- package/authentication/tests/brute-force-protection.test.js +0 -211
- package/authentication/tests/helper.test.d.ts +0 -1
- package/authentication/tests/helper.test.js +0 -122
- package/authentication/tests/password-requirements.error.test.d.ts +0 -1
- package/authentication/tests/password-requirements.error.test.js +0 -14
- package/authentication/tests/remember.api.test.d.ts +0 -1
- package/authentication/tests/remember.api.test.js +0 -117
- package/authentication/tests/remember.service.test.d.ts +0 -1
- package/authentication/tests/remember.service.test.js +0 -83
- package/authentication/tests/subject.service.test.d.ts +0 -1
- package/authentication/tests/subject.service.test.js +0 -140
- package/authentication/tests/suspended-subject.test.d.ts +0 -1
- package/authentication/tests/suspended-subject.test.js +0 -120
- package/authentication/tests/totp.enrollment.test.d.ts +0 -1
- package/authentication/tests/totp.enrollment.test.js +0 -123
- package/authentication/tests/totp.login.test.d.ts +0 -1
- package/authentication/tests/totp.login.test.js +0 -213
- package/authentication/tests/totp.recovery-codes.test.d.ts +0 -1
- package/authentication/tests/totp.recovery-codes.test.js +0 -97
- package/authentication/tests/totp.status.test.d.ts +0 -1
- package/authentication/tests/totp.status.test.js +0 -72
- package/cancellation/tests/coverage.test.d.ts +0 -1
- package/cancellation/tests/coverage.test.js +0 -49
- package/cancellation/tests/leak.test.d.ts +0 -1
- package/cancellation/tests/leak.test.js +0 -35
- package/cancellation/tests/token.test.d.ts +0 -1
- package/cancellation/tests/token.test.js +0 -136
- package/circuit-breaker/tests/circuit-breaker.test.d.ts +0 -1
- package/circuit-breaker/tests/circuit-breaker.test.js +0 -116
- package/cryptography/tests/cryptography.test.d.ts +0 -1
- package/cryptography/tests/cryptography.test.js +0 -175
- package/cryptography/tests/jwt.test.d.ts +0 -1
- package/cryptography/tests/jwt.test.js +0 -54
- package/cryptography/tests/modern.test.d.ts +0 -1
- package/cryptography/tests/modern.test.js +0 -105
- package/cryptography/tests/module.test.d.ts +0 -1
- package/cryptography/tests/module.test.js +0 -100
- package/cryptography/tests/totp.test.d.ts +0 -1
- package/cryptography/tests/totp.test.js +0 -108
- package/document-management/tests/ai-config-hierarchy.test.d.ts +0 -1
- package/document-management/tests/ai-config-hierarchy.test.js +0 -59
- package/document-management/tests/ai-config-integration.test.d.ts +0 -1
- package/document-management/tests/ai-config-integration.test.js +0 -125
- package/document-management/tests/ai-config-merge.test.d.ts +0 -1
- package/document-management/tests/ai-config-merge.test.js +0 -46
- package/document-management/tests/document-management-ai-overrides.test.d.ts +0 -1
- package/document-management/tests/document-management-ai-overrides.test.js +0 -63
- package/document-management/tests/document-management-core.test.d.ts +0 -1
- package/document-management/tests/document-management-core.test.js +0 -157
- package/document-management/tests/document-management.api.test.d.ts +0 -1
- package/document-management/tests/document-management.api.test.js +0 -101
- package/document-management/tests/document-statistics.service.test.d.ts +0 -1
- package/document-management/tests/document-statistics.service.test.js +0 -498
- package/document-management/tests/document-validation-ai-overrides.test.d.ts +0 -1
- package/document-management/tests/document-validation-ai-overrides.test.js +0 -87
- package/document-management/tests/document.service.test.d.ts +0 -1
- package/document-management/tests/document.service.test.js +0 -143
- package/document-management/tests/enum-helpers.test.d.ts +0 -1
- package/document-management/tests/enum-helpers.test.js +0 -452
- package/document-management/tests/helper.d.ts +0 -24
- package/document-management/tests/helper.js +0 -39
- package/errors/tests/format.test.d.ts +0 -1
- package/errors/tests/format.test.js +0 -84
- package/http/tests/server-timing.test.d.ts +0 -1
- package/http/tests/server-timing.test.js +0 -42
- package/injector/tests/advanced.test.d.ts +0 -1
- package/injector/tests/advanced.test.js +0 -116
- package/injector/tests/async-init.test.d.ts +0 -1
- package/injector/tests/async-init.test.js +0 -77
- package/injector/tests/basic.test.d.ts +0 -1
- package/injector/tests/basic.test.js +0 -114
- package/injector/tests/hierarchical.test.d.ts +0 -1
- package/injector/tests/hierarchical.test.js +0 -59
- package/injector/tests/leak.test.d.ts +0 -1
- package/injector/tests/leak.test.js +0 -45
- package/injector/tests/lifecycles.test.d.ts +0 -1
- package/injector/tests/lifecycles.test.js +0 -109
- package/logger/tests/pretty-print.test.d.ts +0 -1
- package/logger/tests/pretty-print.test.js +0 -60
- package/notification/tests/notification-api.test.d.ts +0 -1
- package/notification/tests/notification-api.test.js +0 -124
- package/notification/tests/notification-client.test.d.ts +0 -1
- package/notification/tests/notification-client.test.js +0 -101
- package/notification/tests/notification-flow.test.d.ts +0 -1
- package/notification/tests/notification-flow.test.js +0 -296
- package/notification/tests/notification-sse.service.test.d.ts +0 -1
- package/notification/tests/notification-sse.service.test.js +0 -43
- package/notification/tests/notification-type.service.test.d.ts +0 -1
- package/notification/tests/notification-type.service.test.js +0 -41
- package/object-storage/s3/tests/s3.object-storage.integration.test.d.ts +0 -1
- package/object-storage/s3/tests/s3.object-storage.integration.test.js +0 -303
- package/orm/tests/build-jsonb.test.d.ts +0 -1
- package/orm/tests/build-jsonb.test.js +0 -39
- package/orm/tests/data-types.test.d.ts +0 -1
- package/orm/tests/data-types.test.js +0 -39
- package/orm/tests/database-extension.test.d.ts +0 -1
- package/orm/tests/database-extension.test.js +0 -63
- package/orm/tests/database-migration.test.d.ts +0 -1
- package/orm/tests/database-migration.test.js +0 -83
- package/orm/tests/decorators.test.d.ts +0 -1
- package/orm/tests/decorators.test.js +0 -77
- package/orm/tests/encryption.test.d.ts +0 -1
- package/orm/tests/encryption.test.js +0 -31
- package/orm/tests/query-complex.test.d.ts +0 -1
- package/orm/tests/query-complex.test.js +0 -172
- package/orm/tests/query-converter-complex.test.d.ts +0 -1
- package/orm/tests/query-converter-complex.test.js +0 -131
- package/orm/tests/query-converter.test.d.ts +0 -1
- package/orm/tests/query-converter.test.js +0 -123
- package/orm/tests/repository-advanced.test.d.ts +0 -1
- package/orm/tests/repository-advanced.test.js +0 -189
- package/orm/tests/repository-attributes.test.d.ts +0 -1
- package/orm/tests/repository-attributes.test.js +0 -83
- package/orm/tests/repository-compound-primary-key.test.d.ts +0 -2
- package/orm/tests/repository-compound-primary-key.test.js +0 -226
- package/orm/tests/repository-comprehensive.test.d.ts +0 -1
- package/orm/tests/repository-comprehensive.test.js +0 -162
- package/orm/tests/repository-coverage.test.d.ts +0 -2
- package/orm/tests/repository-coverage.test.js +0 -242
- package/orm/tests/repository-cti-complex.test.d.ts +0 -1
- package/orm/tests/repository-cti-complex.test.js +0 -151
- package/orm/tests/repository-cti-embedded.test.d.ts +0 -1
- package/orm/tests/repository-cti-embedded.test.js +0 -178
- package/orm/tests/repository-cti-extensive.test.d.ts +0 -2
- package/orm/tests/repository-cti-extensive.test.js +0 -279
- package/orm/tests/repository-cti-mapping.test.d.ts +0 -2
- package/orm/tests/repository-cti-mapping.test.js +0 -108
- package/orm/tests/repository-cti-search.test.d.ts +0 -1
- package/orm/tests/repository-cti-search.test.js +0 -141
- package/orm/tests/repository-cti-soft-delete.test.d.ts +0 -2
- package/orm/tests/repository-cti-soft-delete.test.js +0 -103
- package/orm/tests/repository-cti-transactions.test.d.ts +0 -1
- package/orm/tests/repository-cti-transactions.test.js +0 -112
- package/orm/tests/repository-cti-upsert-many.test.d.ts +0 -2
- package/orm/tests/repository-cti-upsert-many.test.js +0 -115
- package/orm/tests/repository-cti.test.d.ts +0 -2
- package/orm/tests/repository-cti.test.js +0 -390
- package/orm/tests/repository-edge-cases.test.d.ts +0 -1
- package/orm/tests/repository-edge-cases.test.js +0 -178
- package/orm/tests/repository-expiration.test.d.ts +0 -2
- package/orm/tests/repository-expiration.test.js +0 -140
- package/orm/tests/repository-extra-coverage.test.d.ts +0 -2
- package/orm/tests/repository-extra-coverage.test.js +0 -402
- package/orm/tests/repository-mapping.test.d.ts +0 -2
- package/orm/tests/repository-mapping.test.js +0 -65
- package/orm/tests/repository-regression.test.d.ts +0 -1
- package/orm/tests/repository-regression.test.js +0 -288
- package/orm/tests/repository-search-coverage.test.d.ts +0 -1
- package/orm/tests/repository-search-coverage.test.js +0 -107
- package/orm/tests/repository-search.test.d.ts +0 -1
- package/orm/tests/repository-search.test.js +0 -105
- package/orm/tests/repository-soft-delete.test.d.ts +0 -1
- package/orm/tests/repository-soft-delete.test.js +0 -118
- package/orm/tests/repository-transactions-nested.test.d.ts +0 -1
- package/orm/tests/repository-transactions-nested.test.js +0 -178
- package/orm/tests/repository-types.test.d.ts +0 -1
- package/orm/tests/repository-types.test.js +0 -184
- package/orm/tests/repository-undelete.test.d.ts +0 -2
- package/orm/tests/repository-undelete.test.js +0 -201
- package/orm/tests/schema-converter.test.d.ts +0 -1
- package/orm/tests/schema-converter.test.js +0 -82
- package/orm/tests/schema-generation.test.d.ts +0 -2
- package/orm/tests/schema-generation.test.js +0 -174
- package/orm/tests/sql-helpers.test.d.ts +0 -1
- package/orm/tests/sql-helpers.test.js +0 -67
- package/orm/tests/transaction-safety.test.d.ts +0 -1
- package/orm/tests/transaction-safety.test.js +0 -81
- package/orm/tests/transactional.test.d.ts +0 -1
- package/orm/tests/transactional.test.js +0 -215
- package/orm/tests/utils.test.d.ts +0 -1
- package/orm/tests/utils.test.js +0 -70
- package/pdf/tests/utils.test.d.ts +0 -1
- package/pdf/tests/utils.test.js +0 -187
- package/process/tests/spawn.test.d.ts +0 -1
- package/process/tests/spawn.test.js +0 -182
- package/rate-limit/tests/postgres-rate-limiter.test.d.ts +0 -1
- package/rate-limit/tests/postgres-rate-limiter.test.js +0 -84
- package/renderer/tests/renderer.test.d.ts +0 -1
- package/renderer/tests/renderer.test.js +0 -88
- package/rpc/tests/rpc.integration.test.d.ts +0 -1
- package/rpc/tests/rpc.integration.test.js +0 -615
- package/signals/implementation/errors.d.ts +0 -2
- package/signals/implementation/graph.js +0 -312
- package/signals/implementation/writable-signal.d.ts +0 -48
- package/signals/implementation/writable-signal.js +0 -32
- package/task-queue/tests/coverage-branch.test.d.ts +0 -1
- package/task-queue/tests/coverage-branch.test.js +0 -395
- package/task-queue/tests/coverage-enhancement.test.d.ts +0 -1
- package/task-queue/tests/coverage-enhancement.test.js +0 -150
- package/task-queue/tests/dag.test.d.ts +0 -1
- package/task-queue/tests/dag.test.js +0 -188
- package/task-queue/tests/dependencies.test.d.ts +0 -1
- package/task-queue/tests/dependencies.test.js +0 -296
- package/task-queue/tests/enqueue-batch.test.d.ts +0 -1
- package/task-queue/tests/enqueue-batch.test.js +0 -125
- package/task-queue/tests/enqueue-item.test.d.ts +0 -1
- package/task-queue/tests/enqueue-item.test.js +0 -12
- package/task-queue/tests/fan-out-spawning.test.d.ts +0 -1
- package/task-queue/tests/fan-out-spawning.test.js +0 -94
- package/task-queue/tests/idempotent-replacement.test.d.ts +0 -1
- package/task-queue/tests/idempotent-replacement.test.js +0 -114
- package/task-queue/tests/missing-idempotent-tasks.test.d.ts +0 -1
- package/task-queue/tests/missing-idempotent-tasks.test.js +0 -39
- package/task-queue/tests/optimization-edge-cases.test.d.ts +0 -1
- package/task-queue/tests/optimization-edge-cases.test.js +0 -124
- package/task-queue/tests/queue-generic.test.d.ts +0 -1
- package/task-queue/tests/queue-generic.test.js +0 -8
- package/task-queue/tests/queue.test.d.ts +0 -1
- package/task-queue/tests/queue.test.js +0 -756
- package/task-queue/tests/shutdown.test.d.ts +0 -1
- package/task-queue/tests/shutdown.test.js +0 -41
- package/task-queue/tests/task-context.test.d.ts +0 -1
- package/task-queue/tests/task-context.test.js +0 -7
- package/task-queue/tests/task-union.test.d.ts +0 -1
- package/task-queue/tests/task-union.test.js +0 -18
- package/task-queue/tests/transactions.test.d.ts +0 -1
- package/task-queue/tests/transactions.test.js +0 -47
- package/task-queue/tests/typing.test.d.ts +0 -1
- package/task-queue/tests/typing.test.js +0 -9
- package/task-queue/tests/worker.test.d.ts +0 -1
- package/task-queue/tests/worker.test.js +0 -258
- package/task-queue/tests/zombie-parent.test.d.ts +0 -1
- package/task-queue/tests/zombie-parent.test.js +0 -45
- package/task-queue/tests/zombie-recovery.test.d.ts +0 -1
- package/task-queue/tests/zombie-recovery.test.js +0 -51
- package/utils/tests/backoff.test.d.ts +0 -1
- package/utils/tests/backoff.test.js +0 -41
- package/utils/tests/retry-with-backoff.test.d.ts +0 -1
- package/utils/tests/retry-with-backoff.test.js +0 -49
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'vitest';
|
|
2
|
-
import { importKey } from '../cryptography.js';
|
|
3
|
-
import { encodeTotpSecret, generateTotpRecoveryCodes, generateTotpSecret, generateTotpToken, generateTotpUri, hashTotpRecoveryCode, verifyTotpRecoveryCode, verifyTotpToken } from '../totp.js';
|
|
4
|
-
const totpOptions = {
|
|
5
|
-
codeHashAlgorithm: 'SHA-1',
|
|
6
|
-
recoveryCodeHashOptions: {
|
|
7
|
-
algorithm: { name: 'PBKDF2', hash: 'SHA-256', salt: new Uint8Array(16), iterations: 10 },
|
|
8
|
-
length: 64,
|
|
9
|
-
},
|
|
10
|
-
};
|
|
11
|
-
describe('TOTP Utilities', () => {
|
|
12
|
-
test('should generate a secret of appropriate length', () => {
|
|
13
|
-
expect(generateTotpSecret('SHA-1').byteLength).toBe(20);
|
|
14
|
-
expect(generateTotpSecret('SHA-256').byteLength).toBe(32);
|
|
15
|
-
expect(generateTotpSecret('SHA-512').byteLength).toBe(64);
|
|
16
|
-
});
|
|
17
|
-
test('should generate a valid TOTP token', async () => {
|
|
18
|
-
const secretData = new Uint8Array(new ArrayBuffer(20));
|
|
19
|
-
secretData.fill(1);
|
|
20
|
-
const secret = await importKey('raw-secret', secretData, { name: 'HMAC', hash: 'SHA-1' }, false, ['sign']);
|
|
21
|
-
const token = await generateTotpToken(secret, { ...totpOptions, timestamp: 1000000000 });
|
|
22
|
-
expect(token).toMatch(/^\d{6}$/);
|
|
23
|
-
});
|
|
24
|
-
test('should verify a valid TOTP token', async () => {
|
|
25
|
-
const secretData = new Uint8Array(new ArrayBuffer(20));
|
|
26
|
-
secretData.fill(1);
|
|
27
|
-
const secret = await importKey('raw-secret', secretData, { name: 'HMAC', hash: 'SHA-1' }, false, ['sign']);
|
|
28
|
-
const timestamp = 1000000000;
|
|
29
|
-
const token = await generateTotpToken(secret, { ...totpOptions, timestamp });
|
|
30
|
-
const isValid = await verifyTotpToken(secret, token, { ...totpOptions, timestamp });
|
|
31
|
-
expect(isValid).toBe(true);
|
|
32
|
-
});
|
|
33
|
-
test('should fail to verify an invalid TOTP token', async () => {
|
|
34
|
-
const secretData = new Uint8Array(new ArrayBuffer(20));
|
|
35
|
-
secretData.fill(1);
|
|
36
|
-
const secret = await importKey('raw-secret', secretData, { name: 'HMAC', hash: 'SHA-1' }, false, ['sign']);
|
|
37
|
-
const isValid = await verifyTotpToken(secret, '000000', { ...totpOptions, timestamp: 1000000000 });
|
|
38
|
-
expect(isValid).toBe(false);
|
|
39
|
-
});
|
|
40
|
-
test('should generate a valid otpauth URI', () => {
|
|
41
|
-
const secret = new Uint8Array(new ArrayBuffer(20));
|
|
42
|
-
secret.fill(1);
|
|
43
|
-
const encodedSecret = encodeTotpSecret(secret);
|
|
44
|
-
const uri = generateTotpUri(encodedSecret, 'user@example.com', 'MyApp', totpOptions);
|
|
45
|
-
expect(uri).toBe('otpauth://totp/MyApp:user%40example.com?secret=AEAQCAIBAEAQCAIBAEAQCAIBAEAQCAIB&issuer=MyApp&algorithm=SHA1&digits=6&period=30');
|
|
46
|
-
});
|
|
47
|
-
test('should generate a valid otpauth URI with SHA-256', () => {
|
|
48
|
-
const secret = new Uint8Array(new ArrayBuffer(32));
|
|
49
|
-
secret.fill(1);
|
|
50
|
-
const encodedSecret = encodeTotpSecret(secret);
|
|
51
|
-
const uri = generateTotpUri(encodedSecret, 'user@example.com', 'MyApp', { ...totpOptions, codeHashAlgorithm: 'SHA-256' });
|
|
52
|
-
expect(uri).toBe('otpauth://totp/MyApp:user%40example.com?secret=AEAQCAIBAEAQCAIBAEAQCAIBAEAQCAIBAEAQCAIBAEAQCAIBAEAQ&issuer=MyApp&algorithm=SHA256&digits=6&period=30');
|
|
53
|
-
});
|
|
54
|
-
test('should verify a valid TOTP token with SHA-256', async () => {
|
|
55
|
-
const secretData = new Uint8Array(new ArrayBuffer(32));
|
|
56
|
-
secretData.fill(1);
|
|
57
|
-
const secret = await importKey('raw-secret', secretData, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
|
|
58
|
-
const timestamp = 1000000000;
|
|
59
|
-
const options = { ...totpOptions, timestamp, codeHashAlgorithm: 'SHA-256' };
|
|
60
|
-
const token = await generateTotpToken(secret, options);
|
|
61
|
-
const isValid = await verifyTotpToken(secret, token, options);
|
|
62
|
-
expect(isValid).toBe(true);
|
|
63
|
-
});
|
|
64
|
-
test('should verify a valid TOTP token with SHA-512', async () => {
|
|
65
|
-
const secretData = new Uint8Array(new ArrayBuffer(64));
|
|
66
|
-
secretData.fill(1);
|
|
67
|
-
const secret = await importKey('raw-secret', secretData, { name: 'HMAC', hash: 'SHA-512' }, false, ['sign']);
|
|
68
|
-
const timestamp = 1000000000;
|
|
69
|
-
const options = { ...totpOptions, timestamp, codeHashAlgorithm: 'SHA-512' };
|
|
70
|
-
const token = await generateTotpToken(secret, options);
|
|
71
|
-
const isValid = await verifyTotpToken(secret, token, options);
|
|
72
|
-
expect(isValid).toBe(true);
|
|
73
|
-
});
|
|
74
|
-
test('should generate recovery codes', () => {
|
|
75
|
-
const codes = generateTotpRecoveryCodes(10, 8);
|
|
76
|
-
expect(codes.length).toBe(10);
|
|
77
|
-
for (const code of codes) {
|
|
78
|
-
expect(code).toMatch(/^[A-Z2-7]{8}$/);
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
test('should hash and verify a recovery code', async () => {
|
|
82
|
-
const code = 'ABCDEFGH';
|
|
83
|
-
const salt = new Uint8Array(new ArrayBuffer(16));
|
|
84
|
-
salt.fill(1);
|
|
85
|
-
const options = { algorithm: { name: 'PBKDF2', hash: 'SHA-256', salt, iterations: 10 }, length: 64 };
|
|
86
|
-
const hash = await hashTotpRecoveryCode(code, options);
|
|
87
|
-
const isValid = await verifyTotpRecoveryCode(code, hash, options);
|
|
88
|
-
expect(isValid).toBe(true);
|
|
89
|
-
});
|
|
90
|
-
test('should fail to verify an invalid recovery code', async () => {
|
|
91
|
-
const code = 'ABCDEFGH';
|
|
92
|
-
const salt = new Uint8Array(new ArrayBuffer(16));
|
|
93
|
-
salt.fill(1);
|
|
94
|
-
const options = { algorithm: { name: 'PBKDF2', hash: 'SHA-256', salt, iterations: 10 }, length: 64 };
|
|
95
|
-
const hash = await hashTotpRecoveryCode(code, options);
|
|
96
|
-
const isValid = await verifyTotpRecoveryCode('WRONGONE', hash, options);
|
|
97
|
-
expect(isValid).toBe(false);
|
|
98
|
-
});
|
|
99
|
-
test('should hash and verify a recovery code with Argon2id', async () => {
|
|
100
|
-
const code = 'ABCDEFGH';
|
|
101
|
-
const salt = new Uint8Array(new ArrayBuffer(16));
|
|
102
|
-
salt.fill(1);
|
|
103
|
-
const options = { algorithm: { name: 'Argon2id', parallelism: 1, memory: 1024, passes: 1, nonce: salt }, length: 64 };
|
|
104
|
-
const hash = await hashTotpRecoveryCode(code, options);
|
|
105
|
-
const isValid = await verifyTotpRecoveryCode(code, hash, options);
|
|
106
|
-
expect(isValid).toBe(true);
|
|
107
|
-
});
|
|
108
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { afterAll, beforeAll, describe, expect, test, vi } from 'vitest';
|
|
2
|
-
import { injectModel } from '../../ai/genkit/index.js';
|
|
3
|
-
import { runInInjectionContext } from '../../injector/index.js';
|
|
4
|
-
import { setupIntegrationTest } from '../../testing/index.js';
|
|
5
|
-
import { DocumentManagementAiService } from '../server/services/document-management-ai.service.js';
|
|
6
|
-
import { DocumentCategoryTypeService, DocumentManagementAiProviderService, DocumentManagementAncillaryService } from '../server/services/index.js';
|
|
7
|
-
import { TestDocumentManagementAncillaryService } from './helper.js';
|
|
8
|
-
describe('DocumentManagementAiService Hierarchy', () => {
|
|
9
|
-
let injector;
|
|
10
|
-
let aiService;
|
|
11
|
-
const tenantId = crypto.randomUUID();
|
|
12
|
-
const mockAiProvider = {
|
|
13
|
-
getGlobalConfiguration: vi.fn(),
|
|
14
|
-
getClassificationConfiguration: vi.fn(),
|
|
15
|
-
getDataExtractionConfiguration: vi.fn(),
|
|
16
|
-
getAssignmentConfiguration: vi.fn(),
|
|
17
|
-
getValidationConfiguration: vi.fn(),
|
|
18
|
-
getContentExtractionConfiguration: vi.fn(),
|
|
19
|
-
};
|
|
20
|
-
beforeAll(async () => {
|
|
21
|
-
({ injector } = await setupIntegrationTest({
|
|
22
|
-
modules: { messageBus: true, signals: true, objectStorage: true, documentManagement: true },
|
|
23
|
-
}));
|
|
24
|
-
injector.register(DocumentManagementAiProviderService, { useValue: mockAiProvider });
|
|
25
|
-
// Ancillary and configuration are already registered by setupIntegrationTest, but we can override if needed
|
|
26
|
-
injector.register(DocumentManagementAncillaryService, { useToken: TestDocumentManagementAncillaryService });
|
|
27
|
-
aiService = await injector.resolveAsync(DocumentManagementAiService);
|
|
28
|
-
});
|
|
29
|
-
afterAll(async () => {
|
|
30
|
-
await injector?.dispose();
|
|
31
|
-
});
|
|
32
|
-
test('resolveAiConfiguration should implement Type > Category > Global Step > Global Defaults hierarchy', async () => {
|
|
33
|
-
const categoryTypeService = await injector.resolveAsync(DocumentCategoryTypeService);
|
|
34
|
-
const category = await categoryTypeService.createCategory({ tenantId, label: 'Finance', key: 'finance-cat', parentId: null });
|
|
35
|
-
const type = await categoryTypeService.createType({ tenantId, categoryId: category.id, label: 'Invoice', key: 'invoice-type' });
|
|
36
|
-
mockAiProvider.getGlobalConfiguration.mockResolvedValue({
|
|
37
|
-
defaults: { language: 'de', classification: 'Global Default Classify' },
|
|
38
|
-
steps: {
|
|
39
|
-
'data-extraction': { language: 'en', extraction: { title: 'Global Step Title' } }
|
|
40
|
-
},
|
|
41
|
-
categories: {
|
|
42
|
-
'finance-cat': { extraction: { title: 'Category Title', subtitle: 'Category Subtitle' } }
|
|
43
|
-
},
|
|
44
|
-
documentTypes: {
|
|
45
|
-
'invoice-type': { extraction: { title: 'Type Title' } }
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
mockAiProvider.getDataExtractionConfiguration.mockResolvedValue({
|
|
49
|
-
extraction: { subtitle: 'Provider Subtitle' }
|
|
50
|
-
});
|
|
51
|
-
await runInInjectionContext(injector, async () => {
|
|
52
|
-
const config = await aiService.resolveAiConfiguration(tenantId, 'data-extraction', { type });
|
|
53
|
-
expect(config.language).toBe('en'); // Step > Defaults
|
|
54
|
-
expect(config.classification).toBe('Global Default Classify'); // Fallback to defaults
|
|
55
|
-
expect(config.extraction.title).toBe('Type Title'); // Type > Category > Step
|
|
56
|
-
expect(config.extraction.subtitle).toBe('Provider Subtitle'); // Provider > Category
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { afterAll, beforeAll, describe, expect, test, vi } from 'vitest';
|
|
2
|
-
const mockGenerate = vi.fn();
|
|
3
|
-
vi.mock('genkit', async () => {
|
|
4
|
-
const original = await vi.importActual('genkit');
|
|
5
|
-
return {
|
|
6
|
-
...original,
|
|
7
|
-
genkit: () => ({
|
|
8
|
-
generate: mockGenerate,
|
|
9
|
-
}),
|
|
10
|
-
};
|
|
11
|
-
});
|
|
12
|
-
import { injectModel } from '../../ai/genkit/index.js';
|
|
13
|
-
import { runInInjectionContext } from '../../injector/index.js';
|
|
14
|
-
import { ObjectStorage } from '../../object-storage/index.js';
|
|
15
|
-
import { setupIntegrationTest } from '../../testing/index.js';
|
|
16
|
-
import { DocumentCategoryTypeService } from '../server/services/document-category-type.service.js';
|
|
17
|
-
import { DocumentManagementAiService } from '../server/services/document-management-ai.service.js';
|
|
18
|
-
import { DocumentService } from '../server/services/document.service.js';
|
|
19
|
-
import { DocumentManagementAiProviderService, DocumentManagementAncillaryService } from '../server/services/index.js';
|
|
20
|
-
import { TestDocumentManagementAncillaryService } from './helper.js';
|
|
21
|
-
describe('DocumentManagementAiService Integration', () => {
|
|
22
|
-
let injector;
|
|
23
|
-
let aiService;
|
|
24
|
-
let flashModel;
|
|
25
|
-
const tenantId = crypto.randomUUID();
|
|
26
|
-
const mockAiProvider = {
|
|
27
|
-
getGlobalConfiguration: vi.fn(),
|
|
28
|
-
getClassificationConfiguration: vi.fn(),
|
|
29
|
-
getDataExtractionConfiguration: vi.fn(),
|
|
30
|
-
getAssignmentConfiguration: vi.fn(),
|
|
31
|
-
getValidationConfiguration: vi.fn(),
|
|
32
|
-
getContentExtractionConfiguration: vi.fn(),
|
|
33
|
-
};
|
|
34
|
-
beforeAll(async () => {
|
|
35
|
-
({ injector } = await setupIntegrationTest({
|
|
36
|
-
modules: { messageBus: true, signals: true, objectStorage: true, documentManagement: true, taskQueue: true },
|
|
37
|
-
}));
|
|
38
|
-
const mockObjectStorage = {
|
|
39
|
-
store: vi.fn().mockResolvedValue({ mimeType: 'application/pdf', hash: 'hash', size: 100 }),
|
|
40
|
-
uploadObject: vi.fn(),
|
|
41
|
-
getDownloadUrl: vi.fn(),
|
|
42
|
-
getContent: vi.fn().mockResolvedValue(new Uint8Array([1, 2, 3])),
|
|
43
|
-
getContentStream: vi.fn(),
|
|
44
|
-
getObject: vi.fn(),
|
|
45
|
-
exists: vi.fn(),
|
|
46
|
-
};
|
|
47
|
-
runInInjectionContext(injector, () => {
|
|
48
|
-
flashModel = injectModel('gemini-2.5-flash');
|
|
49
|
-
});
|
|
50
|
-
injector.register(DocumentManagementAiProviderService, { useValue: mockAiProvider });
|
|
51
|
-
injector.register(DocumentManagementAncillaryService, { useToken: TestDocumentManagementAncillaryService });
|
|
52
|
-
injector.register(ObjectStorage, { useValue: mockObjectStorage });
|
|
53
|
-
aiService = await injector.resolveAsync(DocumentManagementAiService);
|
|
54
|
-
});
|
|
55
|
-
afterAll(async () => {
|
|
56
|
-
await injector?.dispose();
|
|
57
|
-
});
|
|
58
|
-
test('extractData should include granular instructions in prompt', async () => {
|
|
59
|
-
const categoryTypeService = await injector.resolveAsync(DocumentCategoryTypeService);
|
|
60
|
-
const documentService = await injector.resolveAsync(DocumentService);
|
|
61
|
-
const category = await categoryTypeService.createCategory({ tenantId, label: 'Finance', key: 'finance', parentId: null });
|
|
62
|
-
const type = await categoryTypeService.createType({ tenantId, categoryId: category.id, label: 'Invoice', key: 'invoice' });
|
|
63
|
-
const document = await documentService.create(tenantId, {
|
|
64
|
-
typeId: type.id,
|
|
65
|
-
originalFileName: 'test.pdf',
|
|
66
|
-
skipWorkflow: true,
|
|
67
|
-
assignment: { collections: [] }
|
|
68
|
-
}, new Uint8Array([1, 2, 3]));
|
|
69
|
-
mockAiProvider.getGlobalConfiguration.mockResolvedValue({
|
|
70
|
-
documentTypes: {
|
|
71
|
-
'invoice': {
|
|
72
|
-
extraction: {
|
|
73
|
-
title: { format: 'INV-{{Date}}' },
|
|
74
|
-
summary: { content: 'Focus on items.', strategy: 'append' }
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
mockAiProvider.getDataExtractionConfiguration.mockResolvedValue(undefined);
|
|
80
|
-
// Mock Genkit output
|
|
81
|
-
mockGenerate.mockResolvedValue({
|
|
82
|
-
output: {
|
|
83
|
-
documentTitle: 'INV-2024',
|
|
84
|
-
documentSubtitle: null,
|
|
85
|
-
documentSummary: 'Summary',
|
|
86
|
-
documentTags: [],
|
|
87
|
-
documentDate: null
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
await runInInjectionContext(injector, async () => {
|
|
91
|
-
await aiService.extractData(tenantId, document.id);
|
|
92
|
-
const lastCall = mockGenerate.mock.calls[0][0];
|
|
93
|
-
const userPrompt = lastCall.prompt;
|
|
94
|
-
const userPromptText = userPrompt.map((p) => p.text).join('\n');
|
|
95
|
-
expect(userPromptText).toContain('Format the title of the document exactly as follows: INV-{{Date}}');
|
|
96
|
-
expect(userPromptText).toContain('Focus on items.');
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
test('classifyDocumentType should include granular instructions in prompt', async () => {
|
|
100
|
-
const documentService = await injector.resolveAsync(DocumentService);
|
|
101
|
-
const document = await documentService.create(tenantId, {
|
|
102
|
-
originalFileName: 'test.pdf',
|
|
103
|
-
skipWorkflow: true,
|
|
104
|
-
assignment: { collections: [] }
|
|
105
|
-
}, new Uint8Array([1, 2, 3]));
|
|
106
|
-
mockAiProvider.getGlobalConfiguration.mockResolvedValue({
|
|
107
|
-
defaults: {
|
|
108
|
-
classification: { content: 'Prefer Finance types.', strategy: 'append' }
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
mockAiProvider.getClassificationConfiguration.mockResolvedValue(undefined);
|
|
112
|
-
mockGenerate.mockResolvedValue({
|
|
113
|
-
output: {
|
|
114
|
-
documentType: 'Category: Finance | Type: Invoice'
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
await runInInjectionContext(injector, async () => {
|
|
118
|
-
await aiService.classifyDocumentType(tenantId, document.id);
|
|
119
|
-
const lastCall = mockGenerate.mock.calls[1][0];
|
|
120
|
-
const systemPrompt = lastCall.system;
|
|
121
|
-
const systemPromptText = systemPrompt.map((p) => p.text).join('\n');
|
|
122
|
-
expect(systemPromptText).toContain('Prefer Finance types.');
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'vitest';
|
|
2
|
-
import { mergeInstructions } from '../server/services/document-management-ai.service.js';
|
|
3
|
-
describe('AI Instruction Merging', () => {
|
|
4
|
-
test('should return base when no overrides are provided', () => {
|
|
5
|
-
const base = 'Default instruction';
|
|
6
|
-
expect(mergeInstructions(base, [])).toBe(base);
|
|
7
|
-
});
|
|
8
|
-
test('should replace with string override', () => {
|
|
9
|
-
const base = 'Default instruction';
|
|
10
|
-
const overrides = ['Custom instruction'];
|
|
11
|
-
expect(mergeInstructions(base, overrides)).toBe('Custom instruction');
|
|
12
|
-
});
|
|
13
|
-
test('should append with append strategy', () => {
|
|
14
|
-
const base = 'Default instruction';
|
|
15
|
-
const overrides = [{ content: 'Added instruction', strategy: 'append' }];
|
|
16
|
-
expect(mergeInstructions(base, overrides)).toBe('Default instruction\n\nAdded instruction');
|
|
17
|
-
});
|
|
18
|
-
test('should replace with replace strategy', () => {
|
|
19
|
-
const base = 'Default instruction';
|
|
20
|
-
const overrides = [{ content: 'New instruction', strategy: 'replace' }];
|
|
21
|
-
expect(mergeInstructions(base, overrides)).toBe('New instruction');
|
|
22
|
-
});
|
|
23
|
-
test('should handle multiple overrides in order', () => {
|
|
24
|
-
const base = 'Base';
|
|
25
|
-
const overrides = [
|
|
26
|
-
{ content: 'Global', strategy: 'append' },
|
|
27
|
-
{ content: 'Category', strategy: 'append' },
|
|
28
|
-
{ content: 'Type', strategy: 'replace' }
|
|
29
|
-
];
|
|
30
|
-
expect(mergeInstructions(base, overrides)).toBe('Type');
|
|
31
|
-
});
|
|
32
|
-
test('should handle format simple override', () => {
|
|
33
|
-
const base = 'Create a title.';
|
|
34
|
-
const overrides = [{ format: '[ID] - [Name]' }];
|
|
35
|
-
const result = mergeInstructions(base, overrides);
|
|
36
|
-
expect(result).toContain('[ID] - [Name]');
|
|
37
|
-
});
|
|
38
|
-
test('should handle Instructions in content', () => {
|
|
39
|
-
const base = 'Base';
|
|
40
|
-
const overrides = [{ content: { Detail: 'More info' }, strategy: 'append' }];
|
|
41
|
-
const result = mergeInstructions(base, overrides);
|
|
42
|
-
expect(result).toContain('Base');
|
|
43
|
-
expect(result).toContain('# Detail');
|
|
44
|
-
expect(result).toContain('More info');
|
|
45
|
-
});
|
|
46
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { afterAll, beforeAll, describe, expect, test, vi } from 'vitest';
|
|
2
|
-
import { injectModel } from '../../ai/genkit/index.js';
|
|
3
|
-
import { runInInjectionContext } from '../../injector/index.js';
|
|
4
|
-
import { ObjectStorage } from '../../object-storage/index.js';
|
|
5
|
-
import { setupIntegrationTest } from '../../testing/index.js';
|
|
6
|
-
import { DocumentManagementConfiguration } from '../server/module.js';
|
|
7
|
-
import { DocumentManagementAiService } from '../server/services/document-management-ai.service.js';
|
|
8
|
-
import { DocumentCategoryTypeService, DocumentManagementAiProviderService, DocumentManagementAncillaryService } from '../server/services/index.js';
|
|
9
|
-
import { TestDocumentManagementAncillaryService } from './helper.js';
|
|
10
|
-
describe('DocumentManagementAiService Overrides', () => {
|
|
11
|
-
let injector;
|
|
12
|
-
let aiService;
|
|
13
|
-
let flashModel;
|
|
14
|
-
let proModel;
|
|
15
|
-
const tenantId = crypto.randomUUID();
|
|
16
|
-
const mockAiProvider = {
|
|
17
|
-
getGlobalConfiguration: vi.fn(),
|
|
18
|
-
getClassificationConfiguration: vi.fn(),
|
|
19
|
-
getDataExtractionConfiguration: vi.fn(),
|
|
20
|
-
getAssignmentConfiguration: vi.fn(),
|
|
21
|
-
getValidationConfiguration: vi.fn(),
|
|
22
|
-
};
|
|
23
|
-
beforeAll(async () => {
|
|
24
|
-
({ injector } = await setupIntegrationTest({
|
|
25
|
-
modules: { messageBus: true, signals: true, objectStorage: true },
|
|
26
|
-
}));
|
|
27
|
-
runInInjectionContext(injector, () => {
|
|
28
|
-
flashModel = injectModel('gemini-2.5-flash');
|
|
29
|
-
proModel = injectModel('gemini-2.5-pro');
|
|
30
|
-
});
|
|
31
|
-
injector.register(DocumentManagementAiProviderService, { useValue: mockAiProvider });
|
|
32
|
-
injector.register(DocumentManagementAncillaryService, { useToken: TestDocumentManagementAncillaryService });
|
|
33
|
-
injector.register(DocumentManagementConfiguration, { useValue: { fileObjectStorageModule: 'docs', fileUploadObjectStorageModule: 'uploads', filePreviewObjectStorageModule: 'previews' } });
|
|
34
|
-
aiService = await injector.resolveAsync(DocumentManagementAiService);
|
|
35
|
-
});
|
|
36
|
-
afterAll(async () => {
|
|
37
|
-
await injector?.dispose();
|
|
38
|
-
});
|
|
39
|
-
test('resolveAiConfiguration should merge configurations correctly', async () => {
|
|
40
|
-
const categoryTypeService = await injector.resolveAsync(DocumentCategoryTypeService);
|
|
41
|
-
const category = await categoryTypeService.createCategory({ tenantId, label: 'Finance', key: 'finance-cat', parentId: null });
|
|
42
|
-
const type = await categoryTypeService.createType({ tenantId, categoryId: category.id, label: 'Invoice', key: 'invoice-key' });
|
|
43
|
-
mockAiProvider.getGlobalConfiguration.mockResolvedValue({
|
|
44
|
-
defaults: {
|
|
45
|
-
language: 'en',
|
|
46
|
-
model: flashModel,
|
|
47
|
-
prompt: { systemAddition: 'Global System' },
|
|
48
|
-
},
|
|
49
|
-
});
|
|
50
|
-
mockAiProvider.getDataExtractionConfiguration.mockResolvedValue({
|
|
51
|
-
model: proModel,
|
|
52
|
-
prompt: { systemAddition: 'Extraction System', systemOverride: (base) => `OVERRIDDEN: ${base}` },
|
|
53
|
-
});
|
|
54
|
-
await runInInjectionContext(injector, async () => {
|
|
55
|
-
// Accessing private method for testing purposes
|
|
56
|
-
const config = await aiService.resolveAiConfiguration(tenantId, 'data-extraction', { type });
|
|
57
|
-
expect(config.language).toBe('en');
|
|
58
|
-
expect(config.model).toBe(proModel);
|
|
59
|
-
expect(config.prompt.systemAddition).toEqual(['Global System', 'Extraction System']);
|
|
60
|
-
expect(config.prompt.systemOverride('Base')).toBe('OVERRIDDEN: Base');
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import { afterAll, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';
|
|
2
|
-
import { GenkitModuleOptions } from '../../ai/genkit/module.js';
|
|
3
|
-
import { runInInjectionContext } from '../../injector/index.js';
|
|
4
|
-
import { ObjectStorage } from '../../object-storage/index.js';
|
|
5
|
-
import { TaskQueue } from '../../task-queue/index.js';
|
|
6
|
-
import { clearTenantData, setupIntegrationTest } from '../../testing/index.js';
|
|
7
|
-
import { configureDocumentManagement } from '../server/configure.js';
|
|
8
|
-
import { DocumentCategoryTypeService } from '../server/services/document-category-type.service.js';
|
|
9
|
-
import { DocumentCollectionService } from '../server/services/document-collection.service.js';
|
|
10
|
-
import { DocumentManagementAiService } from '../server/services/document-management-ai.service.js';
|
|
11
|
-
import { DocumentManagementService } from '../server/services/document-management.service.js';
|
|
12
|
-
import { DocumentPropertyService } from '../server/services/document-property.service.js';
|
|
13
|
-
import { DocumentRequestService } from '../server/services/document-request.service.js';
|
|
14
|
-
import { DocumentWorkflowService } from '../server/services/document-workflow.service.js';
|
|
15
|
-
import { DocumentService } from '../server/services/document.service.js';
|
|
16
|
-
import { TestDocumentManagementAncillaryService, TestDocumentManagementAuthorizationService } from './helper.js';
|
|
17
|
-
describe('Document Management Core', () => {
|
|
18
|
-
let injector;
|
|
19
|
-
let database;
|
|
20
|
-
let documentService;
|
|
21
|
-
let collectionService;
|
|
22
|
-
let requestService;
|
|
23
|
-
let managementService;
|
|
24
|
-
let categoryTypeService;
|
|
25
|
-
const schema = 'document_management';
|
|
26
|
-
const tenantId = crypto.randomUUID();
|
|
27
|
-
beforeAll(async () => {
|
|
28
|
-
({ injector, database } = await setupIntegrationTest({
|
|
29
|
-
modules: { taskQueue: false, messageBus: true, documentManagement: true }, // Disabled TaskQueue to avoid background noise
|
|
30
|
-
orm: { schema },
|
|
31
|
-
}));
|
|
32
|
-
injector.register(GenkitModuleOptions, { useValue: {} });
|
|
33
|
-
injector.register(DocumentManagementAiService, { useValue: { extractContent: vi.fn(), classifyDocumentType: vi.fn(), extractData: vi.fn(), findSuitableCollectionsForDocument: vi.fn(), findSuitableRequestForDocument: vi.fn() } });
|
|
34
|
-
injector.register(ObjectStorage, {
|
|
35
|
-
useValue: {
|
|
36
|
-
uploadObject: vi.fn(),
|
|
37
|
-
getDownloadUrl: vi.fn(),
|
|
38
|
-
getContent: vi.fn(),
|
|
39
|
-
getContentStream: vi.fn(),
|
|
40
|
-
getObject: vi.fn(),
|
|
41
|
-
exists: vi.fn(),
|
|
42
|
-
},
|
|
43
|
-
});
|
|
44
|
-
// Mock TaskQueue
|
|
45
|
-
injector.register(TaskQueue, {
|
|
46
|
-
useValue: {
|
|
47
|
-
enqueue: vi.fn(),
|
|
48
|
-
enqueueMany: vi.fn(),
|
|
49
|
-
process: vi.fn(),
|
|
50
|
-
},
|
|
51
|
-
});
|
|
52
|
-
configureDocumentManagement({
|
|
53
|
-
ancillaryService: TestDocumentManagementAncillaryService,
|
|
54
|
-
authorizationService: TestDocumentManagementAuthorizationService,
|
|
55
|
-
fileObjectStorageModule: 'documents',
|
|
56
|
-
fileUploadObjectStorageModule: 'document-uploads',
|
|
57
|
-
filePreviewObjectStorageModule: 'document-previews',
|
|
58
|
-
injector,
|
|
59
|
-
});
|
|
60
|
-
documentService = await injector.resolveAsync(DocumentService);
|
|
61
|
-
collectionService = await injector.resolveAsync(DocumentCollectionService);
|
|
62
|
-
requestService = await injector.resolveAsync(DocumentRequestService);
|
|
63
|
-
managementService = await injector.resolveAsync(DocumentManagementService);
|
|
64
|
-
categoryTypeService = await injector.resolveAsync(DocumentCategoryTypeService);
|
|
65
|
-
});
|
|
66
|
-
afterAll(async () => {
|
|
67
|
-
await injector?.dispose();
|
|
68
|
-
});
|
|
69
|
-
beforeEach(async () => {
|
|
70
|
-
await clearTenantData(database, schema, ['request_collection_assignment', 'collection_assignment', 'workflow', 'request', 'document', 'collection', 'type', 'category'], tenantId);
|
|
71
|
-
});
|
|
72
|
-
// --- Collection Management ---
|
|
73
|
-
test('Create and load collection', async () => {
|
|
74
|
-
await runInInjectionContext(injector, async () => {
|
|
75
|
-
const collection = await collectionService.createCollection(tenantId, null);
|
|
76
|
-
expect(collection.id).toBeDefined();
|
|
77
|
-
const loaded = await collectionService.repository.loadByQuery({ tenantId, id: collection.id });
|
|
78
|
-
expect(loaded.id).toBe(collection.id);
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
test('Load collection view resolves metadata', async () => {
|
|
82
|
-
await runInInjectionContext(injector, async () => {
|
|
83
|
-
const collection = await collectionService.createCollection(tenantId, null);
|
|
84
|
-
const data = await managementService.loadData(tenantId, [collection.id]);
|
|
85
|
-
const view = data.collections.find((c) => c.id === collection.id);
|
|
86
|
-
expect(view).toBeDefined();
|
|
87
|
-
// Metadata comes from TestDocumentManagementAncillaryService in helper.ts
|
|
88
|
-
expect(view?.name).toBe(`Collection ${collection.id}`);
|
|
89
|
-
expect(view?.group).toBe('Test');
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
// --- Document Assignments ---
|
|
93
|
-
test('Assign document to collection', async () => {
|
|
94
|
-
await runInInjectionContext(injector, async () => {
|
|
95
|
-
const collection = await collectionService.createCollection(tenantId, null);
|
|
96
|
-
const doc = await documentService.create(tenantId, {
|
|
97
|
-
originalFileName: 'test.pdf',
|
|
98
|
-
assignment: { collections: [] },
|
|
99
|
-
skipAi: true,
|
|
100
|
-
}, new Uint8Array([]));
|
|
101
|
-
await documentService.update(tenantId, doc.id, { collections: { assign: [collection.id] } });
|
|
102
|
-
const assignedCollections = await managementService.getRelevantDocumentCollectionIds(tenantId, doc.id);
|
|
103
|
-
expect(assignedCollections).toContain(collection.id);
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
test('Unassign document from collection', async () => {
|
|
107
|
-
await runInInjectionContext(injector, async () => {
|
|
108
|
-
const collection = await collectionService.createCollection(tenantId, null);
|
|
109
|
-
const doc = await documentService.create(tenantId, {
|
|
110
|
-
originalFileName: 'test.pdf',
|
|
111
|
-
assignment: { collections: [collection.id] },
|
|
112
|
-
skipAi: true,
|
|
113
|
-
}, new Uint8Array([]));
|
|
114
|
-
// Archive assignment to unassign
|
|
115
|
-
await documentService.update(tenantId, doc.id, { collections: { archive: [collection.id] } });
|
|
116
|
-
// getRelevantDocumentCollectionIds includes all assignments (even archived ones maybe?).
|
|
117
|
-
// Let's check the loadData response for active assignments.
|
|
118
|
-
const data = await managementService.loadData(tenantId, [collection.id]);
|
|
119
|
-
const docView = data.documents.find((d) => d.id === doc.id);
|
|
120
|
-
// The assignment should be filtered out or marked archived in the view?
|
|
121
|
-
// loadData: documentCollectionAssignments.filter((collectionDocument) => collectionDocument.documentId == document.id)
|
|
122
|
-
// The query in loadData loads ALL assignments for the collection.
|
|
123
|
-
// But typically "active" documents are what we care about.
|
|
124
|
-
// If archived, it might still show up. Let's check the 'archiveTimestamp' in the assignment view.
|
|
125
|
-
const assignment = docView?.assignment.collections.find((a) => a.collectionId === collection.id);
|
|
126
|
-
expect(assignment?.archiveTimestamp).not.toBeNull();
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
// --- Requests ---
|
|
130
|
-
test('Create and load document request', async () => {
|
|
131
|
-
await runInInjectionContext(injector, async () => {
|
|
132
|
-
// Create a dummy type first
|
|
133
|
-
const category = await categoryTypeService.createCategory({ tenantId, label: 'ReqCat', parentId: null });
|
|
134
|
-
const type = await categoryTypeService.createType({ tenantId, label: 'ReqType', categoryId: category.id });
|
|
135
|
-
const collection = await collectionService.createCollection(tenantId, null);
|
|
136
|
-
const request = await requestService.createRequest(tenantId, type.id, [collection.id], 'New Request');
|
|
137
|
-
expect(request.comment).toBe('New Request');
|
|
138
|
-
// Verify via loadData (indirectly verifies persistence)
|
|
139
|
-
const data = await managementService.loadData(tenantId, [collection.id]);
|
|
140
|
-
const loaded = data.requests.find((r) => r.id === request.id);
|
|
141
|
-
expect(loaded).toBeDefined();
|
|
142
|
-
expect(loaded?.comment).toBe('New Request');
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
test('Request with collection assignment', async () => {
|
|
146
|
-
await runInInjectionContext(injector, async () => {
|
|
147
|
-
const category = await categoryTypeService.createCategory({ tenantId, label: 'Cat2', parentId: null });
|
|
148
|
-
const type = await categoryTypeService.createType({ tenantId, label: 'Type2', categoryId: category.id });
|
|
149
|
-
const collection = await collectionService.createCollection(tenantId, null);
|
|
150
|
-
const request = await requestService.createRequest(tenantId, type.id, [collection.id], 'Assignment Request');
|
|
151
|
-
const data = await managementService.loadData(tenantId, [collection.id]);
|
|
152
|
-
const reqView = data.requests.find((r) => r.id === request.id);
|
|
153
|
-
expect(reqView).toBeDefined();
|
|
154
|
-
expect(reqView?.collectionIds).toContain(collection.id);
|
|
155
|
-
});
|
|
156
|
-
});
|
|
157
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|