Skip to content
Open
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
29 changes: 29 additions & 0 deletions .oagen-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,35 @@
"language": "node",
"generatedAt": "2026-05-19T16:22:01.987Z",
"files": [
"src/radar/fixtures/radar-list-entry-already-present-response.json",
"src/radar/fixtures/radar-standalone-assess-request.json",
"src/radar/fixtures/radar-standalone-delete-radar-list-entry-request.json",
"src/radar/fixtures/radar-standalone-response.json",
"src/radar/fixtures/radar-standalone-update-radar-attempt-request.json",
"src/radar/fixtures/radar-standalone-update-radar-list-request.json",
"src/radar/interfaces/index.ts",
"src/radar/interfaces/radar-list-action.interface.ts",
"src/radar/interfaces/radar-list-entry-already-present-response.interface.ts",
"src/radar/interfaces/radar-standalone-assess-request-action.interface.ts",
Comment thread
gjtorikian marked this conversation as resolved.
"src/radar/interfaces/radar-standalone-assess-request-auth-method.interface.ts",
"src/radar/interfaces/radar-standalone-assess-request.interface.ts",
"src/radar/interfaces/radar-standalone-delete-radar-list-entry-request.interface.ts",
"src/radar/interfaces/radar-standalone-response-blocklist-type.interface.ts",
"src/radar/interfaces/radar-standalone-response-control.interface.ts",
"src/radar/interfaces/radar-standalone-response-verdict.interface.ts",
"src/radar/interfaces/radar-standalone-response.interface.ts",
"src/radar/interfaces/radar-standalone-update-radar-attempt-request.interface.ts",
"src/radar/interfaces/radar-standalone-update-radar-list-request.interface.ts",
"src/radar/interfaces/radar-type.interface.ts",
"src/radar/radar.spec.ts",
"src/radar/radar.ts",
"src/radar/serializers/index.ts",
"src/radar/serializers/radar-list-entry-already-present-response.serializer.ts",
"src/radar/serializers/radar-standalone-assess-request.serializer.ts",
"src/radar/serializers/radar-standalone-delete-radar-list-entry-request.serializer.ts",
"src/radar/serializers/radar-standalone-response.serializer.ts",
"src/radar/serializers/radar-standalone-update-radar-attempt-request.serializer.ts",
"src/radar/serializers/radar-standalone-update-radar-list-request.serializer.ts",
"src/webhooks/fixtures/create-webhook-endpoint.json",
"src/webhooks/fixtures/list-webhook-endpoint.json",
"src/webhooks/fixtures/update-webhook-endpoint.json",
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export * from './organization-domains/interfaces';
export * from './passwordless/interfaces';
export * from './pipes/interfaces';
export * from './admin-portal/interfaces';
export * from './radar/interfaces';
export * from './roles/interfaces';
export * from './sso/interfaces';
export * from './user-management/interfaces';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"message": "Entry already present in list"
}
7 changes: 7 additions & 0 deletions src/radar/fixtures/radar-standalone-assess-request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"ip_address": "49.78.240.97",
"user_agent": "Mozilla/5.0",
"email": "user@example.com",
"auth_method": "Password",
"action": "sign-in"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"entry": "198.51.100.42"
}
7 changes: 7 additions & 0 deletions src/radar/fixtures/radar-standalone-response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"verdict": "block",
"reason": "Detected enabled Radar control",
"attempt_id": "radar_att_01HZBC6N1EB1ZY7KG32X",
"control": "bot_detection",
"blocklist_type": "ip_address"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"challenge_status": "success",
"attempt_status": "success"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"entry": "198.51.100.42"
}
15 changes: 15 additions & 0 deletions src/radar/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// This file is auto-generated by oagen. Do not edit.

export * from './radar-list-action.interface';
export * from './radar-list-entry-already-present-response.interface';
export * from './radar-standalone-assess-request-action.interface';
export * from './radar-standalone-assess-request-auth-method.interface';
export * from './radar-standalone-assess-request.interface';
export * from './radar-standalone-delete-radar-list-entry-request.interface';
export * from './radar-standalone-response-blocklist-type.interface';
export * from './radar-standalone-response-control.interface';
export * from './radar-standalone-response-verdict.interface';
export * from './radar-standalone-response.interface';
export * from './radar-standalone-update-radar-attempt-request.interface';
export * from './radar-standalone-update-radar-list-request.interface';
export * from './radar-type.interface';
9 changes: 9 additions & 0 deletions src/radar/interfaces/radar-list-action.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// This file is auto-generated by oagen. Do not edit.

export const RadarListAction = {
Block: 'block',
Allow: 'allow',
} as const;

export type RadarListAction =
(typeof RadarListAction)[keyof typeof RadarListAction];
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// This file is auto-generated by oagen. Do not edit.

export interface RadarListEntryAlreadyPresentResponse {
/** A message indicating the entry already exists. */
message: string;
}

export interface RadarListEntryAlreadyPresentResponseWire {
message: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// This file is auto-generated by oagen. Do not edit.

export const RadarStandaloneAssessRequestAction = {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we narrow this to just be "sign-up" and "sign-in"? I'm also looking at the public docs, and we support like a lot of different variations, but I think that's just iterations. Wonder if we can only show these two options publicly to try and get users to send the right one.

SignUp: 'sign-up',
SignIn: 'sign-in',
} as const;

export type RadarStandaloneAssessRequestAction =
(typeof RadarStandaloneAssessRequestAction)[keyof typeof RadarStandaloneAssessRequestAction];
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// This file is auto-generated by oagen. Do not edit.

export const RadarStandaloneAssessRequestAuthMethod = {
Password: 'Password',
Passkey: 'Passkey',
Authenticator: 'Authenticator',
SmsOtp: 'SMS_OTP',
EmailOtp: 'Email_OTP',
Social: 'Social',
SSO: 'SSO',
Other: 'Other',
} as const;

export type RadarStandaloneAssessRequestAuthMethod =
(typeof RadarStandaloneAssessRequestAuthMethod)[keyof typeof RadarStandaloneAssessRequestAuthMethod];
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// This file is auto-generated by oagen. Do not edit.

import type { RadarStandaloneAssessRequestAuthMethod } from './radar-standalone-assess-request-auth-method.interface';
import type { RadarStandaloneAssessRequestAction } from './radar-standalone-assess-request-action.interface';

export interface RadarStandaloneAssessRequest {
/** The IP address of the request to assess. */
ipAddress: string;
/** The user agent string of the request to assess. */
userAgent: string;
/** The email address of the user making the request. */
email: string;
/** The authentication method being used. */
authMethod: RadarStandaloneAssessRequestAuthMethod;
/** The action being performed. */
action: RadarStandaloneAssessRequestAction;
}

export interface RadarStandaloneAssessRequestResponse {
ip_address: string;
user_agent: string;
email: string;
auth_method: RadarStandaloneAssessRequestAuthMethod;
action: RadarStandaloneAssessRequestAction;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// This file is auto-generated by oagen. Do not edit.

export interface RadarStandaloneDeleteRadarListEntryRequest {
/** The value to remove from the list. Must match an existing entry. */
entry: string;
}

export interface RadarStandaloneDeleteRadarListEntryRequestResponse {
entry: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// This file is auto-generated by oagen. Do not edit.

export const RadarStandaloneResponseBlocklistType = {
IpAddress: 'ip_address',
Domain: 'domain',
Email: 'email',
Device: 'device',
UserAgent: 'user_agent',
DeviceFingerprint: 'device_fingerprint',
Country: 'country',
} as const;
Comment thread
gjtorikian marked this conversation as resolved.

export type RadarStandaloneResponseBlocklistType =
(typeof RadarStandaloneResponseBlocklistType)[keyof typeof RadarStandaloneResponseBlocklistType];
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// This file is auto-generated by oagen. Do not edit.

export const RadarStandaloneResponseControl = {
BotDetection: 'bot_detection',
BruteForceAttack: 'brute_force_attack',
DomainSignUpRateLimit: 'domain_sign_up_rate_limit',
ImpossibleTravel: 'impossible_travel',
RepeatSignUp: 'repeat_sign_up',
StaleAccount: 'stale_account',
UnrecognizedDevice: 'unrecognized_device',
Restriction: 'restriction',
} as const;

export type RadarStandaloneResponseControl =
(typeof RadarStandaloneResponseControl)[keyof typeof RadarStandaloneResponseControl];
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// This file is auto-generated by oagen. Do not edit.

export const RadarStandaloneResponseVerdict = {
Allow: 'allow',
Block: 'block',
Challenge: 'challenge',
} as const;

export type RadarStandaloneResponseVerdict =
(typeof RadarStandaloneResponseVerdict)[keyof typeof RadarStandaloneResponseVerdict];
26 changes: 26 additions & 0 deletions src/radar/interfaces/radar-standalone-response.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// This file is auto-generated by oagen. Do not edit.

import type { RadarStandaloneResponseVerdict } from './radar-standalone-response-verdict.interface';
import type { RadarStandaloneResponseControl } from './radar-standalone-response-control.interface';
import type { RadarStandaloneResponseBlocklistType } from './radar-standalone-response-blocklist-type.interface';

export interface RadarStandaloneResponse {
/** The verdict of the risk assessment. */
verdict: RadarStandaloneResponseVerdict;
/** A human-readable reason for the verdict. */
reason: string;
/** Unique identifier of the authentication attempt. */
attemptId: string;
/** The Radar control that triggered the verdict. Only present if the verdict is `block` or `challenge`. */
control?: RadarStandaloneResponseControl;
/** The type of blocklist entry that triggered the verdict. Only present if the control is `restriction`. */
blocklistType?: RadarStandaloneResponseBlocklistType;
}

export interface RadarStandaloneResponseWire {
verdict: RadarStandaloneResponseVerdict;
reason: string;
attempt_id: string;
control?: RadarStandaloneResponseControl;
blocklist_type?: RadarStandaloneResponseBlocklistType;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// This file is auto-generated by oagen. Do not edit.

export interface RadarStandaloneUpdateRadarAttemptRequest {
/** Set to `"success"` to mark the challenge as completed. */
challengeStatus?: 'success';
/** Set to `"success"` to mark the authentication attempt as successful. */
attemptStatus?: 'success';
}

export interface RadarStandaloneUpdateRadarAttemptRequestResponse {
challenge_status?: 'success';
attempt_status?: 'success';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// This file is auto-generated by oagen. Do not edit.

export interface RadarStandaloneUpdateRadarListRequest {
/** The value to add to the list. Must match the format of the list type (e.g. a valid IP address for `ip_address`, a valid email for `email`). */
entry: string;
}

export interface RadarStandaloneUpdateRadarListRequestResponse {
entry: string;
}
13 changes: 13 additions & 0 deletions src/radar/interfaces/radar-type.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// This file is auto-generated by oagen. Do not edit.

export const RadarType = {
IpAddress: 'ip_address',
Domain: 'domain',
Email: 'email',
Device: 'device',
UserAgent: 'user_agent',
DeviceFingerprint: 'device_fingerprint',
Country: 'country',
} as const;

export type RadarType = (typeof RadarType)[keyof typeof RadarType];
107 changes: 107 additions & 0 deletions src/radar/radar.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// This file is auto-generated by oagen. Do not edit.

import fetch from 'jest-fetch-mock';
import {
fetchOnce,
fetchURL,
fetchMethod,
fetchBody,
} from '../common/utils/test-utils';
import { WorkOS } from '../workos';

import radarStandaloneResponseFixture from './fixtures/radar-standalone-response.json';
import radarListEntryAlreadyPresentResponseFixture from './fixtures/radar-list-entry-already-present-response.json';

const workos = new WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');

describe('Radar', () => {
beforeEach(() => fetch.resetMocks());

describe('createAttempt', () => {
it('sends the correct request and returns result', async () => {
fetchOnce(radarStandaloneResponseFixture);

const result = await workos.radar.createAttempt({
ipAddress: 'test_ip_address',
userAgent: 'test_user_agent',
email: 'test@example.com',
authMethod: 'Password',
action: 'sign-up',
});

expect(fetchMethod()).toBe('POST');
expect(new URL(String(fetchURL())).pathname).toBe('/radar/attempts');
expect(fetchBody()).toEqual(
expect.objectContaining({
ip_address: 'test_ip_address',
user_agent: 'test_user_agent',
email: 'test@example.com',
auth_method: 'Password',
action: 'sign-up',
}),
);
expect(result.verdict).toBe('block');
expect(result.reason).toBe('Detected enabled Radar control');
expect(result.attemptId).toBe('radar_att_01HZBC6N1EB1ZY7KG32X');
});
});

describe('updateAttempt', () => {
it('sends the request', async () => {
fetchOnce({});

await workos.radar.updateAttempt('test_id', {
challengeStatus: 'success',
attemptStatus: 'success',
});

expect(fetchMethod()).toBe('PUT');
expect(new URL(String(fetchURL())).pathname).toBe(
'/radar/attempts/test_id',
);
expect(fetchBody()).toEqual(
expect.objectContaining({
challenge_status: 'success',
attempt_status: 'success',
}),
);
});
});

describe('addListEntry', () => {
it('sends the correct request and returns result', async () => {
fetchOnce(radarListEntryAlreadyPresentResponseFixture);

const result = await workos.radar.addListEntry('ip_address', 'block', {
entry: 'test_entry',
});

expect(fetchMethod()).toBe('POST');
expect(new URL(String(fetchURL())).pathname).toBe(
'/radar/lists/ip_address/block',
);
expect(fetchBody()).toEqual(
expect.objectContaining({ entry: 'test_entry' }),
);
expect(result.message).toBe('Entry already present in list');
});
});

describe('removeListEntry', () => {
it('sends a DELETE request', async () => {
fetchOnce({}, { status: 204 });

await workos.radar.removeListEntry('ip_address', 'block', {
entry: 'test_entry',
});

expect(fetchMethod()).toBe('DELETE');
expect(new URL(String(fetchURL())).pathname).toBe(
'/radar/lists/ip_address/block',
);
expect(fetchBody()).toEqual(
expect.objectContaining({ entry: 'test_entry' }),
);
});
});
});
Loading