import type { RelayClientEnvironmentRecord, RelayEnvironmentLinkProofPayload, RelayEnvironmentLinkRequest, RelayManagedEndpoint,} from "@t3tools/contracts/relay";import * as Context from "effect/Context";import * as DateTime from "effect/DateTime";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer";import * as Schema from "effect/Schema";import { and, eq, isNull, or } from "drizzle-orm"; import * as RelayDb from "../db.ts";import { relayEnvironmentLinks } from "../persistence/schema.ts"; export interface RelayLinkedEnvironmentRecord extends RelayClientEnvironmentRecord { readonly environmentPublicKey: string;} export interface AgentAwarenessDeliveryUserRecord { readonly userId: string; readonly notificationsEnabled: boolean; readonly liveActivitiesEnabled: boolean;} export class EnvironmentLinkUpsertPersistenceError extends Schema.TaggedErrorClass<EnvironmentLinkUpsertPersistenceError>()( "EnvironmentLinkUpsertPersistenceError", { userId: Schema.String, environmentId: Schema.String, deviceId: Schema.optionalKey(Schema.String), cause: Schema.Defect(), },) { override get message(): string { return `Failed to persist environment link for user '${this.userId}', environment '${this.environmentId}'`; }} export class EnvironmentLinkUserListPersistenceError extends Schema.TaggedErrorClass<EnvironmentLinkUserListPersistenceError>()( "EnvironmentLinkUserListPersistenceError", { operation: Schema.Literals(["list-users", "list-delivery-users"]), environmentId: Schema.String, cause: Schema.Defect(), },) { override get message(): string { return `Environment link user query '${this.operation}' failed for environment '${this.environmentId}'`; }} export class EnvironmentPublicKeyListPersistenceError extends Schema.TaggedErrorClass<EnvironmentPublicKeyListPersistenceError>()( "EnvironmentPublicKeyListPersistenceError", { environmentId: Schema.String, cause: Schema.Defect(), },) { override get message(): string { return `Failed to list public keys for environment '${this.environmentId}'`; }} export class EnvironmentLinkListPersistenceError extends Schema.TaggedErrorClass<EnvironmentLinkListPersistenceError>()( "EnvironmentLinkListPersistenceError", { userId: Schema.String, cause: Schema.Defect(), },) { override get message(): string { return `Failed to list environment links for user '${this.userId}'`; }} export class EnvironmentLinkLookupPersistenceError extends Schema.TaggedErrorClass<EnvironmentLinkLookupPersistenceError>()( "EnvironmentLinkLookupPersistenceError", { userId: Schema.String, environmentId: Schema.String, cause: Schema.Defect(), },) { override get message(): string { return `Failed to look up environment link for user '${this.userId}', environment '${this.environmentId}'`; }} export class EnvironmentLinkRevokePersistenceError extends Schema.TaggedErrorClass<EnvironmentLinkRevokePersistenceError>()( "EnvironmentLinkRevokePersistenceError", { userId: Schema.String, environmentId: Schema.String, cause: Schema.Defect(), },) { override get message(): string { return `Failed to revoke environment link for user '${this.userId}', environment '${this.environmentId}'`; }} export class EnvironmentLinks extends Context.Service< EnvironmentLinks, { readonly upsert: (input: { readonly userId: string; readonly request: RelayEnvironmentLinkRequest; readonly proof: RelayEnvironmentLinkProofPayload; readonly endpoint: RelayManagedEndpoint; }) => Effect.Effect<void, EnvironmentLinkUpsertPersistenceError>; readonly listUsersForEnvironment: (input: { readonly environmentId: string; }) => Effect.Effect<ReadonlyArray<string>, EnvironmentLinkUserListPersistenceError>; readonly listDeliveryUsersForEnvironment: (input: { readonly environmentId: string; readonly environmentPublicKey: string; }) => Effect.Effect< ReadonlyArray<AgentAwarenessDeliveryUserRecord>, EnvironmentLinkUserListPersistenceError >; readonly listPublicKeysForEnvironment: (input: { readonly environmentId: string; }) => Effect.Effect<ReadonlyArray<string>, EnvironmentPublicKeyListPersistenceError>; readonly listForUser: (input: { readonly userId: string; }) => Effect.Effect< ReadonlyArray<RelayClientEnvironmentRecord>, EnvironmentLinkListPersistenceError >; readonly getForUser: (input: { readonly userId: string; readonly environmentId: string; }) => Effect.Effect<RelayLinkedEnvironmentRecord | null, EnvironmentLinkLookupPersistenceError>; readonly revokeForUser: (input: { readonly userId: string; readonly environmentId: string; }) => Effect.Effect<boolean, EnvironmentLinkRevokePersistenceError>; }>()("t3code-relay/environments/EnvironmentLinks") {} function agentAwarenessDeliveryUserCondition(environmentId: string) { return and( eq(relayEnvironmentLinks.environmentId, environmentId), isNull(relayEnvironmentLinks.revokedAt), or( eq(relayEnvironmentLinks.notificationsEnabled, true), eq(relayEnvironmentLinks.liveActivitiesEnabled, true), ), );} function agentAwarenessDeliveryUserKeyCondition(input: { readonly environmentId: string; readonly environmentPublicKey: string;}) { return and( agentAwarenessDeliveryUserCondition(input.environmentId), eq(relayEnvironmentLinks.environmentPublicKey, input.environmentPublicKey), );} const make = Effect.gen(function* () { const db = yield* RelayDb.RelayDb; return EnvironmentLinks.of({ upsert: Effect.fn("relay.environment_links.upsert")(function* (input) { yield* Effect.annotateCurrentSpan({ "relay.environment_id": input.proof.environmentId, }); const now = DateTime.formatIso(yield* DateTime.now); const { request, proof } = input; const environmentId = proof.environmentId; const { endpoint } = input; yield* db .insert(relayEnvironmentLinks) .values({ userId: input.userId, environmentId, environmentLabel: proof.descriptor.label, environmentPublicKey: proof.environmentPublicKey, endpointHttpBaseUrl: endpoint.httpBaseUrl, endpointWsBaseUrl: endpoint.wsBaseUrl, endpointProviderKind: endpoint.providerKind, notificationsEnabled: request.notificationsEnabled, liveActivitiesEnabled: request.liveActivitiesEnabled, managedTunnelsEnabled: request.managedTunnelsEnabled, createdByDeviceId: request.deviceId ?? null, revokedAt: null, createdAt: now, updatedAt: now, }) .onConflictDoUpdate({ target: [relayEnvironmentLinks.userId, relayEnvironmentLinks.environmentId], set: { environmentPublicKey: proof.environmentPublicKey, environmentLabel: proof.descriptor.label, endpointHttpBaseUrl: endpoint.httpBaseUrl, endpointWsBaseUrl: endpoint.wsBaseUrl, endpointProviderKind: endpoint.providerKind, notificationsEnabled: request.notificationsEnabled, liveActivitiesEnabled: request.liveActivitiesEnabled, managedTunnelsEnabled: request.managedTunnelsEnabled, createdByDeviceId: request.deviceId ?? null, revokedAt: null, updatedAt: now, }, }) .pipe( Effect.mapError( (cause) => new EnvironmentLinkUpsertPersistenceError({ userId: input.userId, environmentId, ...(request.deviceId === undefined ? {} : { deviceId: request.deviceId }), cause, }), ), ); }), listUsersForEnvironment: Effect.fn("relay.environment_links.list_users_for_environment")( function* (input) { yield* Effect.annotateCurrentSpan({ "relay.environment_id": input.environmentId }); return yield* db .select({ userId: relayEnvironmentLinks.userId }) .from(relayEnvironmentLinks) .where(agentAwarenessDeliveryUserCondition(input.environmentId)) .pipe( Effect.map((rows) => rows.map((row) => row.userId)), Effect.mapError( (cause) => new EnvironmentLinkUserListPersistenceError({ operation: "list-users", environmentId: input.environmentId, cause, }), ), ); }, ), listDeliveryUsersForEnvironment: Effect.fn( "relay.environment_links.list_delivery_users_for_environment", )(function* (input) { yield* Effect.annotateCurrentSpan({ "relay.environment_id": input.environmentId }); return yield* db .select({ userId: relayEnvironmentLinks.userId, notificationsEnabled: relayEnvironmentLinks.notificationsEnabled, liveActivitiesEnabled: relayEnvironmentLinks.liveActivitiesEnabled, }) .from(relayEnvironmentLinks) .where(agentAwarenessDeliveryUserKeyCondition(input)) .pipe( Effect.map((rows) => rows.map((row) => ({ userId: row.userId, notificationsEnabled: row.notificationsEnabled, liveActivitiesEnabled: row.liveActivitiesEnabled, })), ), Effect.mapError( (cause) => new EnvironmentLinkUserListPersistenceError({ operation: "list-delivery-users", environmentId: input.environmentId, cause, }), ), ); }), listPublicKeysForEnvironment: Effect.fn( "relay.environment_links.list_public_keys_for_environment", )(function* (input) { yield* Effect.annotateCurrentSpan({ "relay.environment_id": input.environmentId }); return yield* db .select({ environmentPublicKey: relayEnvironmentLinks.environmentPublicKey }) .from(relayEnvironmentLinks) .where( and( eq(relayEnvironmentLinks.environmentId, input.environmentId), isNull(relayEnvironmentLinks.revokedAt), ), ) .pipe( Effect.map((rows) => [ ...new Set(rows.map((row) => row.environmentPublicKey).filter((key) => key.length > 0)), ]), Effect.mapError( (cause) => new EnvironmentPublicKeyListPersistenceError({ environmentId: input.environmentId, cause, }), ), ); }), listForUser: Effect.fn("relay.environment_links.list_for_user")(function* (input) { return yield* db .select({ environmentId: relayEnvironmentLinks.environmentId, environmentLabel: relayEnvironmentLinks.environmentLabel, endpointHttpBaseUrl: relayEnvironmentLinks.endpointHttpBaseUrl, endpointWsBaseUrl: relayEnvironmentLinks.endpointWsBaseUrl, endpointProviderKind: relayEnvironmentLinks.endpointProviderKind, createdAt: relayEnvironmentLinks.createdAt, }) .from(relayEnvironmentLinks) .where( and( eq(relayEnvironmentLinks.userId, input.userId), isNull(relayEnvironmentLinks.revokedAt), ), ) .pipe( Effect.map((rows) => rows.map((row) => ({ environmentId: row.environmentId as RelayClientEnvironmentRecord["environmentId"], label: row.environmentLabel.trim().length > 0 ? row.environmentLabel : row.environmentId, endpoint: { httpBaseUrl: row.endpointHttpBaseUrl, wsBaseUrl: row.endpointWsBaseUrl, providerKind: row.endpointProviderKind as RelayClientEnvironmentRecord["endpoint"]["providerKind"], }, linkedAt: row.createdAt, })), ), Effect.mapError( (cause) => new EnvironmentLinkListPersistenceError({ userId: input.userId, cause, }), ), ); }), getForUser: Effect.fn("relay.environment_links.get_for_user")(function* (input) { yield* Effect.annotateCurrentSpan({ "relay.environment_id": input.environmentId, }); return yield* db .select({ environmentId: relayEnvironmentLinks.environmentId, environmentLabel: relayEnvironmentLinks.environmentLabel, environmentPublicKey: relayEnvironmentLinks.environmentPublicKey, endpointHttpBaseUrl: relayEnvironmentLinks.endpointHttpBaseUrl, endpointWsBaseUrl: relayEnvironmentLinks.endpointWsBaseUrl, endpointProviderKind: relayEnvironmentLinks.endpointProviderKind, createdAt: relayEnvironmentLinks.createdAt, }) .from(relayEnvironmentLinks) .where( and( eq(relayEnvironmentLinks.userId, input.userId), eq(relayEnvironmentLinks.environmentId, input.environmentId), isNull(relayEnvironmentLinks.revokedAt), ), ) .limit(1) .pipe( Effect.map((rows) => { const row = rows[0]; return row ? { environmentId: row.environmentId as RelayClientEnvironmentRecord["environmentId"], label: row.environmentLabel.trim().length > 0 ? row.environmentLabel : row.environmentId, endpoint: { httpBaseUrl: row.endpointHttpBaseUrl, wsBaseUrl: row.endpointWsBaseUrl, providerKind: row.endpointProviderKind as RelayClientEnvironmentRecord["endpoint"]["providerKind"], }, environmentPublicKey: row.environmentPublicKey, linkedAt: row.createdAt, } : null; }), Effect.mapError( (cause) => new EnvironmentLinkLookupPersistenceError({ userId: input.userId, environmentId: input.environmentId, cause, }), ), ); }), revokeForUser: Effect.fn("relay.environment_links.revoke_for_user")(function* (input) { yield* Effect.annotateCurrentSpan({ "relay.environment_id": input.environmentId, }); const revokedAt = DateTime.formatIso(yield* DateTime.now); const rows = yield* db .update(relayEnvironmentLinks) .set({ revokedAt, updatedAt: revokedAt, }) .where( and( eq(relayEnvironmentLinks.userId, input.userId), eq(relayEnvironmentLinks.environmentId, input.environmentId), isNull(relayEnvironmentLinks.revokedAt), ), ) .returning({ environmentId: relayEnvironmentLinks.environmentId }) .pipe( Effect.mapError( (cause) => new EnvironmentLinkRevokePersistenceError({ userId: input.userId, environmentId: input.environmentId, cause, }), ), ); return rows.length > 0; }), });}); export const layer = Layer.effect(EnvironmentLinks, make);
import type {
RelayClientEnvironmentRecord,
RelayEnvironmentLinkProofPayload,
RelayEnvironmentLinkRequest,
RelayManagedEndpoint,
} from "@t3tools/contracts/relay";
import * as Context from "effect/Context";
import * as DateTime from "effect/DateTime";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";
import * as Schema from "effect/Schema";
import { and, eq, isNull, or } from "drizzle-orm";
import * as RelayDb from "../db.ts";
import { relayEnvironmentLinks } from "../persistence/schema.ts";
export interface RelayLinkedEnvironmentRecord extends RelayClientEnvironmentRecord {
readonly environmentPublicKey: string;
}
export interface AgentAwarenessDeliveryUserRecord {
readonly userId: string;
readonly notificationsEnabled: boolean;
readonly liveActivitiesEnabled: boolean;
}
export class EnvironmentLinkUpsertPersistenceError extends Schema.TaggedErrorClass<EnvironmentLinkUpsertPersistenceError>()(
"EnvironmentLinkUpsertPersistenceError",
{
userId: Schema.String,
environmentId: Schema.String,
deviceId: Schema.optionalKey(Schema.String),
cause: Schema.Defect(),
},
) {
override get message(): string {
return `Failed to persist environment link for user '${this.userId}', environment '${this.environmentId}'`;
}
}
export class EnvironmentLinkUserListPersistenceError extends Schema.TaggedErrorClass<EnvironmentLinkUserListPersistenceError>()(
"EnvironmentLinkUserListPersistenceError",
{
operation: Schema.Literals(["list-users", "list-delivery-users"]),
environmentId: Schema.String,
cause: Schema.Defect(),
},
) {
override get message(): string {
return `Environment link user query '${this.operation}' failed for environment '${this.environmentId}'`;
}
}
export class EnvironmentPublicKeyListPersistenceError extends Schema.TaggedErrorClass<EnvironmentPublicKeyListPersistenceError>()(
"EnvironmentPublicKeyListPersistenceError",
{
environmentId: Schema.String,
cause: Schema.Defect(),
},
) {
override get message(): string {
return `Failed to list public keys for environment '${this.environmentId}'`;
}
}
export class EnvironmentLinkListPersistenceError extends Schema.TaggedErrorClass<EnvironmentLinkListPersistenceError>()(
"EnvironmentLinkListPersistenceError",
{
userId: Schema.String,
cause: Schema.Defect(),
},
) {
override get message(): string {
return `Failed to list environment links for user '${this.userId}'`;
}
}
export class EnvironmentLinkLookupPersistenceError extends Schema.TaggedErrorClass<EnvironmentLinkLookupPersistenceError>()(
"EnvironmentLinkLookupPersistenceError",
{
userId: Schema.String,
environmentId: Schema.String,
cause: Schema.Defect(),
},
) {
override get message(): string {
return `Failed to look up environment link for user '${this.userId}', environment '${this.environmentId}'`;
}
}
export class EnvironmentLinkRevokePersistenceError extends Schema.TaggedErrorClass<EnvironmentLinkRevokePersistenceError>()(
"EnvironmentLinkRevokePersistenceError",
{
userId: Schema.String,
environmentId: Schema.String,
cause: Schema.Defect(),
},
) {
override get message(): string {
return `Failed to revoke environment link for user '${this.userId}', environment '${this.environmentId}'`;
}
}
export class EnvironmentLinks extends Context.Service<
EnvironmentLinks,
{
readonly upsert: (input: {
readonly userId: string;
readonly request: RelayEnvironmentLinkRequest;
readonly proof: RelayEnvironmentLinkProofPayload;
readonly endpoint: RelayManagedEndpoint;
}) => Effect.Effect<void, EnvironmentLinkUpsertPersistenceError>;
readonly listUsersForEnvironment: (input: {
readonly environmentId: string;
}) => Effect.Effect<ReadonlyArray<string>, EnvironmentLinkUserListPersistenceError>;
readonly listDeliveryUsersForEnvironment: (input: {
readonly environmentId: string;
readonly environmentPublicKey: string;
}) => Effect.Effect<
ReadonlyArray<AgentAwarenessDeliveryUserRecord>,
EnvironmentLinkUserListPersistenceError
>;
readonly listPublicKeysForEnvironment: (input: {
readonly environmentId: string;
}) => Effect.Effect<ReadonlyArray<string>, EnvironmentPublicKeyListPersistenceError>;
readonly listForUser: (input: {
readonly userId: string;
}) => Effect.Effect<
ReadonlyArray<RelayClientEnvironmentRecord>,
EnvironmentLinkListPersistenceError
>;
readonly getForUser: (input: {
readonly userId: string;
readonly environmentId: string;
}) => Effect.Effect<RelayLinkedEnvironmentRecord | null, EnvironmentLinkLookupPersistenceError>;
readonly revokeForUser: (input: {
readonly userId: string;
readonly environmentId: string;
}) => Effect.Effect<boolean, EnvironmentLinkRevokePersistenceError>;
}
>()("t3code-relay/environments/EnvironmentLinks") {}
function agentAwarenessDeliveryUserCondition(environmentId: string) {
return and(
eq(relayEnvironmentLinks.environmentId, environmentId),
isNull(relayEnvironmentLinks.revokedAt),
or(
eq(relayEnvironmentLinks.notificationsEnabled, true),
eq(relayEnvironmentLinks.liveActivitiesEnabled, true),
),
);
}
function agentAwarenessDeliveryUserKeyCondition(input: {
readonly environmentId: string;
readonly environmentPublicKey: string;
}) {
return and(
agentAwarenessDeliveryUserCondition(input.environmentId),
eq(relayEnvironmentLinks.environmentPublicKey, input.environmentPublicKey),
);
}
const make = Effect.gen(function* () {
const db = yield* RelayDb.RelayDb;
return EnvironmentLinks.of({
upsert: Effect.fn("relay.environment_links.upsert")(function* (input) {
yield* Effect.annotateCurrentSpan({
"relay.environment_id": input.proof.environmentId,
});
const now = DateTime.formatIso(yield* DateTime.now);
const { request, proof } = input;
const environmentId = proof.environmentId;
const { endpoint } = input;
yield* db
.insert(relayEnvironmentLinks)
.values({
userId: input.userId,
environmentId,
environmentLabel: proof.descriptor.label,
environmentPublicKey: proof.environmentPublicKey,
endpointHttpBaseUrl: endpoint.httpBaseUrl,
endpointWsBaseUrl: endpoint.wsBaseUrl,
endpointProviderKind: endpoint.providerKind,
notificationsEnabled: request.notificationsEnabled,
liveActivitiesEnabled: request.liveActivitiesEnabled,
managedTunnelsEnabled: request.managedTunnelsEnabled,
createdByDeviceId: request.deviceId ?? null,
revokedAt: null,
createdAt: now,
updatedAt: now,
})
.onConflictDoUpdate({
target: [relayEnvironmentLinks.userId, relayEnvironmentLinks.environmentId],
set: {
environmentPublicKey: proof.environmentPublicKey,
environmentLabel: proof.descriptor.label,
endpointHttpBaseUrl: endpoint.httpBaseUrl,
endpointWsBaseUrl: endpoint.wsBaseUrl,
endpointProviderKind: endpoint.providerKind,
notificationsEnabled: request.notificationsEnabled,
liveActivitiesEnabled: request.liveActivitiesEnabled,
managedTunnelsEnabled: request.managedTunnelsEnabled,
createdByDeviceId: request.deviceId ?? null,
revokedAt: null,
updatedAt: now,
},
})
.pipe(
Effect.mapError(
(cause) =>
new EnvironmentLinkUpsertPersistenceError({
userId: input.userId,
environmentId,
...(request.deviceId === undefined ? {} : { deviceId: request.deviceId }),
cause,
}),
),
);
}),
listUsersForEnvironment: Effect.fn("relay.environment_links.list_users_for_environment")(
function* (input) {
yield* Effect.annotateCurrentSpan({ "relay.environment_id": input.environmentId });
return yield* db
.select({ userId: relayEnvironmentLinks.userId })
.from(relayEnvironmentLinks)
.where(agentAwarenessDeliveryUserCondition(input.environmentId))
.pipe(
Effect.map((rows) => rows.map((row) => row.userId)),
Effect.mapError(
(cause) =>
new EnvironmentLinkUserListPersistenceError({
operation: "list-users",
environmentId: input.environmentId,
cause,
}),
),
);
},
),
listDeliveryUsersForEnvironment: Effect.fn(
"relay.environment_links.list_delivery_users_for_environment",
)(function* (input) {
yield* Effect.annotateCurrentSpan({ "relay.environment_id": input.environmentId });
return yield* db
.select({
userId: relayEnvironmentLinks.userId,
notificationsEnabled: relayEnvironmentLinks.notificationsEnabled,
liveActivitiesEnabled: relayEnvironmentLinks.liveActivitiesEnabled,
})
.from(relayEnvironmentLinks)
.where(agentAwarenessDeliveryUserKeyCondition(input))
.pipe(
Effect.map((rows) =>
rows.map((row) => ({
userId: row.userId,
notificationsEnabled: row.notificationsEnabled,
liveActivitiesEnabled: row.liveActivitiesEnabled,
})),
),
Effect.mapError(
(cause) =>
new EnvironmentLinkUserListPersistenceError({
operation: "list-delivery-users",
environmentId: input.environmentId,
cause,
}),
),
);
}),
listPublicKeysForEnvironment: Effect.fn(
"relay.environment_links.list_public_keys_for_environment",
)(function* (input) {
yield* Effect.annotateCurrentSpan({ "relay.environment_id": input.environmentId });
return yield* db
.select({ environmentPublicKey: relayEnvironmentLinks.environmentPublicKey })
.from(relayEnvironmentLinks)
.where(
and(
eq(relayEnvironmentLinks.environmentId, input.environmentId),
isNull(relayEnvironmentLinks.revokedAt),
),
)
.pipe(
Effect.map((rows) => [
...new Set(rows.map((row) => row.environmentPublicKey).filter((key) => key.length > 0)),
]),
Effect.mapError(
(cause) =>
new EnvironmentPublicKeyListPersistenceError({
environmentId: input.environmentId,
cause,
}),
),
);
}),
listForUser: Effect.fn("relay.environment_links.list_for_user")(function* (input) {
return yield* db
.select({
environmentId: relayEnvironmentLinks.environmentId,
environmentLabel: relayEnvironmentLinks.environmentLabel,
endpointHttpBaseUrl: relayEnvironmentLinks.endpointHttpBaseUrl,
endpointWsBaseUrl: relayEnvironmentLinks.endpointWsBaseUrl,
endpointProviderKind: relayEnvironmentLinks.endpointProviderKind,
createdAt: relayEnvironmentLinks.createdAt,
})
.from(relayEnvironmentLinks)
.where(
and(
eq(relayEnvironmentLinks.userId, input.userId),
isNull(relayEnvironmentLinks.revokedAt),
),
)
.pipe(
Effect.map((rows) =>
rows.map((row) => ({
environmentId: row.environmentId as RelayClientEnvironmentRecord["environmentId"],
label:
row.environmentLabel.trim().length > 0 ? row.environmentLabel : row.environmentId,
endpoint: {
httpBaseUrl: row.endpointHttpBaseUrl,
wsBaseUrl: row.endpointWsBaseUrl,
providerKind:
row.endpointProviderKind as RelayClientEnvironmentRecord["endpoint"]["providerKind"],
},
linkedAt: row.createdAt,
})),
),
Effect.mapError(
(cause) =>
new EnvironmentLinkListPersistenceError({
userId: input.userId,
cause,
}),
),
);
}),
getForUser: Effect.fn("relay.environment_links.get_for_user")(function* (input) {
yield* Effect.annotateCurrentSpan({
"relay.environment_id": input.environmentId,
});
return yield* db
.select({
environmentId: relayEnvironmentLinks.environmentId,
environmentLabel: relayEnvironmentLinks.environmentLabel,
environmentPublicKey: relayEnvironmentLinks.environmentPublicKey,
endpointHttpBaseUrl: relayEnvironmentLinks.endpointHttpBaseUrl,
endpointWsBaseUrl: relayEnvironmentLinks.endpointWsBaseUrl,
endpointProviderKind: relayEnvironmentLinks.endpointProviderKind,
createdAt: relayEnvironmentLinks.createdAt,
})
.from(relayEnvironmentLinks)
.where(
and(
eq(relayEnvironmentLinks.userId, input.userId),
eq(relayEnvironmentLinks.environmentId, input.environmentId),
isNull(relayEnvironmentLinks.revokedAt),
),
)
.limit(1)
.pipe(
Effect.map((rows) => {
const row = rows[0];
return row
? {
environmentId: row.environmentId as RelayClientEnvironmentRecord["environmentId"],
label:
row.environmentLabel.trim().length > 0
? row.environmentLabel
: row.environmentId,
endpoint: {
httpBaseUrl: row.endpointHttpBaseUrl,
wsBaseUrl: row.endpointWsBaseUrl,
providerKind:
row.endpointProviderKind as RelayClientEnvironmentRecord["endpoint"]["providerKind"],
},
environmentPublicKey: row.environmentPublicKey,
linkedAt: row.createdAt,
}
: null;
}),
Effect.mapError(
(cause) =>
new EnvironmentLinkLookupPersistenceError({
userId: input.userId,
environmentId: input.environmentId,
cause,
}),
),
);
}),
revokeForUser: Effect.fn("relay.environment_links.revoke_for_user")(function* (input) {
yield* Effect.annotateCurrentSpan({
"relay.environment_id": input.environmentId,
});
const revokedAt = DateTime.formatIso(yield* DateTime.now);
const rows = yield* db
.update(relayEnvironmentLinks)
.set({
revokedAt,
updatedAt: revokedAt,
})
.where(
and(
eq(relayEnvironmentLinks.userId, input.userId),
eq(relayEnvironmentLinks.environmentId, input.environmentId),
isNull(relayEnvironmentLinks.revokedAt),
),
)
.returning({ environmentId: relayEnvironmentLinks.environmentId })
.pipe(
Effect.mapError(
(cause) =>
new EnvironmentLinkRevokePersistenceError({
userId: input.userId,
environmentId: input.environmentId,
cause,
}),
),
);
return rows.length > 0;
}),
});
});
export const layer = Layer.effect(EnvironmentLinks, make);