Skip to main content

Pre-built Routes

The @elcto/api library includes pre-built route functions for common API operations. These functions handle GraphQL/REST queries internally and provide typed responses.

Config-first

Every route helper takes an ApiClientConfig as its first argument. Pass getApiConfig() from @/lib/api (the library reads no env itself):

import { getApiConfig } from "@/lib/api";
import { getActiveSessions } from "@elcto/api";

const { sessions } = await getActiveSessions(getApiConfig(), currentToken, {
accessToken: session.accessToken,
});
User data

There are no REST route helpers for user profile / permissions / accounts. Fetch user data over GraphQL instead — the userProfile, userPermissions, user and users operations in the GraphQL API. The apps wrap these in their own /api/user/* routes.

Session Routes​

Functions for managing user sessions.

import {
getActiveSessions,
revokeSession,
revokeAllOtherSessions,
} from "@elcto/api";

getActiveSessions​

Get all active sessions for the authenticated user. Pass the current session token to flag which session is current; pass GraphQL request options (including accessToken) to authenticate.

const { sessions, currentSessionId } = await getActiveSessions(getApiConfig(), currentToken, {
accessToken: session.accessToken,
});

// Mark current session
const sessionsWithCurrent = sessions.map(s => ({
...s,
isCurrent: s.id === currentSessionId,
}));

Parameters:

ParameterTypeDescription
configApiClientConfigAPI client config — use getApiConfig()
currentTokenstringOptional session token identifying the current session
optionsGraphQLRequestOptionsOptional GraphQL request options (including accessToken)

Returns: Promise<ActiveSessionsResponse>

interface ActiveSessionsResponse {
sessions: ActiveSession[];
currentSessionId: string | null;
}

revokeSession​

Revoke a specific session. Cannot revoke the current session.

const result = await revokeSession(getApiConfig(), sessionId, currentToken, {
accessToken: session.accessToken,
});

if (result.success) {
console.log(result.message);
}

Parameters:

ParameterTypeDescription
configApiClientConfigAPI client config — use getApiConfig()
sessionIdstringID of the session to revoke
currentTokenstringOptional session token to prevent revoking the current session
optionsGraphQLRequestOptionsOptional GraphQL request options (including accessToken)

Returns: Promise<RevokeSessionResponse>

interface RevokeSessionResponse {
success: boolean;
message: string;
}

revokeAllOtherSessions​

Revoke all sessions except the current one.

const result = await revokeAllOtherSessions(getApiConfig(), currentToken, {
accessToken: session.accessToken,
});

console.log(`Revoked ${result.revokedCount} sessions`);

Parameters:

ParameterTypeDescription
configApiClientConfigAPI client config — use getApiConfig()
currentTokenstringOptional session token to exclude from revocation
optionsGraphQLRequestOptionsOptional GraphQL request options (including accessToken)

Returns: Promise<RevokeAllSessionsResponse>

interface RevokeAllSessionsResponse {
success: boolean;
revokedCount: number;
message: string;
}

Audit Routes​

Functions for accessing and managing audit logs.

import {
getMyAuditLog,
getUserAuditLog,
getAllAuditEvents,
logAuditEvent,
reportAuditEvent,
getMyAuditReports,
} from "@elcto/api";

getMyAuditLog​

Get the current user's activity log.

const auditPage = await getMyAuditLog(
getApiConfig(),
{
page: 1,
limit: 20,
eventType: "login",
status: "success",
},
headers
);

console.log(`Found ${auditPage.totalCount} events`);

Parameters:

ParameterTypeDescription
configApiClientConfigAPI client config — use getApiConfig()
queryAuditEventQueryQuery parameters
headersRecord<string, string>Optional headers

Returns: Promise<AuditEventPage>

getUserAuditLog​

Get audit log for a specific user (admin only).

const auditPage = await getUserAuditLog(
getApiConfig(),
userId,
{ page: 1, limit: 50 },
headers
);

Parameters:

ParameterTypeDescription
configApiClientConfigAPI client config — use getApiConfig()
userIdstringTarget user ID
queryAuditEventQueryQuery parameters
headersRecord<string, string>Optional headers

Returns: Promise<AuditEventPage>

Required Permission: audit:read

getAllAuditEvents​

Get all audit events with advanced filtering (admin only).

const auditPage = await getAllAuditEvents(
getApiConfig(),
{
page: 1,
limit: 50,
eventType: "login_failed",
sourceService: "id",
startDate: "2024-01-01T00:00:00Z",
endDate: "2024-01-31T23:59:59Z",
sortField: "createdAt",
sortDirection: "desc",
isReported: true,
},
headers
);

Query Parameters:

ParameterTypeDescription
pagenumberPage number (1-indexed)
limitnumberItems per page
eventTypestringFilter by event type
eventTypesstringComma-separated event types
userIdstringFilter by user ID
userSearchstringSearch by username
resourceTypestringFilter by resource type
statusstringFilter by status ("success" or "failure")
sourceServicestringFilter by source service
startDatestringStart date (ISO 8601)
endDatestringEnd date (ISO 8601)
sortFieldstringSort field
sortDirectionstring"asc" or "desc"
isReportedbooleanFilter reported events

Required Permission: audit:read

logAuditEvent​

Log an audit event programmatically.

import { AuditEventTypes, AuditResourceTypes, AuditSourceServices } from "@elcto/api";

const event = await logAuditEvent(
getApiConfig(),
{
userId: user.id,
eventType: AuditEventTypes.USER_UPDATED,
resourceType: AuditResourceTypes.USER,
resourceId: targetUserId,
description: "Custom action performed",
metadata: { action: "example" },
ipAddress: clientIp,
userAgent: userAgent,
status: "success",
sourceService: AuditSourceServices.BACKEND,
},
headers
);

Parameters:

FieldTypeRequiredDescription
userIdstringNoUser ID (optional for system events)
eventTypestringYesEvent type constant
resourceTypestringNoResource type
resourceIdstringNoResource ID
actorIdstringNoActor user ID (if different from userId)
descriptionstringNoHuman-readable description
metadataobjectNoAdditional data
ipAddressstringNoClient IP address
userAgentstringNoClient user agent
statusstringNo"success" or "failure"
errorMessagestringNoError message (if failure)
sourceServicestringNoSource service identifier

reportAuditEvent​

Report an audit event as suspicious activity.

const result = await reportAuditEvent(
getApiConfig(),
{
auditEventId: event.id,
reason: "not_me",
description: "I didn't perform this action",
},
headers
);

if (result.success) {
console.log("Report submitted:", result.report?.id);
}

Input:

FieldTypeRequiredDescription
auditEventIdstringYesAudit event ID to report
reasonstringYesReason: "not_me", "suspicious", "unknown_device", "unknown_location", "other"
descriptionstringNoAdditional details

Returns: Promise<ReportAuditEventResponse>

getMyAuditReports​

Get the current user's submitted reports.

const reports = await getMyAuditReports(getApiConfig(), headers);

const pendingReports = reports.filter(r => r.status === "pending");

Parameters:

ParameterTypeDescription
configApiClientConfigAPI client config — use getApiConfig()
headersRecord<string, string>Optional headers

Returns: Promise<AuditEventReport[]>


Admin Audit Routes​

Additional audit functions for administrators.

import {
getAllAuditReports,
updateAuditReport,
} from "@elcto/api";

getAllAuditReports​

Get all audit reports (admin only).

const reportPage = await getAllAuditReports(
getApiConfig(),
{
page: 1,
limit: 20,
status: "pending",
},
headers
);

Query Parameters:

ParameterTypeDescription
pagenumberPage number
limitnumberItems per page
statusstringFilter by status: "pending", "reviewed", "resolved", "dismissed"

Required Permission: audit:read

updateAuditReport​

Update an audit report status (admin only).

const result = await updateAuditReport(
getApiConfig(),
{
reportId: report.id,
status: "resolved",
resolutionNotes: "Confirmed unauthorized access. User notified and security measures taken.",
},
headers
);

Input:

FieldTypeRequiredDescription
reportIdstringYesReport ID
statusstringYesNew status: "reviewed", "resolved", "dismissed"
resolutionNotesstringNoNotes about resolution

Required Permission: audit:write


Vessel Routes (AIS)​

GraphQL-based read helpers for the AIS vessel query API. See Vessels API for the full endpoint reference. There is intentionally no getVesselTrack helper — the registry is static-only and positions are never persisted to Postgres; live positions stream over the WebSocket "vessels" channel instead.

import { getVessels, getVessel } from "@elcto/api";

getVessels​

List vessels from the static registry (paginated, filterable by name / ship type). Position fields are always null in this list. Requires ais:read.

const page = await getVessels(
getApiConfig(),
{ filter: { name: "rena", shipTypeCode: 70 }, page: 1, limit: 20 },
{ Authorization: `Bearer ${session.accessToken}` }
);

console.log(`Found ${page.total} vessels`);

Parameters:

ParameterTypeDescription
configApiClientConfigAPI client config — use getApiConfig()
params.filterVesselFilterInputOptional { name?, shipTypeCode? } filter
params.pagenumberPage number (1-indexed), default 1
params.limitnumberItems per page, default 20
headersRecord<string, string>Headers to extract the caller's Bearer token from

Returns: Promise<PaginatedVessel>

getVessel​

Get a single vessel by MMSI. Reads the Redis hot cache first (live position included), falling back to the static registry (position fields null) on a cache miss. Requires ais:read.

const vessel = await getVessel(getApiConfig(), 211234560, {
Authorization: `Bearer ${session.accessToken}`,
});

if (vessel?.lat != null) {
console.log(`Live position: ${vessel.lat}, ${vessel.lng}`);
}

Parameters:

ParameterTypeDescription
configApiClientConfigAPI client config — use getApiConfig()
mmsinumberVessel MMSI
headersRecord<string, string>Headers to extract the caller's Bearer token from

Returns: Promise<Vessel | null> — null if the vessel is in neither Redis nor the registry.


Usage in Next.js API Routes​

Example: Session Management​

// src/app/api/sessions/route.ts
import { NextRequest, NextResponse } from "next/server";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import { getActiveSessions, handleApiError } from "@elcto/api";
import { getApiConfig } from "@/lib/api";

export async function GET(request: NextRequest) {
try {
const session = await getServerSession(authOptions);
if (!session?.user?.id) {
return NextResponse.json(
{ error: "Unauthorized", code: "UNAUTHORIZED" },
{ status: 401 }
);
}

const result = await getActiveSessions(getApiConfig(), undefined, {
accessToken: session.accessToken,
});

return NextResponse.json(result);
} catch (error) {
return handleApiError(request, error, {
route: "sessions/list",
defaultMessage: "Failed to fetch sessions",
});
}
}

Example: Audit Activity Page​

// src/app/api/account/activity/route.ts
import { NextRequest, NextResponse } from "next/server";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import { getMyAuditLog, handleApiError } from "@elcto/api";
import { getApiConfig } from "@/lib/api";

export async function GET(request: NextRequest) {
try {
const session = await getServerSession(authOptions);
if (!session?.user?.id) {
return NextResponse.json(
{ error: "Unauthorized", code: "UNAUTHORIZED" },
{ status: 401 }
);
}

const { searchParams } = new URL(request.url);
const page = parseInt(searchParams.get("page") || "1");
const limit = parseInt(searchParams.get("limit") || "20");
const eventType = searchParams.get("eventType") || undefined;

const headers = {
Authorization: `Bearer ${session.accessToken}`,
};

const result = await getMyAuditLog(
getApiConfig(),
{ page, limit, eventType },
headers
);

return NextResponse.json(result);
} catch (error) {
return handleApiError(request, error, {
route: "account/activity",
defaultMessage: "Failed to fetch activity log",
});
}
}