authhero 9.10.0 → 9.11.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.
Files changed (31) hide show
  1. package/dist/assets/u/widget/index.esm.js +1 -1
  2. package/dist/authhero.cjs +146 -146
  3. package/dist/authhero.d.ts +341 -119
  4. package/dist/authhero.mjs +15107 -14199
  5. package/dist/tsconfig.types.tsbuildinfo +1 -1
  6. package/dist/types/helpers/dcr/metadata-mapping.d.ts +1 -1
  7. package/dist/types/helpers/reserved-claims.d.ts +2 -2
  8. package/dist/types/helpers/run-retention.d.ts +5 -0
  9. package/dist/types/helpers/users-import/map.d.ts +128 -0
  10. package/dist/types/helpers/users-import/process.d.ts +95 -0
  11. package/dist/types/helpers/users-import-cleanup.d.ts +26 -0
  12. package/dist/types/index.d.ts +238 -115
  13. package/dist/types/routes/management-api/authentication-methods.d.ts +1 -1
  14. package/dist/types/routes/management-api/branding.d.ts +9 -9
  15. package/dist/types/routes/management-api/client-grants.d.ts +9 -9
  16. package/dist/types/routes/management-api/failed-events.d.ts +2 -2
  17. package/dist/types/routes/management-api/helpers.d.ts +1 -1
  18. package/dist/types/routes/management-api/index.d.ts +194 -75
  19. package/dist/types/routes/management-api/jobs.d.ts +133 -0
  20. package/dist/types/routes/management-api/logs.d.ts +4 -4
  21. package/dist/types/routes/management-api/organizations.d.ts +1 -1
  22. package/dist/types/routes/management-api/prompts.d.ts +4 -4
  23. package/dist/types/routes/management-api/tenant-export-import.d.ts +5 -5
  24. package/dist/types/routes/management-api/tenant-operations.d.ts +33 -9
  25. package/dist/types/routes/management-api/users.d.ts +2 -2
  26. package/dist/types/routes/universal-login/flow-api.d.ts +4 -4
  27. package/dist/types/state-machines/login-session.d.ts +1 -1
  28. package/dist/types/types/AuthHeroConfig.d.ts +13 -0
  29. package/dist/types/types/Bindings.d.ts +2 -0
  30. package/dist/types/types/auth0/UserImport.d.ts +317 -0
  31. package/package.json +6 -6
@@ -23,9 +23,9 @@ export declare const dcrRequestSchema: z.ZodObject<{
23
23
  grant_types: z.ZodOptional<z.ZodArray<z.ZodString>>;
24
24
  response_types: z.ZodOptional<z.ZodArray<z.ZodString>>;
25
25
  token_endpoint_auth_method: z.ZodOptional<z.ZodEnum<{
26
- none: "none";
27
26
  client_secret_post: "client_secret_post";
28
27
  client_secret_basic: "client_secret_basic";
28
+ none: "none";
29
29
  client_secret_jwt: "client_secret_jwt";
30
30
  private_key_jwt: "private_key_jwt";
31
31
  }>>;
@@ -15,9 +15,9 @@ export declare const USERINFO_RESERVED_CLAIMS: readonly ["iss", "sub", "aud", "e
15
15
  * vendor/tenant for downstream APIs while `sub` stays `auth-service`.
16
16
  * Client-bound mints keep `azp` locked (see below).
17
17
  */
18
- export declare const SERVICE_TOKEN_RESERVED_CLAIMS: ("client_id" | "scope" | "sid" | "tenant_id" | "org_id" | "org_name" | "sub" | "permissions" | "iat" | "exp" | "iss" | "aud" | "auth_time" | "acr" | "amr" | "nbf" | "jti" | "act" | "requested_userinfo_claims" | "gty")[];
18
+ export declare const SERVICE_TOKEN_RESERVED_CLAIMS: ("client_id" | "scope" | "sid" | "tenant_id" | "sub" | "org_name" | "permissions" | "iat" | "org_id" | "exp" | "iss" | "aud" | "auth_time" | "acr" | "amr" | "nbf" | "jti" | "act" | "requested_userinfo_claims" | "gty")[];
19
19
  /** Client-bound mints: `azp` must stay the registered client id. */
20
- export declare const CLIENT_SERVICE_TOKEN_RESERVED_CLAIMS: ("client_id" | "scope" | "sid" | "tenant_id" | "org_id" | "org_name" | "sub" | "permissions" | "iat" | "exp" | "iss" | "aud" | "auth_time" | "acr" | "amr" | "azp" | "nbf" | "jti" | "act" | "requested_userinfo_claims" | "gty")[];
20
+ export declare const CLIENT_SERVICE_TOKEN_RESERVED_CLAIMS: ("client_id" | "scope" | "sid" | "tenant_id" | "sub" | "org_name" | "permissions" | "iat" | "org_id" | "exp" | "iss" | "aud" | "auth_time" | "acr" | "amr" | "azp" | "nbf" | "jti" | "act" | "requested_userinfo_claims" | "gty")[];
21
21
  export type AccessTokenReservedClaim = (typeof ACCESS_TOKEN_RESERVED_CLAIMS)[number];
22
22
  export type IdTokenReservedClaim = (typeof ID_TOKEN_RESERVED_CLAIMS)[number];
23
23
  /**
@@ -8,6 +8,11 @@ export interface RunRetentionConfig {
8
8
  outboxRetentionDays?: number;
9
9
  /** Days of action execution history to keep. Default 30. */
10
10
  actionExecutionsRetentionDays?: number;
11
+ /**
12
+ * Hours to keep finished bulk user-import jobs and their staged rows.
13
+ * Default 24, matching Auth0's job-data retention.
14
+ */
15
+ usersImportRetentionHours?: number;
11
16
  /**
12
17
  * Scope the session sweep to a single tenant. Codes and outbox events are
13
18
  * always swept globally — an expired row is dead regardless of who owns it.
@@ -0,0 +1,128 @@
1
+ import type { PasswordInsert, UserInsert } from "@authhero/adapter-interfaces";
2
+ import { type UserImportEntry } from "../../types/auth0/UserImport";
3
+ /**
4
+ * Machine-readable per-row failure reasons, surfaced by the Auth0-compatible
5
+ * `GET /api/v2/jobs/{id}/errors` endpoint. Stable strings — clients branch on
6
+ * them, so treat these as API surface.
7
+ */
8
+ export declare const IMPORT_ERROR_CODES: {
9
+ /** The entry did not match the import-file schema. */
10
+ readonly VALIDATION_ERROR: "VALIDATION_ERROR";
11
+ /** A well-formed hash in an algorithm AuthHero cannot verify. */
12
+ readonly UNSUPPORTED_HASH_ALGORITHM: "UNSUPPORTED_HASH_ALGORITHM";
13
+ /** bcrypt, but a variant or encoding that would never verify. */
14
+ readonly UNSUPPORTED_HASH_FORMAT: "UNSUPPORTED_HASH_FORMAT";
15
+ /** The same identity appears earlier in the same file. */
16
+ readonly DUPLICATE_ENTRY: "DUPLICATE_ENTRY";
17
+ /** The user already exists and `upsert` was not enabled. */
18
+ readonly USER_ALREADY_EXISTS: "USER_ALREADY_EXISTS";
19
+ /** The write itself failed. */
20
+ readonly INTERNAL_ERROR: "INTERNAL_ERROR";
21
+ };
22
+ export type ImportErrorCode = (typeof IMPORT_ERROR_CODES)[keyof typeof IMPORT_ERROR_CODES];
23
+ export interface ImportRowError {
24
+ code: ImportErrorCode;
25
+ message: string;
26
+ path?: string;
27
+ }
28
+ export type MappedPassword = Pick<PasswordInsert, "password" | "algorithm">;
29
+ export interface MappedEntry {
30
+ user: Omit<UserInsert, "connection"> & {
31
+ connection: string;
32
+ };
33
+ password?: MappedPassword;
34
+ }
35
+ export type MapResult = {
36
+ ok: true;
37
+ value: MappedEntry;
38
+ } | {
39
+ ok: false;
40
+ error: ImportRowError;
41
+ };
42
+ /**
43
+ * Resolve the entry's password into something AuthHero can actually verify.
44
+ *
45
+ * Returns `undefined` when the entry carries no credential at all — a valid
46
+ * case that produces a shell user who signs in via password reset or the
47
+ * upstream `import_mode` fallback.
48
+ *
49
+ * AuthHero verifies with `bcryptjs.compare`, so bcrypt is the only algorithm
50
+ * that can round-trip. Storing anything else would create a user who can
51
+ * never authenticate, so unsupported hashes fail the row instead.
52
+ */
53
+ export declare function mapPassword(entry: UserImportEntry): {
54
+ ok: true;
55
+ value?: MappedPassword;
56
+ } | {
57
+ ok: false;
58
+ error: ImportRowError;
59
+ };
60
+ /**
61
+ * Build the stored `provider|id` identifier for an imported entry.
62
+ *
63
+ * Auth0 prefixes bare import ids with the connection's provider; AuthHero
64
+ * uses the tenant's resolved username-password provider (`auth0`, or `auth2`
65
+ * for tenants still pinned to the legacy value) so the password row lands on
66
+ * the identity the login path actually reads. An entry that already carries
67
+ * the prefix is not double-prefixed, and one with no id at all gets a
68
+ * generated one — the users table requires the column.
69
+ *
70
+ * Mirrors `POST /api/v2/users`, which derives the id exactly this way.
71
+ */
72
+ export declare function buildUserId(userId: string | undefined, provider: string, fallbackId?: string): string;
73
+ /**
74
+ * Deterministic bare id for an import row that supplied no `user_id`.
75
+ *
76
+ * Retry safety depends on this. A driver can create a user and then die
77
+ * before committing that row's outcome, leaving the row `pending`; the next
78
+ * driver reprocesses it. With a random id the retry cannot tell its own
79
+ * half-finished write from a genuinely pre-existing user, and reports a
80
+ * successful import as `USER_ALREADY_EXISTS`. Deriving the id from
81
+ * `(operation_id, seq)` — both immutable for the life of the row — makes the
82
+ * retry regenerate the exact same id, so it can recognise its own work.
83
+ *
84
+ * Not a security boundary: the inputs are our own identifiers, so this only
85
+ * needs to be stable and collision-free, which a truncated SHA-256 is.
86
+ */
87
+ export declare function deriveImportUserId(operationId: string, seq: number): Promise<string>;
88
+ export interface MapEntryParams {
89
+ entry: UserImportEntry;
90
+ /** Connection NAME (the users table stores the name, not the id). */
91
+ connection: string;
92
+ /** Resolved username-password provider for this tenant. */
93
+ provider: string;
94
+ /**
95
+ * Id to use when the entry supplies none. Pass the value from
96
+ * {@link deriveImportUserId} so a reprocessed row rebuilds the same id;
97
+ * omitting it falls back to a random one.
98
+ */
99
+ fallbackUserId?: string;
100
+ }
101
+ /**
102
+ * Map one validated import entry onto the user and password rows to write.
103
+ * Pure — performs no I/O and makes no existence checks, so it is safe to call
104
+ * repeatedly when a chunk is retried.
105
+ */
106
+ export declare function mapEntry({ entry, connection, provider, fallbackUserId, }: MapEntryParams): MapResult;
107
+ /**
108
+ * Strip credential material from a staged entry before it is returned by
109
+ * `GET /jobs/{id}/errors`.
110
+ *
111
+ * Redaction happens on the way OUT, not on the way in: the staged row is the
112
+ * work item, so it must keep the hash the job exists to import. What must
113
+ * never happen is echoing that hash back over the API, which is what this
114
+ * guards. The marker is left in place so an operator reading an error can
115
+ * still tell a credential was supplied.
116
+ */
117
+ export declare function redactEntry(entry: unknown): Record<string, unknown>;
118
+ /**
119
+ * Normalize a raw file entry into the record shape a staged row stores,
120
+ * WITHOUT redacting: the row has to carry the credential it is going to
121
+ * import. {@link redactEntry} is applied when the row is read back out.
122
+ */
123
+ export declare function toStagedPayload(entry: unknown): Record<string, unknown>;
124
+ /**
125
+ * Identity keys Auth0 dedupes an import file on: a repeat of any of these
126
+ * within one file is an error rather than a silent overwrite.
127
+ */
128
+ export declare function entryIdentityKeys(entry: UserImportEntry): string[];
@@ -0,0 +1,95 @@
1
+ import type { DataAdapters, TenantOperation } from "@authhero/adapter-interfaces";
2
+ /**
3
+ * How many staged rows one chunk processes.
4
+ *
5
+ * Sized against Cloudflare D1's per-invocation query cap (order of a
6
+ * thousand): a row costs up to four existence probes plus a user and a
7
+ * password write, so 50 rows leaves comfortable headroom for the
8
+ * surrounding reads and the outcome commit. Chunks are cheap — a smaller
9
+ * one only means more of them, while an oversized one fails the whole
10
+ * invocation.
11
+ */
12
+ export declare const DEFAULT_CHUNK_SIZE = 50;
13
+ /** How long a driver's lease on an operation is valid. */
14
+ export declare const DEFAULT_LEASE_MS = 60000;
15
+ export interface UsersImportInput {
16
+ connection_id: string;
17
+ connection: string;
18
+ upsert: boolean;
19
+ external_id?: string;
20
+ send_completion_email?: boolean;
21
+ provider: string;
22
+ }
23
+ export interface AdvanceOptions {
24
+ /** Stop after this many rows, so a driver can bound its own runtime. */
25
+ maxRows?: number;
26
+ /** Rows per chunk; defaults to {@link DEFAULT_CHUNK_SIZE}. */
27
+ chunkSize?: number;
28
+ /** Lease duration for this driver's claim. */
29
+ leaseMs?: number;
30
+ /**
31
+ * Wall-clock deadline (epoch ms). The driver stops cleanly at the next
32
+ * chunk boundary once passed, leaving the remainder `pending` for the
33
+ * next driver — never mid-chunk, so no work is half-committed.
34
+ */
35
+ deadline?: number;
36
+ /** Identifies the lease holder; defaults to a random id. */
37
+ workerId?: string;
38
+ }
39
+ export interface AdvanceResult {
40
+ /** True when no `pending` rows remain and the operation was finalized. */
41
+ done: boolean;
42
+ /** Rows this call committed an outcome for. */
43
+ processed: number;
44
+ /** Rows still `pending` after this call. */
45
+ remaining: number;
46
+ /** False when another live driver holds the lease. */
47
+ claimed: boolean;
48
+ }
49
+ /**
50
+ * Read the operation's `input` back into a typed shape. The row is written
51
+ * by the accept route, so a malformed one means the operation is
52
+ * unrunnable rather than that the caller made a mistake.
53
+ */
54
+ export declare function parseImportInput(operation: TenantOperation): UsersImportInput | null;
55
+ /**
56
+ * Advance a `users_import` operation by processing staged rows until it is
57
+ * finished or the caller's budget runs out.
58
+ *
59
+ * This is the whole execution model. Every engine — an inline kick from the
60
+ * accepting request, a cron sweep, a Cloudflare Workflow step — calls this
61
+ * same function; they differ only in how much budget they pass and how often
62
+ * they call it. Durability comes from the database, not from the caller:
63
+ * outcomes are committed chunk by chunk, so a driver that dies loses at most
64
+ * the chunk in flight, and those rows stay `pending` for whoever runs next.
65
+ */
66
+ export declare function advanceUsersImport(data: DataAdapters, operationId: string, options?: AdvanceOptions): Promise<AdvanceResult>;
67
+ /** Auth0's job summary shape, derived from the staged-row counts. */
68
+ export declare function buildSummary(counts: {
69
+ total: number;
70
+ inserted: number;
71
+ updated: number;
72
+ failed: number;
73
+ }): Record<string, number>;
74
+ export interface ResumeUsersImportsOptions extends Omit<AdvanceOptions, "workerId"> {
75
+ /** Maximum operations to advance in one sweep. */
76
+ maxOperations?: number;
77
+ }
78
+ export interface ResumeUsersImportsResult {
79
+ scanned: number;
80
+ advanced: number;
81
+ completed: number;
82
+ errors: number;
83
+ }
84
+ /**
85
+ * Resume every unfinished bulk import that no live driver is working on.
86
+ *
87
+ * This is what makes the feature durable regardless of deployment. Wire it
88
+ * to a scheduled handler alongside `runRetention`: whatever started an
89
+ * import — a request that timed out, a worker that was evicted, a process
90
+ * that was redeployed mid-run — the sweep picks the job back up and carries
91
+ * it to completion from the last committed chunk.
92
+ *
93
+ * One operation's failure never aborts the sweep.
94
+ */
95
+ export declare function resumeUsersImports(data: DataAdapters, options?: ResumeUsersImportsOptions): Promise<ResumeUsersImportsResult>;
@@ -0,0 +1,26 @@
1
+ import { DataAdapters } from "@authhero/adapter-interfaces";
2
+ /**
3
+ * Auth0 deletes all job-related data 24 hours after the job is created.
4
+ */
5
+ export declare const DEFAULT_IMPORT_JOB_RETENTION_HOURS = 24;
6
+ export interface UsersImportCleanupParams {
7
+ /** Hours to keep finished import jobs. Defaults to Auth0's 24. */
8
+ retentionHours?: number;
9
+ /** Maximum jobs to delete per sweep. */
10
+ limit?: number;
11
+ }
12
+ /**
13
+ * Delete finished bulk-import jobs (and, by cascade, their staged rows)
14
+ * older than the retention window.
15
+ *
16
+ * Staged rows hold the submitted user entries, so this is a privacy control
17
+ * as much as a housekeeping one — though credential material is redacted
18
+ * before staging rather than relying on this sweep.
19
+ *
20
+ * Only terminal jobs are removed: an unfinished import may legitimately be
21
+ * older than the window (a very large file, or one that has been waiting on
22
+ * a resume sweep), and deleting it would strand the users it had not yet
23
+ * created. Returns the number of jobs deleted, or `null` when the
24
+ * deployment has no tenant-operations adapter.
25
+ */
26
+ export declare function cleanupUsersImports(data: DataAdapters, params?: UsersImportCleanupParams): Promise<number | null>;