@atlasauth/backend 0.24.0 → 0.25.0
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/CHANGELOG.md +7 -0
- package/dist/client/abac.d.ts +132 -0
- package/dist/client/abac.js +48 -0
- package/dist/client/abac.js.map +1 -0
- package/dist/client/access-policies.d.ts +100 -0
- package/dist/client/access-policies.js +29 -0
- package/dist/client/access-policies.js.map +1 -0
- package/dist/client/action-gallery.d.ts +1 -1
- package/dist/client/action-gallery.js.map +1 -1
- package/dist/client/actions.d.ts +129 -6
- package/dist/client/actions.js +4 -0
- package/dist/client/actions.js.map +1 -1
- package/dist/client/analytics-reports.d.ts +215 -0
- package/dist/client/analytics-reports.js +56 -0
- package/dist/client/analytics-reports.js.map +1 -0
- package/dist/client/app-catalog.d.ts +74 -0
- package/dist/client/app-catalog.js +30 -0
- package/dist/client/app-catalog.js.map +1 -0
- package/dist/client/attack-protection.d.ts +10 -0
- package/dist/client/attack-protection.js +8 -0
- package/dist/client/attack-protection.js.map +1 -1
- package/dist/client/audit-events.d.ts +71 -0
- package/dist/client/audit-events.js +28 -0
- package/dist/client/audit-events.js.map +1 -1
- package/dist/client/credentials.d.ts +8 -0
- package/dist/client/credentials.js.map +1 -1
- package/dist/client/delegated-ui-proxy.d.ts +25 -0
- package/dist/client/delegated-ui-proxy.js +46 -0
- package/dist/client/delegated-ui-proxy.js.map +1 -0
- package/dist/client/devices.d.ts +44 -0
- package/dist/client/devices.js +26 -0
- package/dist/client/devices.js.map +1 -0
- package/dist/client/email-templates.d.ts +1 -1
- package/dist/client/email-templates.js.map +1 -1
- package/dist/client/flags.d.ts +101 -0
- package/dist/client/flags.js +104 -0
- package/dist/client/flags.js.map +1 -0
- package/dist/client/groups.d.ts +146 -0
- package/dist/client/groups.js +67 -0
- package/dist/client/groups.js.map +1 -0
- package/dist/client/identity-verification.d.ts +62 -0
- package/dist/client/identity-verification.js +39 -0
- package/dist/client/identity-verification.js.map +1 -0
- package/dist/client/index.d.ts +943 -2
- package/dist/client/index.js +73 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/journeys.d.ts +108 -0
- package/dist/client/journeys.js +35 -0
- package/dist/client/journeys.js.map +1 -0
- package/dist/client/log-streams.d.ts +1 -1
- package/dist/client/marketing.d.ts +67 -0
- package/dist/client/marketing.js +26 -0
- package/dist/client/marketing.js.map +1 -0
- package/dist/client/mcp-gateways.d.ts +54 -0
- package/dist/client/mcp-gateways.js +25 -0
- package/dist/client/mcp-gateways.js.map +1 -0
- package/dist/client/messaging.d.ts +14 -3
- package/dist/client/messaging.js.map +1 -1
- package/dist/client/mfa-factors.d.ts +120 -0
- package/dist/client/mfa-factors.js +73 -0
- package/dist/client/mfa-factors.js.map +1 -0
- package/dist/client/migrations.d.ts +1 -1
- package/dist/client/migrations.js.map +1 -1
- package/dist/client/network-acls.d.ts +6 -1
- package/dist/client/network-acls.js.map +1 -1
- package/dist/client/network-zones.d.ts +56 -0
- package/dist/client/network-zones.js +29 -0
- package/dist/client/network-zones.js.map +1 -0
- package/dist/client/notifications.d.ts +1 -1
- package/dist/client/notifications.js.map +1 -1
- package/dist/client/oauth-clients.d.ts +183 -3
- package/dist/client/oauth-clients.js +64 -0
- package/dist/client/oauth-clients.js.map +1 -1
- package/dist/client/org-role-grants.d.ts +57 -0
- package/dist/client/org-role-grants.js +40 -0
- package/dist/client/org-role-grants.js.map +1 -0
- package/dist/client/organizations.d.ts +52 -0
- package/dist/client/organizations.js +44 -0
- package/dist/client/organizations.js.map +1 -1
- package/dist/client/page-templates.d.ts +78 -0
- package/dist/client/page-templates.js +31 -0
- package/dist/client/page-templates.js.map +1 -0
- package/dist/client/passkey-api.d.ts +73 -0
- package/dist/client/passkey-api.js +34 -0
- package/dist/client/passkey-api.js.map +1 -0
- package/dist/client/resources.d.ts +149 -0
- package/dist/client/resources.js +73 -0
- package/dist/client/resources.js.map +1 -0
- package/dist/client/risk-based-mfa.d.ts +147 -0
- package/dist/client/risk-based-mfa.js +30 -0
- package/dist/client/risk-based-mfa.js.map +1 -1
- package/dist/client/roles.d.ts +4 -0
- package/dist/client/roles.js.map +1 -1
- package/dist/client/service-connectors.d.ts +83 -0
- package/dist/client/service-connectors.js +33 -0
- package/dist/client/service-connectors.js.map +1 -0
- package/dist/client/ssf.d.ts +111 -0
- package/dist/client/ssf.js +49 -0
- package/dist/client/ssf.js.map +1 -0
- package/dist/client/sso-onboarding.d.ts +6 -0
- package/dist/client/sso-onboarding.js.map +1 -1
- package/dist/client/users.d.ts +302 -0
- package/dist/client/users.js +125 -0
- package/dist/client/users.js.map +1 -1
- package/dist/client/vault.d.ts +85 -0
- package/dist/client/vault.js +50 -0
- package/dist/client/vault.js.map +1 -0
- package/dist/client/vc.d.ts +128 -0
- package/dist/client/vc.js +43 -0
- package/dist/client/vc.js.map +1 -0
- package/dist/client/webhooks.d.ts +31 -2
- package/dist/client/webhooks.js.map +1 -1
- package/dist/client/workflows.d.ts +131 -0
- package/dist/client/workflows.js +36 -0
- package/dist/client/workflows.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/magic-did.d.ts +5 -0
- package/dist/magic-did.js +49 -0
- package/dist/magic-did.js.map +1 -0
- package/dist/migration-bridge.d.ts +9 -0
- package/dist/migration-bridge.js +28 -2
- package/dist/migration-bridge.js.map +1 -1
- package/dist/migration-presets-g3.d.ts +2 -0
- package/dist/migration-presets-g3.js +254 -0
- package/dist/migration-presets-g3.js.map +1 -0
- package/dist/migration-presets-g4/authentik.d.ts +14 -0
- package/dist/migration-presets-g4/authentik.js +37 -0
- package/dist/migration-presets-g4/authentik.js.map +1 -0
- package/dist/migration-presets-g4/fusionauth.d.ts +2 -0
- package/dist/migration-presets-g4/fusionauth.js +52 -0
- package/dist/migration-presets-g4/fusionauth.js.map +1 -0
- package/dist/migration-presets-g4/hanko.d.ts +12 -0
- package/dist/migration-presets-g4/hanko.js +46 -0
- package/dist/migration-presets-g4/hanko.js.map +1 -0
- package/dist/migration-presets-g4/keycloak.d.ts +16 -0
- package/dist/migration-presets-g4/keycloak.js +37 -0
- package/dist/migration-presets-g4/keycloak.js.map +1 -0
- package/dist/migration-presets-g4/logto.d.ts +12 -0
- package/dist/migration-presets-g4/logto.js +35 -0
- package/dist/migration-presets-g4/logto.js.map +1 -0
- package/dist/migration-presets-g4/ory.d.ts +2 -0
- package/dist/migration-presets-g4/ory.js +67 -0
- package/dist/migration-presets-g4/ory.js.map +1 -0
- package/dist/migration-presets-g4/supertokens.d.ts +13 -0
- package/dist/migration-presets-g4/supertokens.js +35 -0
- package/dist/migration-presets-g4/supertokens.js.map +1 -0
- package/dist/migration-presets-g4/zitadel.d.ts +2 -0
- package/dist/migration-presets-g4/zitadel.js +36 -0
- package/dist/migration-presets-g4/zitadel.js.map +1 -0
- package/dist/migration-presets-g4.d.ts +10 -0
- package/dist/migration-presets-g4.js +30 -0
- package/dist/migration-presets-g4.js.map +1 -0
- package/dist/migration-presets.d.ts +6 -0
- package/dist/migration-presets.js +102 -6
- package/dist/migration-presets.js.map +1 -1
- package/dist/request-auth.d.ts +32 -0
- package/dist/request-auth.js +72 -0
- package/dist/request-auth.js.map +1 -0
- package/dist/verify.d.ts +2 -0
- package/dist/verify.js.map +1 -1
- package/dist/workos-session.d.ts +30 -0
- package/dist/workos-session.js +123 -0
- package/dist/workos-session.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.delegatedUiProxy = delegatedUiProxy;
|
|
4
|
+
/**
|
|
5
|
+
* The backend half of the browser helper `createDelegatedUiClient` (@atlasauth/js).
|
|
6
|
+
* Mount it under any route; it forwards the challenge calls to Atlas with your
|
|
7
|
+
* secret key. YOU must authenticate the visitor before letting an `accept`
|
|
8
|
+
* through: pass `authorize` to decide (return the Atlas user id for a login
|
|
9
|
+
* accept, or throw / return null to refuse).
|
|
10
|
+
*/
|
|
11
|
+
function delegatedUiProxy(atlas, opts) {
|
|
12
|
+
return async function handle(req) {
|
|
13
|
+
const login = req.query.login_challenge;
|
|
14
|
+
const consent = req.query.consent_challenge;
|
|
15
|
+
const body = (req.body ?? {});
|
|
16
|
+
try {
|
|
17
|
+
const route = `${req.method.toUpperCase()} ${req.path.replace(/^\/|\/$/g, '')}`;
|
|
18
|
+
if (route === 'GET login' && login)
|
|
19
|
+
return { status: 200, body: await atlas.oauthClients.loginRequests.get(login) };
|
|
20
|
+
if (route === 'GET consent' && consent)
|
|
21
|
+
return { status: 200, body: await atlas.oauthClients.consentRequests.get(consent) };
|
|
22
|
+
if (route === 'POST login/reject' && login)
|
|
23
|
+
return { status: 200, body: await atlas.oauthClients.loginRequests.reject(login, body) };
|
|
24
|
+
if (route === 'POST consent/reject' && consent)
|
|
25
|
+
return { status: 200, body: await atlas.oauthClients.consentRequests.reject(consent, body) };
|
|
26
|
+
if (route === 'POST login/accept' && login) {
|
|
27
|
+
const subject = await opts.authorize(req);
|
|
28
|
+
if (!subject)
|
|
29
|
+
return { status: 401, body: { error: { message: 'Not signed in.' } } };
|
|
30
|
+
// The subject is decided by your authorize(), never by the browser.
|
|
31
|
+
return { status: 200, body: await atlas.oauthClients.loginRequests.accept(login, { ...body, subject }) };
|
|
32
|
+
}
|
|
33
|
+
if (route === 'POST consent/accept' && consent) {
|
|
34
|
+
if (!(await opts.authorize(req)))
|
|
35
|
+
return { status: 401, body: { error: { message: 'Not signed in.' } } };
|
|
36
|
+
return { status: 200, body: await atlas.oauthClients.consentRequests.accept(consent, body) };
|
|
37
|
+
}
|
|
38
|
+
return { status: 404, body: { error: { message: 'Unknown route.' } } };
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
const status = e.status ?? 502;
|
|
42
|
+
return { status, body: { error: { message: e instanceof Error ? e.message : 'Request failed.' } } };
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=delegated-ui-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegated-ui-proxy.js","sourceRoot":"","sources":["../../src/client/delegated-ui-proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type RequestFn } from './request';
|
|
2
|
+
import type { ListPage } from './types';
|
|
3
|
+
export interface Device {
|
|
4
|
+
object: 'device';
|
|
5
|
+
id: string;
|
|
6
|
+
user_id: string | null;
|
|
7
|
+
source: string;
|
|
8
|
+
external_id: string;
|
|
9
|
+
name: string | null;
|
|
10
|
+
platform: string | null;
|
|
11
|
+
managed: boolean;
|
|
12
|
+
compliant: boolean;
|
|
13
|
+
posture: Record<string, unknown>;
|
|
14
|
+
last_reported_at: number;
|
|
15
|
+
created_at: number;
|
|
16
|
+
}
|
|
17
|
+
/** One posture report. Identify the owner with `user_id` or a verified `user_email`. */
|
|
18
|
+
export interface DeviceReportBody {
|
|
19
|
+
external_id: string;
|
|
20
|
+
/** Who reported it (`intune`, `jamf`, …); defaults to `api`. */
|
|
21
|
+
source?: string;
|
|
22
|
+
user_id?: string | null;
|
|
23
|
+
user_email?: string;
|
|
24
|
+
name?: string | null;
|
|
25
|
+
platform?: string | null;
|
|
26
|
+
managed?: boolean;
|
|
27
|
+
compliant?: boolean;
|
|
28
|
+
posture?: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
export declare function devicesResource(request: RequestFn): {
|
|
31
|
+
list(query?: {
|
|
32
|
+
user_id?: string;
|
|
33
|
+
source?: string;
|
|
34
|
+
}): Promise<ListPage<Device>>;
|
|
35
|
+
get(id: string): Promise<Device>;
|
|
36
|
+
report(body: DeviceReportBody): Promise<Device>;
|
|
37
|
+
/** Bulk posture ingestion, up to 500 reports. */
|
|
38
|
+
ingestPosture(devices: DeviceReportBody[]): Promise<ListPage<Device>>;
|
|
39
|
+
remove(id: string): Promise<{
|
|
40
|
+
object: "device";
|
|
41
|
+
id: string;
|
|
42
|
+
deleted: true;
|
|
43
|
+
}>;
|
|
44
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.devicesResource = devicesResource;
|
|
4
|
+
const request_1 = require("./request");
|
|
5
|
+
function devicesResource(request) {
|
|
6
|
+
return {
|
|
7
|
+
list(query = {}) {
|
|
8
|
+
const q = new URLSearchParams(Object.entries(query).filter((e) => e[1] !== undefined)).toString();
|
|
9
|
+
return request({ method: 'GET', path: `/v1/devices${q ? `?${q}` : ''}` });
|
|
10
|
+
},
|
|
11
|
+
get(id) {
|
|
12
|
+
return request({ method: 'GET', path: `/v1/devices/${(0, request_1.enc)(id)}` });
|
|
13
|
+
},
|
|
14
|
+
report(body) {
|
|
15
|
+
return request({ method: 'PUT', path: '/v1/devices', body });
|
|
16
|
+
},
|
|
17
|
+
/** Bulk posture ingestion, up to 500 reports. */
|
|
18
|
+
ingestPosture(devices) {
|
|
19
|
+
return request({ method: 'POST', path: '/v1/device_posture', body: { devices } });
|
|
20
|
+
},
|
|
21
|
+
remove(id) {
|
|
22
|
+
return request({ method: 'DELETE', path: `/v1/devices/${(0, request_1.enc)(id)}` });
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=devices.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devices.js","sourceRoot":"","sources":["../../src/client/devices.ts"],"names":[],"mappings":";;AAgCA,0CAoBC;AApDD,uCAAgD;AAgChD,SAAgB,eAAe,CAAC,OAAkB;IAChD,OAAO;QACL,IAAI,CAAC,QAA+C,EAAE;YACpD,MAAM,CAAC,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAyB,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;YACzH,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC5E,CAAC;QACD,GAAG,CAAC,EAAU;YACZ,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,eAAe,IAAA,aAAG,EAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACpE,CAAC;QACD,MAAM,CAAC,IAAsB;YAC3B,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,CAAC;QACD,iDAAiD;QACjD,aAAa,CAAC,OAA2B;YACvC,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;QACpF,CAAC;QACD,MAAM,CAAC,EAAU;YACf,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,eAAe,IAAA,aAAG,EAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACvE,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type RequestFn } from './request';
|
|
2
2
|
import type { ListPage } from './types';
|
|
3
3
|
/** The transactional email a template drives. */
|
|
4
|
-
export type EmailTemplateName = 'verification_code' | 'magic_link' | 'password_reset' | 'password_changed' | 'account_exists_notice' | 'organization_invitation' | 'new_device_sign_in' | 'session_revoked_token_reuse' | 'account_locked' | 'account_secured' | 'team_member_added' | 'team_role_changed' | 'email_changed' | 'verification_link' | 'password_reset_link' | 'account_reactivated';
|
|
4
|
+
export type EmailTemplateName = 'verification_code' | 'magic_link' | 'password_reset' | 'password_changed' | 'account_exists_notice' | 'organization_invitation' | 'new_device_sign_in' | 'session_revoked_token_reuse' | 'account_locked' | 'account_secured' | 'team_member_added' | 'team_role_changed' | 'email_changed' | 'email_change_confirm' | 'parental_consent_request' | 'phone_changed' | 'identity_linked' | 'identity_unlinked' | 'passkey_added' | 'passkey_removed' | 'recovery_codes_regenerated' | 'factor_removed' | 'device_key_added' | 'device_key_removed' | 'risk_alert' | 'verification_link' | 'password_reset_link' | 'account_reactivated';
|
|
5
5
|
/** The customizable body of a template: a subject line and a text body. */
|
|
6
6
|
export interface EmailTemplateBody {
|
|
7
7
|
subject?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email-templates.js","sourceRoot":"","sources":["../../src/client/email-templates.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"email-templates.js","sourceRoot":"","sources":["../../src/client/email-templates.ts"],"names":[],"mappings":";;AAyEA,wDAkBC;AA3FD,uCAAgD;AAyEhD,SAAgB,sBAAsB,CAAC,OAAkB;IACvD,OAAO;QACL,IAAI;YACF,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC,CAAC;QACjE,CAAC;QACD,2EAA2E;QAC3E,OAAO,CAAC,IAAY,EAAE,OAA0B,EAAE;YAChD,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,IAAA,aAAG,EAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7F,CAAC;QACD,2DAA2D;QAC3D,MAAM,CAAC,IAAY,EAAE,IAAuB;YAC1C,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,uBAAuB,IAAA,aAAG,EAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QACpF,CAAC;QACD,8BAA8B;QAC9B,MAAM,CAAC,IAAY;YACjB,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,uBAAuB,IAAA,aAAG,EAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QACjF,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { type RequestFn } from './request';
|
|
2
|
+
import type { CursorParams } from './types';
|
|
3
|
+
export type FeatureFlagType = 'boolean' | 'string' | 'int' | 'json';
|
|
4
|
+
export type FeatureFlagValue = boolean | string | number | Record<string, unknown> | unknown[];
|
|
5
|
+
/** Who a flag is evaluated for. `user_id` (else `org_id`) seeds percentage rollouts. */
|
|
6
|
+
export interface FeatureFlagSubject {
|
|
7
|
+
user_id?: string | null;
|
|
8
|
+
org_id?: string | null;
|
|
9
|
+
plan?: string | null;
|
|
10
|
+
}
|
|
11
|
+
/** Every given `match` dimension must hold; an empty rule matches everyone. */
|
|
12
|
+
export interface FeatureFlagRule {
|
|
13
|
+
match?: {
|
|
14
|
+
user_ids?: string[];
|
|
15
|
+
org_ids?: string[];
|
|
16
|
+
plans?: string[];
|
|
17
|
+
};
|
|
18
|
+
/** 0–100: the share of matching subjects, stable per flag and subject. */
|
|
19
|
+
percentage?: number;
|
|
20
|
+
value: FeatureFlagValue;
|
|
21
|
+
}
|
|
22
|
+
export interface FeatureFlag {
|
|
23
|
+
object: 'feature_flag';
|
|
24
|
+
id: string;
|
|
25
|
+
key: string;
|
|
26
|
+
type: FeatureFlagType;
|
|
27
|
+
description: string | null;
|
|
28
|
+
enabled: boolean;
|
|
29
|
+
default_value: FeatureFlagValue;
|
|
30
|
+
/** Returned while the flag is switched off. */
|
|
31
|
+
off_value: FeatureFlagValue;
|
|
32
|
+
rules: FeatureFlagRule[];
|
|
33
|
+
created_at: number;
|
|
34
|
+
updated_at: number;
|
|
35
|
+
}
|
|
36
|
+
export interface CreateFeatureFlagBody {
|
|
37
|
+
key: string;
|
|
38
|
+
type: FeatureFlagType;
|
|
39
|
+
default_value: FeatureFlagValue;
|
|
40
|
+
description?: string;
|
|
41
|
+
enabled?: boolean;
|
|
42
|
+
off_value?: FeatureFlagValue;
|
|
43
|
+
rules?: FeatureFlagRule[];
|
|
44
|
+
}
|
|
45
|
+
export type UpdateFeatureFlagBody = Partial<Omit<CreateFeatureFlagBody, 'key' | 'type'>>;
|
|
46
|
+
export interface FeatureFlagEvaluation {
|
|
47
|
+
object: 'feature_flag_evaluation';
|
|
48
|
+
subject: FeatureFlagSubject;
|
|
49
|
+
flags: Record<string, {
|
|
50
|
+
value: FeatureFlagValue;
|
|
51
|
+
reason: string;
|
|
52
|
+
}>;
|
|
53
|
+
}
|
|
54
|
+
export interface AssignEntitlementsBody {
|
|
55
|
+
plan?: string | null;
|
|
56
|
+
features?: string[] | null;
|
|
57
|
+
limits?: Record<string, unknown> | null;
|
|
58
|
+
/** Epoch ms; omit for open-ended. */
|
|
59
|
+
expires_at?: number | null;
|
|
60
|
+
}
|
|
61
|
+
export interface AssignedEntitlements {
|
|
62
|
+
object: 'assigned_entitlements';
|
|
63
|
+
subject_type: 'user' | 'org';
|
|
64
|
+
subject_id: string;
|
|
65
|
+
plan: string | null;
|
|
66
|
+
features: string[] | null;
|
|
67
|
+
limits: Record<string, unknown> | null;
|
|
68
|
+
expires_at: number | null;
|
|
69
|
+
}
|
|
70
|
+
/** Evaluate a flag definition for a subject (first matching in-bucket rule wins, else the default). */
|
|
71
|
+
export declare function evaluateFeatureFlag(flag: FeatureFlag, subject: FeatureFlagSubject): FeatureFlagValue;
|
|
72
|
+
export declare function flagsResource(request: RequestFn, cacheTtlMs?: number): {
|
|
73
|
+
create(body: CreateFeatureFlagBody, idempotencyKey?: string): Promise<FeatureFlag>;
|
|
74
|
+
/** `starting_after` is the key of the last flag of the previous page. */
|
|
75
|
+
list(params?: CursorParams): Promise<{
|
|
76
|
+
object: "list";
|
|
77
|
+
data: FeatureFlag[];
|
|
78
|
+
has_more: boolean;
|
|
79
|
+
}>;
|
|
80
|
+
retrieve(key: string): Promise<FeatureFlag>;
|
|
81
|
+
update(key: string, body: UpdateFeatureFlagBody): Promise<FeatureFlag>;
|
|
82
|
+
delete(key: string): Promise<{
|
|
83
|
+
object: "feature_flag";
|
|
84
|
+
id: string;
|
|
85
|
+
key: string;
|
|
86
|
+
deleted: boolean;
|
|
87
|
+
}>;
|
|
88
|
+
/** Server-side evaluation; `plan` defaults to the org's (else the user's) resolved plan. */
|
|
89
|
+
evaluate(body: FeatureFlagSubject & {
|
|
90
|
+
keys?: string[];
|
|
91
|
+
}): Promise<FeatureFlagEvaluation>;
|
|
92
|
+
/** Local evaluation against cached definitions. `plan` is not looked up here — pass it for plan rules. */
|
|
93
|
+
get<T extends FeatureFlagValue>(key: string, subject: FeatureFlagSubject, fallback: T): Promise<T>;
|
|
94
|
+
/** True only for a boolean flag that evaluates to true; an unknown flag is false. */
|
|
95
|
+
isEnabled(key: string, subject?: FeatureFlagSubject): Promise<boolean>;
|
|
96
|
+
/** Drop the cached definitions (e.g. after changing a flag). */
|
|
97
|
+
invalidate(): void;
|
|
98
|
+
/** Replace the entitlements assigned to an organization (an empty body clears them). */
|
|
99
|
+
assignOrganizationEntitlements(orgId: string, body: AssignEntitlementsBody): Promise<AssignedEntitlements>;
|
|
100
|
+
assignUserEntitlements(userId: string, body: AssignEntitlementsBody): Promise<AssignedEntitlements>;
|
|
101
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.evaluateFeatureFlag = evaluateFeatureFlag;
|
|
4
|
+
exports.flagsResource = flagsResource;
|
|
5
|
+
const sha256_1 = require("@noble/hashes/sha256");
|
|
6
|
+
const request_1 = require("./request");
|
|
7
|
+
/** Same bucketing as the server: the same subject lands in the same bucket everywhere. */
|
|
8
|
+
function bucket(flagKey, subjectKey) {
|
|
9
|
+
const d = (0, sha256_1.sha256)(new TextEncoder().encode(`${flagKey}:${subjectKey}`));
|
|
10
|
+
return (((d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3]) >>> 0) % 100;
|
|
11
|
+
}
|
|
12
|
+
/** Evaluate a flag definition for a subject (first matching in-bucket rule wins, else the default). */
|
|
13
|
+
function evaluateFeatureFlag(flag, subject) {
|
|
14
|
+
if (!flag.enabled)
|
|
15
|
+
return flag.off_value;
|
|
16
|
+
const seed = subject.user_id ?? subject.org_id ?? '';
|
|
17
|
+
for (const rule of flag.rules) {
|
|
18
|
+
const m = rule.match ?? {};
|
|
19
|
+
if (m.user_ids && (!subject.user_id || !m.user_ids.includes(subject.user_id)))
|
|
20
|
+
continue;
|
|
21
|
+
if (m.org_ids && (!subject.org_id || !m.org_ids.includes(subject.org_id)))
|
|
22
|
+
continue;
|
|
23
|
+
if (m.plans && (!subject.plan || !m.plans.includes(subject.plan)))
|
|
24
|
+
continue;
|
|
25
|
+
if (rule.percentage !== undefined && (!seed || bucket(flag.key, seed) >= rule.percentage))
|
|
26
|
+
continue;
|
|
27
|
+
return rule.value;
|
|
28
|
+
}
|
|
29
|
+
return flag.default_value;
|
|
30
|
+
}
|
|
31
|
+
const pageAll = async (request) => {
|
|
32
|
+
const out = [];
|
|
33
|
+
let after;
|
|
34
|
+
for (;;) {
|
|
35
|
+
const page = await request({
|
|
36
|
+
method: 'GET',
|
|
37
|
+
path: '/v1/feature_flags',
|
|
38
|
+
query: { limit: 200, starting_after: after },
|
|
39
|
+
});
|
|
40
|
+
out.push(...page.data);
|
|
41
|
+
if (!page.has_more || page.data.length === 0)
|
|
42
|
+
return out;
|
|
43
|
+
after = page.data[page.data.length - 1].key;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
function flagsResource(request, cacheTtlMs = 30_000) {
|
|
47
|
+
let cache;
|
|
48
|
+
let inflight;
|
|
49
|
+
/** All flag definitions, cached for `cacheTtlMs`; concurrent callers share one fetch. */
|
|
50
|
+
const definitions = async () => {
|
|
51
|
+
if (cache && Date.now() - cache.at < cacheTtlMs)
|
|
52
|
+
return cache.flags;
|
|
53
|
+
inflight ??= pageAll(request)
|
|
54
|
+
.then((all) => {
|
|
55
|
+
cache = { at: Date.now(), flags: new Map(all.map((f) => [f.key, f])) };
|
|
56
|
+
return cache.flags;
|
|
57
|
+
})
|
|
58
|
+
.finally(() => { inflight = undefined; });
|
|
59
|
+
return inflight;
|
|
60
|
+
};
|
|
61
|
+
return {
|
|
62
|
+
create(body, idempotencyKey) {
|
|
63
|
+
return request({ method: 'POST', path: '/v1/feature_flags', body, idempotencyKey });
|
|
64
|
+
},
|
|
65
|
+
/** `starting_after` is the key of the last flag of the previous page. */
|
|
66
|
+
list(params = {}) {
|
|
67
|
+
return request({ method: 'GET', path: '/v1/feature_flags', query: params });
|
|
68
|
+
},
|
|
69
|
+
retrieve(key) {
|
|
70
|
+
return request({ method: 'GET', path: `/v1/feature_flags/${(0, request_1.enc)(key)}` });
|
|
71
|
+
},
|
|
72
|
+
update(key, body) {
|
|
73
|
+
return request({ method: 'PATCH', path: `/v1/feature_flags/${(0, request_1.enc)(key)}`, body });
|
|
74
|
+
},
|
|
75
|
+
delete(key) {
|
|
76
|
+
return request({ method: 'DELETE', path: `/v1/feature_flags/${(0, request_1.enc)(key)}` });
|
|
77
|
+
},
|
|
78
|
+
/** Server-side evaluation; `plan` defaults to the org's (else the user's) resolved plan. */
|
|
79
|
+
evaluate(body) {
|
|
80
|
+
return request({ method: 'POST', path: '/v1/feature_flags/evaluate', body });
|
|
81
|
+
},
|
|
82
|
+
/** Local evaluation against cached definitions. `plan` is not looked up here — pass it for plan rules. */
|
|
83
|
+
async get(key, subject, fallback) {
|
|
84
|
+
const flag = (await definitions()).get(key);
|
|
85
|
+
return flag ? evaluateFeatureFlag(flag, subject) : fallback;
|
|
86
|
+
},
|
|
87
|
+
/** True only for a boolean flag that evaluates to true; an unknown flag is false. */
|
|
88
|
+
async isEnabled(key, subject = {}) {
|
|
89
|
+
return (await this.get(key, subject, false)) === true;
|
|
90
|
+
},
|
|
91
|
+
/** Drop the cached definitions (e.g. after changing a flag). */
|
|
92
|
+
invalidate() {
|
|
93
|
+
cache = undefined;
|
|
94
|
+
},
|
|
95
|
+
/** Replace the entitlements assigned to an organization (an empty body clears them). */
|
|
96
|
+
assignOrganizationEntitlements(orgId, body) {
|
|
97
|
+
return request({ method: 'PUT', path: `/v1/organizations/${(0, request_1.enc)(orgId)}/entitlements`, body });
|
|
98
|
+
},
|
|
99
|
+
assignUserEntitlements(userId, body) {
|
|
100
|
+
return request({ method: 'PUT', path: `/v1/users/${(0, request_1.enc)(userId)}/entitlements`, body });
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=flags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flags.js","sourceRoot":"","sources":["../../src/client/flags.ts"],"names":[],"mappings":";;AAgFA,kDAYC;AAiBD,sCA0DC;AAvKD,iDAA8C;AAC9C,uCAAgD;AAwEhD,0FAA0F;AAC1F,SAAS,MAAM,CAAC,OAAe,EAAE,UAAkB;IACjD,MAAM,CAAC,GAAG,IAAA,eAAM,EAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,OAAO,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC;IACvE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC;AAC9E,CAAC;AAED,uGAAuG;AACvG,SAAgB,mBAAmB,CAAC,IAAiB,EAAE,OAA2B;IAChF,IAAI,CAAC,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC;IACzC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;IACrD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QAC3B,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAAE,SAAS;QACxF,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAAE,SAAS;QACpF,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAAE,SAAS;QAC5E,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC;YAAE,SAAS;QACpG,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IACD,OAAO,IAAI,CAAC,aAAa,CAAC;AAC5B,CAAC;AAED,MAAM,OAAO,GAAG,KAAK,EAAE,OAAkB,EAA0B,EAAE;IACnE,MAAM,GAAG,GAAkB,EAAE,CAAC;IAC9B,IAAI,KAAyB,CAAC;IAC9B,SAAS,CAAC;QACR,MAAM,IAAI,GAAG,MAAM,OAAO,CAA6C;YACrE,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,mBAAmB;YACzB,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE;SAC7C,CAAC,CAAC;QACH,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;QACvB,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,GAAG,CAAC;QACzD,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,GAAG,CAAC;IAC/C,CAAC;AACH,CAAC,CAAC;AAEF,SAAgB,aAAa,CAAC,OAAkB,EAAE,UAAU,GAAG,MAAM;IACnE,IAAI,KAAkE,CAAC;IACvE,IAAI,QAAuD,CAAC;IAE5D,yFAAyF;IACzF,MAAM,WAAW,GAAG,KAAK,IAAuC,EAAE;QAChE,IAAI,KAAK,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,EAAE,GAAG,UAAU;YAAE,OAAO,KAAK,CAAC,KAAK,CAAC;QACpE,QAAQ,KAAK,OAAO,CAAC,OAAO,CAAC;aAC1B,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;YACZ,KAAK,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACvE,OAAO,KAAK,CAAC,KAAK,CAAC;QACrB,CAAC,CAAC;aACD,OAAO,CAAC,GAAG,EAAE,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5C,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO;QACL,MAAM,CAAC,IAA2B,EAAE,cAAuB;YACzD,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;QACtF,CAAC;QACD,yEAAyE;QACzE,IAAI,CAAC,SAAuB,EAAE;YAC5B,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAqD,EAAE,CAAC,CAAC;QAC7H,CAAC;QACD,QAAQ,CAAC,GAAW;YAClB,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,qBAAqB,IAAA,aAAG,EAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QAC3E,CAAC;QACD,MAAM,CAAC,GAAW,EAAE,IAA2B;YAC7C,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,qBAAqB,IAAA,aAAG,EAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QACnF,CAAC;QACD,MAAM,CAAC,GAAW;YAChB,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,qBAAqB,IAAA,aAAG,EAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QAC9E,CAAC;QACD,4FAA4F;QAC5F,QAAQ,CAAC,IAA8C;YACrD,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,4BAA4B,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/E,CAAC;QACD,0GAA0G;QAC1G,KAAK,CAAC,GAAG,CAA6B,GAAW,EAAE,OAA2B,EAAE,QAAW;YACzF,MAAM,IAAI,GAAG,CAAC,MAAM,WAAW,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5C,OAAO,IAAI,CAAC,CAAC,CAAE,mBAAmB,CAAC,IAAI,EAAE,OAAO,CAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;QACrE,CAAC;QACD,qFAAqF;QACrF,KAAK,CAAC,SAAS,CAAC,GAAW,EAAE,UAA8B,EAAE;YAC3D,OAAO,CAAC,MAAM,IAAI,CAAC,GAAG,CAAmB,GAAG,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,KAAK,IAAI,CAAC;QAC1E,CAAC;QACD,gEAAgE;QAChE,UAAU;YACR,KAAK,GAAG,SAAS,CAAC;QACpB,CAAC;QACD,wFAAwF;QACxF,8BAA8B,CAAC,KAAa,EAAE,IAA4B;YACxE,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,qBAAqB,IAAA,aAAG,EAAC,KAAK,CAAC,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;QAChG,CAAC;QACD,sBAAsB,CAAC,MAAc,EAAE,IAA4B;YACjE,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,IAAA,aAAG,EAAC,MAAM,CAAC,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;QACzF,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { type RequestFn } from './request';
|
|
2
|
+
import type { ListPage } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Instance-level groups (independent of organizations) and the rules engine.
|
|
5
|
+
* Groups nest, carry attributes, map to app roles, can ride the session token as
|
|
6
|
+
* `groups`, and fill by hand, by filter, from SSO claims or by rules.
|
|
7
|
+
*/
|
|
8
|
+
export interface Group {
|
|
9
|
+
object: 'group';
|
|
10
|
+
id: string;
|
|
11
|
+
slug: string;
|
|
12
|
+
name: string;
|
|
13
|
+
description: string | null;
|
|
14
|
+
parent_id: string | null;
|
|
15
|
+
attributes: Record<string, unknown>;
|
|
16
|
+
app_role_keys: string[];
|
|
17
|
+
include_in_token: boolean;
|
|
18
|
+
dynamic_filter: Record<string, unknown> | null;
|
|
19
|
+
sso_match: {
|
|
20
|
+
claim: string;
|
|
21
|
+
equals?: string;
|
|
22
|
+
contains?: string;
|
|
23
|
+
matches?: string;
|
|
24
|
+
} | null;
|
|
25
|
+
member_count?: number;
|
|
26
|
+
/** `users.groups` only: how the user joined. */
|
|
27
|
+
source?: 'manual' | 'dynamic' | 'sso' | 'rule';
|
|
28
|
+
created_at: number;
|
|
29
|
+
updated_at: number;
|
|
30
|
+
}
|
|
31
|
+
export interface GroupBody {
|
|
32
|
+
slug?: string;
|
|
33
|
+
name?: string;
|
|
34
|
+
description?: string | null;
|
|
35
|
+
parent_id?: string | null;
|
|
36
|
+
attributes?: Record<string, unknown>;
|
|
37
|
+
app_role_keys?: string[];
|
|
38
|
+
include_in_token?: boolean;
|
|
39
|
+
/** A user-search filter tree. */
|
|
40
|
+
dynamic_filter?: Record<string, unknown> | null;
|
|
41
|
+
sso_match?: Group['sso_match'];
|
|
42
|
+
}
|
|
43
|
+
export interface GroupMember {
|
|
44
|
+
object: 'group_member';
|
|
45
|
+
group_id: string;
|
|
46
|
+
user_id: string;
|
|
47
|
+
source: 'manual' | 'dynamic' | 'sso' | 'rule';
|
|
48
|
+
source_ref: string | null;
|
|
49
|
+
created_at: number;
|
|
50
|
+
}
|
|
51
|
+
export type GroupRuleAction = {
|
|
52
|
+
type: 'add_to_group';
|
|
53
|
+
group: string;
|
|
54
|
+
} | {
|
|
55
|
+
type: 'add_app_role';
|
|
56
|
+
role: string;
|
|
57
|
+
} | {
|
|
58
|
+
type: 'set_trait';
|
|
59
|
+
key: string;
|
|
60
|
+
value: unknown;
|
|
61
|
+
};
|
|
62
|
+
export interface GroupRule {
|
|
63
|
+
object: 'group_rule';
|
|
64
|
+
id: string;
|
|
65
|
+
name: string;
|
|
66
|
+
enabled: boolean;
|
|
67
|
+
priority: number;
|
|
68
|
+
condition: Record<string, unknown>;
|
|
69
|
+
actions: GroupRuleAction[];
|
|
70
|
+
created_by: string | null;
|
|
71
|
+
created_at: number;
|
|
72
|
+
updated_at: number;
|
|
73
|
+
}
|
|
74
|
+
export interface GroupRuleBody {
|
|
75
|
+
name?: string;
|
|
76
|
+
enabled?: boolean;
|
|
77
|
+
priority?: number;
|
|
78
|
+
condition?: Record<string, unknown>;
|
|
79
|
+
actions?: GroupRuleAction[];
|
|
80
|
+
}
|
|
81
|
+
export interface GroupRuleResult {
|
|
82
|
+
object: 'group_rule_result';
|
|
83
|
+
rule_id: string;
|
|
84
|
+
matched: number;
|
|
85
|
+
groups_added: number;
|
|
86
|
+
groups_removed: number;
|
|
87
|
+
roles_granted: number;
|
|
88
|
+
traits_set: number;
|
|
89
|
+
}
|
|
90
|
+
export declare function groupsResource(request: RequestFn): {
|
|
91
|
+
list(): Promise<ListPage<Group>>;
|
|
92
|
+
get(idOrSlug: string): Promise<Group>;
|
|
93
|
+
create(body: GroupBody & {
|
|
94
|
+
slug: string;
|
|
95
|
+
name: string;
|
|
96
|
+
}, idempotencyKey?: string): Promise<Group>;
|
|
97
|
+
update(idOrSlug: string, body: GroupBody): Promise<Group>;
|
|
98
|
+
delete(idOrSlug: string): Promise<{
|
|
99
|
+
object: "group";
|
|
100
|
+
id: string;
|
|
101
|
+
deleted: true;
|
|
102
|
+
}>;
|
|
103
|
+
listMembers(idOrSlug: string, query?: {
|
|
104
|
+
limit?: number;
|
|
105
|
+
starting_after?: string;
|
|
106
|
+
}): Promise<ListPage<GroupMember> & {
|
|
107
|
+
next_cursor: string | null;
|
|
108
|
+
}>;
|
|
109
|
+
/** Add up to 500 users by hand. */
|
|
110
|
+
addMembers(idOrSlug: string, userIds: string[]): Promise<{
|
|
111
|
+
added: number;
|
|
112
|
+
promoted: number;
|
|
113
|
+
already_member: number;
|
|
114
|
+
skipped: number;
|
|
115
|
+
}>;
|
|
116
|
+
removeMembers(idOrSlug: string, userIds: string[]): Promise<{
|
|
117
|
+
removed: number;
|
|
118
|
+
}>;
|
|
119
|
+
/** Re-evaluate a dynamic group's filter now. */
|
|
120
|
+
reapply(idOrSlug: string): Promise<{
|
|
121
|
+
matched: number;
|
|
122
|
+
added: number;
|
|
123
|
+
removed: number;
|
|
124
|
+
}>;
|
|
125
|
+
/** A user's direct groups. */
|
|
126
|
+
forUser(userId: string): Promise<ListPage<Group>>;
|
|
127
|
+
rules: {
|
|
128
|
+
list(): Promise<ListPage<GroupRule>>;
|
|
129
|
+
get(id: string): Promise<GroupRule>;
|
|
130
|
+
create(body: GroupRuleBody & {
|
|
131
|
+
name: string;
|
|
132
|
+
condition: Record<string, unknown>;
|
|
133
|
+
actions: GroupRuleAction[];
|
|
134
|
+
}, idempotencyKey?: string): Promise<GroupRule>;
|
|
135
|
+
update(id: string, body: GroupRuleBody): Promise<GroupRule>;
|
|
136
|
+
delete(id: string): Promise<{
|
|
137
|
+
object: "group_rule";
|
|
138
|
+
id: string;
|
|
139
|
+
deleted: true;
|
|
140
|
+
}>;
|
|
141
|
+
/** Run one rule now. */
|
|
142
|
+
apply(id: string): Promise<GroupRuleResult>;
|
|
143
|
+
/** Run every enabled rule in priority order. */
|
|
144
|
+
applyAll(): Promise<ListPage<GroupRuleResult>>;
|
|
145
|
+
};
|
|
146
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.groupsResource = groupsResource;
|
|
4
|
+
const request_1 = require("./request");
|
|
5
|
+
function groupsResource(request) {
|
|
6
|
+
return {
|
|
7
|
+
list() {
|
|
8
|
+
return request({ method: 'GET', path: '/v1/groups' });
|
|
9
|
+
},
|
|
10
|
+
get(idOrSlug) {
|
|
11
|
+
return request({ method: 'GET', path: `/v1/groups/${(0, request_1.enc)(idOrSlug)}` });
|
|
12
|
+
},
|
|
13
|
+
create(body, idempotencyKey) {
|
|
14
|
+
return request({ method: 'POST', path: '/v1/groups', body, idempotencyKey });
|
|
15
|
+
},
|
|
16
|
+
update(idOrSlug, body) {
|
|
17
|
+
return request({ method: 'PATCH', path: `/v1/groups/${(0, request_1.enc)(idOrSlug)}`, body });
|
|
18
|
+
},
|
|
19
|
+
delete(idOrSlug) {
|
|
20
|
+
return request({ method: 'DELETE', path: `/v1/groups/${(0, request_1.enc)(idOrSlug)}` });
|
|
21
|
+
},
|
|
22
|
+
listMembers(idOrSlug, query = {}) {
|
|
23
|
+
return request({ method: 'GET', path: `/v1/groups/${(0, request_1.enc)(idOrSlug)}/members`, query });
|
|
24
|
+
},
|
|
25
|
+
/** Add up to 500 users by hand. */
|
|
26
|
+
addMembers(idOrSlug, userIds) {
|
|
27
|
+
return request({ method: 'POST', path: `/v1/groups/${(0, request_1.enc)(idOrSlug)}/members`, body: { user_ids: userIds } });
|
|
28
|
+
},
|
|
29
|
+
removeMembers(idOrSlug, userIds) {
|
|
30
|
+
return request({ method: 'POST', path: `/v1/groups/${(0, request_1.enc)(idOrSlug)}/members/remove`, body: { user_ids: userIds } });
|
|
31
|
+
},
|
|
32
|
+
/** Re-evaluate a dynamic group's filter now. */
|
|
33
|
+
reapply(idOrSlug) {
|
|
34
|
+
return request({ method: 'POST', path: `/v1/groups/${(0, request_1.enc)(idOrSlug)}/reapply` });
|
|
35
|
+
},
|
|
36
|
+
/** A user's direct groups. */
|
|
37
|
+
forUser(userId) {
|
|
38
|
+
return request({ method: 'GET', path: `/v1/users/${(0, request_1.enc)(userId)}/groups` });
|
|
39
|
+
},
|
|
40
|
+
rules: {
|
|
41
|
+
list() {
|
|
42
|
+
return request({ method: 'GET', path: '/v1/group_rules' });
|
|
43
|
+
},
|
|
44
|
+
get(id) {
|
|
45
|
+
return request({ method: 'GET', path: `/v1/group_rules/${(0, request_1.enc)(id)}` });
|
|
46
|
+
},
|
|
47
|
+
create(body, idempotencyKey) {
|
|
48
|
+
return request({ method: 'POST', path: '/v1/group_rules', body, idempotencyKey });
|
|
49
|
+
},
|
|
50
|
+
update(id, body) {
|
|
51
|
+
return request({ method: 'PATCH', path: `/v1/group_rules/${(0, request_1.enc)(id)}`, body });
|
|
52
|
+
},
|
|
53
|
+
delete(id) {
|
|
54
|
+
return request({ method: 'DELETE', path: `/v1/group_rules/${(0, request_1.enc)(id)}` });
|
|
55
|
+
},
|
|
56
|
+
/** Run one rule now. */
|
|
57
|
+
apply(id) {
|
|
58
|
+
return request({ method: 'POST', path: `/v1/group_rules/${(0, request_1.enc)(id)}/apply` });
|
|
59
|
+
},
|
|
60
|
+
/** Run every enabled rule in priority order. */
|
|
61
|
+
applyAll() {
|
|
62
|
+
return request({ method: 'POST', path: '/v1/group_rules/apply' });
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=groups.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"groups.js","sourceRoot":"","sources":["../../src/client/groups.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type RequestFn } from './request';
|
|
2
|
+
export type IdentityVerificationOutcome = 'pending' | 'approved' | 'declined' | 'needs_review';
|
|
3
|
+
export interface IdentityVerification {
|
|
4
|
+
object: 'identity_verification';
|
|
5
|
+
id: string;
|
|
6
|
+
user_id: string;
|
|
7
|
+
provider: 'persona' | 'onfido' | 'veriff' | 'stripe_identity';
|
|
8
|
+
status: IdentityVerificationOutcome;
|
|
9
|
+
reason: string | null;
|
|
10
|
+
/** The verification service's hosted page, while pending. */
|
|
11
|
+
url: string | null;
|
|
12
|
+
decided_by: string | null;
|
|
13
|
+
created_at: number;
|
|
14
|
+
completed_at: number | null;
|
|
15
|
+
}
|
|
16
|
+
export interface IdentityVerificationSettings {
|
|
17
|
+
object: 'identity_verification_settings';
|
|
18
|
+
enabled: boolean;
|
|
19
|
+
/** The service connector (Persona, Onfido, Veriff or Stripe Identity) that does the checking. */
|
|
20
|
+
connector_id: string | null;
|
|
21
|
+
/** Offer a verified identity as the custom second step of sign-in. */
|
|
22
|
+
as_challenge: boolean;
|
|
23
|
+
/** Give this URL to the verification service for verdict webhooks; store its webhook secret on the connector as `webhook_secret`. */
|
|
24
|
+
webhook_url: string | null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Identity verification (document and selfie) through your own verification
|
|
28
|
+
* service. An approved check is written to the user as
|
|
29
|
+
* `public_metadata.verification.identity` (`{ status, provider, verified_at }`).
|
|
30
|
+
*/
|
|
31
|
+
export declare function identityVerificationResource(request: RequestFn): {
|
|
32
|
+
settings(): Promise<IdentityVerificationSettings>;
|
|
33
|
+
updateSettings(body: {
|
|
34
|
+
enabled: boolean;
|
|
35
|
+
connector_id?: string | null;
|
|
36
|
+
as_challenge?: boolean;
|
|
37
|
+
}): Promise<IdentityVerificationSettings>;
|
|
38
|
+
/** Checks by status, newest first. Defaults to `needs_review`, the review queue. */
|
|
39
|
+
list(params?: {
|
|
40
|
+
status?: IdentityVerificationOutcome;
|
|
41
|
+
}): Promise<{
|
|
42
|
+
object: "list";
|
|
43
|
+
data: IdentityVerification[];
|
|
44
|
+
has_more: boolean;
|
|
45
|
+
}>;
|
|
46
|
+
/** One check; a pending one is refreshed from the verification service. */
|
|
47
|
+
get(id: string): Promise<IdentityVerification>;
|
|
48
|
+
/** Approve or decline a check that is waiting for review. */
|
|
49
|
+
decide(id: string, body: {
|
|
50
|
+
decision: "approved" | "declined";
|
|
51
|
+
reason?: string;
|
|
52
|
+
}): Promise<IdentityVerification>;
|
|
53
|
+
forUser(userId: string): Promise<{
|
|
54
|
+
object: "list";
|
|
55
|
+
data: IdentityVerification[];
|
|
56
|
+
has_more: boolean;
|
|
57
|
+
}>;
|
|
58
|
+
/** Start a check for a user; send them to the returned `url`. */
|
|
59
|
+
start(userId: string, body?: {
|
|
60
|
+
redirect_url?: string;
|
|
61
|
+
}): Promise<IdentityVerification>;
|
|
62
|
+
};
|