Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions app/apps/shell-super-app/tests/integration/auth-runtime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ const installedPageCatalog = (): InstalledModuleCatalog =>
},
]);

test('creates, resolves, persists, revokes, and signs out a Better Auth session', async () => {
void test('creates, resolves, persists, revokes, and signs out a Better Auth session', async () => {
const configuration = await runEffectTestPromise(loadAuthConfig());
const corePool = new Pool({ connectionString: configuration.connectionString });
const coreDatabase = await runEffectTestPromise(
Expand Down Expand Up @@ -370,7 +370,7 @@ test('creates, resolves, persists, revokes, and signs out a Better Auth session'
const invalid = await runEffectTestPromise(
Effect.flip(authentication.signIn(email, 'wrong-password', requestHeaders)),
);
assert.equal(invalid._tag, 'InvalidCredentialsError');
assert.ok(Predicate.isTagged(invalid, 'InvalidCredentialsError'));

const anonymousRuntime = makeShellAuthenticationApiRuntime(
authenticationLayer,
Expand Down Expand Up @@ -1013,7 +1013,7 @@ test('creates, resolves, persists, revokes, and signs out a Better Auth session'
.pipe(Effect.provide(authenticationContextLayer)),
),
);
assert.equal(revoked._tag, 'OntosIdentityForbiddenError');
assert.ok(Predicate.isTagged(revoked, 'OntosIdentityForbiddenError'));
const forbiddenModulesResponse = await unavailableHandler.handler(
new Request(`${configuration.baseUrl}/shell/composition`, {
headers: authenticatedHeaders,
Expand Down Expand Up @@ -1066,7 +1066,7 @@ test('creates, resolves, persists, revokes, and signs out a Better Auth session'
}
});

test('selects, lists, switches, revalidates, and upgrades a multi-tenant session', async () => {
void test('selects, lists, switches, revalidates, and upgrades a multi-tenant session', async () => {
const multiEmail = 'better-auth-multi-tenant@example.test';
const firstTenantId = '31000000-0000-4000-8000-000000000001';
const secondTenantId = '31000000-0000-4000-8000-000000000002';
Expand Down Expand Up @@ -1738,7 +1738,7 @@ test('selects, lists, switches, revalidates, and upgrades a multi-tenant session
.pipe(Effect.provide(multiAuthenticationContextLayer)),
),
);
assert.equal(revokedSession._tag, 'OntosIdentityForbiddenError');
assert.ok(Predicate.isTagged(revokedSession, 'OntosIdentityForbiddenError'));
await runEffectTestPromise(
coreDatabase
.update(principalAuthBindings)
Expand Down Expand Up @@ -1769,7 +1769,7 @@ test('selects, lists, switches, revalidates, and upgrades a multi-tenant session
.pipe(Effect.provide(multiAuthenticationContextLayer)),
),
);
assert.equal(sessionWithRemovedBinding._tag, 'OntosIdentityForbiddenError');
assert.ok(Predicate.isTagged(sessionWithRemovedBinding, 'OntosIdentityForbiddenError'));
} finally {
await Promise.all(handlers.map(async ({ dispose }) => await dispose()));
await cleanup();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ void test('verifies provider keys and completes live support impersonation with
);
await runEffectTestPromise(keys.setEnabled(verified.providerKeyId, false));
const invalidKey = await runEffectTestPromise(Effect.flip(keys.verify(issued.secret)));
assert.equal(invalidKey._tag, 'ApiKeyCredentialInvalidError');
assert.ok(Predicate.isTagged(invalidKey, 'ApiKeyCredentialInvalidError'));

const managedPrincipal = await runEffectTestPromise(
providePrincipalManagementRepository(
Expand Down Expand Up @@ -580,7 +580,7 @@ void test('verifies provider keys and completes live support impersonation with
const incompleteImpersonation = await runEffectTestPromise(
Effect.flip(provideContextAccess(authentication.resolveTenantContext(impersonatedHeaders))),
);
assert.equal(incompleteImpersonation._tag, 'OntosIdentityForbiddenError');
assert.ok(Predicate.isTagged(incompleteImpersonation, 'OntosIdentityForbiddenError'));
await runEffectTestPromise(
authDatabase
.update(session)
Expand All @@ -596,7 +596,7 @@ void test('verifies provider keys and completes live support impersonation with
const mismatchedImpersonationReason = await runEffectTestPromise(
Effect.flip(provideContextAccess(authentication.resolveTenantContext(impersonatedHeaders))),
);
assert.equal(mismatchedImpersonationReason._tag, 'OntosIdentityForbiddenError');
assert.ok(Predicate.isTagged(mismatchedImpersonationReason, 'OntosIdentityForbiddenError'));
await runEffectTestPromise(
authDatabase
.update(session)
Expand Down Expand Up @@ -626,7 +626,7 @@ void test('verifies provider keys and completes live support impersonation with
const revokedImpersonation = await runEffectTestPromise(
Effect.flip(provideContextAccess(authentication.resolveTenantContext(impersonatedHeaders))),
);
assert.equal(revokedImpersonation._tag, 'OntosIdentityForbiddenError');
assert.ok(Predicate.isTagged(revokedImpersonation, 'OntosIdentityForbiddenError'));
const stopped = await runEffectTestPromise(
provideContextAccess(
providePrincipalManagementRepository(
Expand Down
8 changes: 4 additions & 4 deletions app/apps/shell-super-app/tests/unit/auth-config.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { runEffectTestPromise } from '@app/core-runtime/testing/effect-runtime';
import { expect, test } from '@rstest/core';
import { Effect } from 'effect';
import { Effect, Predicate } from 'effect';
import { parseAuthConfig } from '../../api/auth/config.ts';
import { parseGatewayIssuerConfig } from '../../api/auth/gateway-issuer-config.ts';

Expand Down Expand Up @@ -39,14 +39,14 @@ test('requires a strong secret and PostgreSQL URL in the typed error channel', a
),
),
]).then(([secretError, databaseError]) => {
expect(secretError._tag).toBe('AuthConfigError');
expect(databaseError._tag).toBe('AuthConfigError');
expect(Predicate.isTagged(secretError, 'AuthConfigError')).toBe(true);
expect(Predicate.isTagged(databaseError, 'AuthConfigError')).toBe(true);
}));

test('keeps gateway signing configuration independent from Better Auth configuration', async () => {
const authentication = await runEffectTestPromise(parseAuthConfig(validEnvironment));
const gatewayError = await runEffectTestPromise(Effect.flip(parseGatewayIssuerConfig({})));

expect(authentication.baseUrl).toBe('http://localhost:3020');
expect(gatewayError._tag).toBe('GatewayIssuerConfigError');
expect(Predicate.isTagged(gatewayError, 'GatewayIssuerConfigError')).toBe(true);
});
10 changes: 5 additions & 5 deletions app/apps/shell-super-app/tests/unit/auth-contract.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { runEffectTestPromise } from '@app/core-runtime/testing/effect-runtime';
import { expect, test } from '@rstest/core';
import { DateTime, Effect, Schema } from 'effect';
import { DateTime, Effect, Schema, Predicate } from 'effect';
import {
CurrentSessionSchema,
AvailableLegalEntitiesResponseSchema,
Expand Down Expand Up @@ -233,7 +233,7 @@ test('validates tenant UUIDs and strips all non-contract fields', async () => {
const invalidPayload = await runEffectTestPromise(
Effect.flip(Schema.decodeUnknownEffect(SwitchTenantPayloadSchema)({ tenantId: 'not-a-uuid' })),
);
expect(invalidPayload._tag).toBe('SchemaError');
expect(Predicate.isTagged(invalidPayload, 'SchemaError')).toBe(true);
});

test('rejects malformed credentials through Effect Schema', async () => {
Expand All @@ -245,7 +245,7 @@ test('rejects malformed credentials through Effect Schema', async () => {
}),
),
);
expect(error._tag).toBe('SchemaError');
expect(Predicate.isTagged(error, 'SchemaError')).toBe(true);
});

test('requires lifecycle reasons and strips provider-private API key identifiers', async () => {
Expand All @@ -270,8 +270,8 @@ test('requires lifecycle reasons and strips provider-private API key identifiers
}),
),
);
expect(missingPrincipalReason._tag).toBe('SchemaError');
expect(missingRevocationReason._tag).toBe('SchemaError');
expect(Predicate.isTagged(missingPrincipalReason, 'SchemaError')).toBe(true);
expect(Predicate.isTagged(missingRevocationReason, 'SchemaError')).toBe(true);

const lifecycle = await runEffectTestPromise(
Schema.decodeUnknownEffect(ApiKeyLifecycleResponseSchema)({
Expand Down
10 changes: 5 additions & 5 deletions app/apps/shell-super-app/tests/unit/identity-lifecycle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
IdentityTargetInvalidError,
PrincipalBindingMissingError,
} from '@app/core-runtime';
import { Effect, Redacted } from 'effect';
import { Effect, Redacted, Predicate } from 'effect';
import {
ApiKeyProviderUnavailableError,
ApiKeyStateInconsistentError,
Expand Down Expand Up @@ -89,7 +89,7 @@ test('compensates a failed Core bind and never exposes the provider key identifi
),
);
expect(failure).toBe(bindFailure);
expect(failure._tag).toBe('IdentityTargetInvalidError');
expect(Predicate.isTagged(failure, 'IdentityTargetInvalidError')).toBe(true);
expect(disabled).toEqual(['private-provider-key-id']);
});

Expand Down Expand Up @@ -117,7 +117,7 @@ test('preserves resolver lifecycle failures instead of rewriting them as an outa
);

expect(failure).toBe(resolverFailure);
expect(failure._tag).toBe('PrincipalBindingMissingError');
expect(Predicate.isTagged(failure, 'PrincipalBindingMissingError')).toBe(true);
});

test('preserves a typed Core status-transition failure before touching provider state', async () => {
Expand Down Expand Up @@ -151,7 +151,7 @@ test('preserves a typed Core status-transition failure before touching provider
);

expect(failure).toBe(actionFailure);
expect(failure._tag).toBe('IdentityTargetInvalidError');
expect(Predicate.isTagged(failure, 'IdentityTargetInvalidError')).toBe(true);
expect(providerCalls).toBe(0);
});

Expand Down Expand Up @@ -456,7 +456,7 @@ test('cleans one bounded pending batch and requires a retry before issuing anoth
),
);

expect(failure._tag).toBe('IdentityLifecycleOperationError');
expect(Predicate.isTagged(failure, 'IdentityLifecycleOperationError')).toBe(true);
expect(disabled).toEqual(['bounded-orphan']);
expect(issueCalls).toBe(0);
});
Expand Down
6 changes: 2 additions & 4 deletions app/apps/shell-super-app/tests/unit/layout.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -305,10 +305,8 @@ test('renders the account Menu last and dispatches only the logout command by ke
const header = document.querySelector('header[aria-label="Dashboard header"]');
const trigger = screen.getByRole('button', { name: 'Ada Lovelace' });
expect(header?.lastElementChild?.contains(trigger)).toBe(true);
const accountMenu = header?.lastElementChild;
expect(accountMenu instanceof HTMLElement ? accountMenu.dataset['position'] : undefined).toBe(
'end',
);
const accountMenu = header?.querySelector<HTMLElement>(':scope > :last-child');
expect(accountMenu?.dataset['position']).toBe('end');

trigger.focus();
await user.keyboard('{Enter}');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import assert from 'node:assert/strict';
import { test } from '@rstest/core';
import { ContextAccess, LegalEntityContext } from '@app/core-runtime';
import type { ContextAccessService, LegalEntityContextService } from '@app/core-runtime';
import { Effect, Layer } from 'effect';
import { Effect, Layer, Predicate } from 'effect';
import {
resolveAuthorizedLegalEntities,
validateAuthorizedLegalEntity,
Expand Down Expand Up @@ -110,7 +110,7 @@ test('fails closed for authorization uncertainty and validates a switch independ
),
),
);
assert.equal(unavailable._tag, 'LegalEntitySelectionUnavailableError');
assert.ok(Predicate.isTagged(unavailable, 'LegalEntitySelectionUnavailableError'));
assert.deepEqual(
await runEffectTestPromise(
provideSelectionServices(
Expand Down
2 changes: 1 addition & 1 deletion app/packages/core-runtime/src/actions/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ const normalizeForHash = <Value>(value: Value, seen: WeakSet<object>): Canonical
if (Predicate.isBigInt(value)) {
return ['bigint', value.toString(10)];
}
if (value instanceof Date) {
if (Predicate.isDate(value)) {
return ['date', value.toISOString()];
}
if (Array.isArray(value)) {
Expand Down
17 changes: 5 additions & 12 deletions app/packages/core-runtime/src/outbox/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ import {
import {
OutboxHandlerExecutionError,
OutboxPayloadDecodeError,
OutboxPersistenceError,
OutboxWorkerDescriptorError,
} from './errors.ts';
import type { OutboxClaimLostError } from './errors.ts';
import type { OutboxClaimLostError, OutboxPersistenceError } from './errors.ts';
import { OutboxRepository } from './repository.ts';
import type { OutboxClaim, OutboxRepositoryService as OutboxRepositoryPort } from './repository.ts';

Expand Down Expand Up @@ -101,7 +100,7 @@ const validateCycleInput = Effect.fn('OutboxRuntime.validateCycleInput')(
}
const registrations = yield* Effect.try({
catch: (error) =>
error instanceof OutboxWorkerDescriptorError
Schema.is(OutboxWorkerDescriptorError)(error)
? error
: descriptorFailure('The Outbox Worker descriptor set is invalid'),
try: () => validateOutboxWorkerRegistrations(input.registrations),
Expand Down Expand Up @@ -302,9 +301,7 @@ const processNextOutboxDelivery = Effect.fn('makeOutboxRuntime.processNextDelive
reason: 'The Outbox Message payload does not match its published schema',
});
const status = yield* repository.fail(claim, decodeError.reason, execution.now).pipe(
Effect.tapError((error) =>
error instanceof OutboxPersistenceError ? logUnexpectedPersistence(claim) : Effect.void,
),
Effect.tapErrorTag('OutboxPersistenceError', () => logUnexpectedPersistence(claim)),
(effect) => withOutcomeSpan(effect, claim, 'payload_decode_failure'),
);
return {
Expand Down Expand Up @@ -342,9 +339,7 @@ const processNextOutboxDelivery = Effect.fn('makeOutboxRuntime.processNextDelive
: 'The Outbox Worker handler returned a declared failure',
});
const status = yield* repository.fail(claim, executionError.reason, execution.now).pipe(
Effect.tapError((error) =>
error instanceof OutboxPersistenceError ? logUnexpectedPersistence(claim) : Effect.void,
),
Effect.tapErrorTag('OutboxPersistenceError', () => logUnexpectedPersistence(claim)),
(effect) => withOutcomeSpan(effect, claim, 'handler_failure'),
);
return {
Expand All @@ -356,9 +351,7 @@ const processNextOutboxDelivery = Effect.fn('makeOutboxRuntime.processNextDelive
}

yield* repository.complete(claim, execution.now).pipe(
Effect.tapError((error) =>
error instanceof OutboxPersistenceError ? logUnexpectedPersistence(claim) : Effect.void,
),
Effect.tapErrorTag('OutboxPersistenceError', () => logUnexpectedPersistence(claim)),
(effect) => withOutcomeSpan(effect, claim, 'success'),
);
return { ...claimedState, succeeded: claimedState.succeeded + 1 };
Expand Down
1 change: 0 additions & 1 deletion app/packages/core-runtime/src/testing/live-operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ export type LiveOperationFixtureConfiguration =
class LiveOperationFixtureError extends Schema.TaggedError<LiveOperationFixtureError>()(
'LiveOperationFixtureError',
{
commitIndeterminate: Schema.optional(Schema.Literal(true)),
reason: Schema.String,
},
) {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { runEffectTestPromise } from '@app/core-runtime/testing/effect-runtime';
import { v1 } from '@authzed/authzed-node';
import { and, eq } from 'drizzle-orm';
import { Effect, Exit, Schema, flow } from 'effect';
import { Effect, Exit, Schema, flow, Predicate } from 'effect';
import assert from 'node:assert/strict';
import { randomUUID } from 'node:crypto';
import test, { after, before } from 'node:test';
Expand Down Expand Up @@ -578,7 +578,7 @@ effectTest(
.where(eq(outboxMessages.tenantId, tenantId)),
]);

assert.equal(failure._tag, 'ActionPermissionDenied');
assert.ok(Predicate.isTagged(failure, 'ActionPermissionDenied'));
assert.equal(failure.reason, 'The principal is not permitted to execute this Action');
assert.equal(executions.value, 0);
assert.equal(invocation.status, 'rejected');
Expand Down Expand Up @@ -637,7 +637,7 @@ effectTest(
),
);

assert.equal(failure._tag, 'ActionPermissionDenied', kind);
assert.ok(Predicate.isTagged(failure, 'ActionPermissionDenied'), kind);
assert.equal(executions.value, 0, kind);
}),
{ concurrency: 1, discard: true },
Expand Down Expand Up @@ -678,10 +678,10 @@ effectTest(
.from(auditEvents)
.where(eq(auditEvents.actionInvocationId, invocation.actionInvocationId));

assert.deepEqual(
results.map((result) => result._tag),
['ActionPermissionDenied', 'ActionPermissionDenied'],
);
assert.equal(results.length, 2);
for (const result of results) {
assert.ok(Predicate.isTagged(result, 'ActionPermissionDenied'));
}
assert.equal(executions.value, 0);
assert.equal(invocation.status, 'rejected');
assert.equal(audits.length, 1);
Expand Down Expand Up @@ -773,7 +773,7 @@ effectTest(
.from(auditEvents)
.where(eq(auditEvents.actionInvocationId, invocation.actionInvocationId));

assert.equal(failure._tag, 'ActionTransactionError', stage);
assert.ok(Predicate.isTagged(failure, 'ActionTransactionError'), stage);
assert.equal(executions.value, 0, stage);
assert.equal(invocation.status, 'received', stage);
assert.equal(invocation.completedAt, null, stage);
Expand Down Expand Up @@ -823,7 +823,7 @@ effectTest(
),
);

assert.equal(failure._tag, 'ActionPermissionCheckError');
assert.ok(Predicate.isTagged(failure, 'ActionPermissionCheckError'));
assert.equal(failure.reason.includes('invalid-integration-key'), false);
assert.equal(executions.value, 0);
assert.equal(invocation.status, 'received');
Expand Down
Loading
Loading