@qlever-llc/trellis 0.10.18-rc.1 → 0.10.19

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 (120) hide show
  1. package/esm/auth/browser/login.d.ts +8 -7
  2. package/esm/auth/browser/login.d.ts.map +1 -1
  3. package/esm/auth/browser/logout.d.ts +23 -0
  4. package/esm/auth/browser/logout.d.ts.map +1 -0
  5. package/esm/auth/browser/logout.js +80 -0
  6. package/esm/auth/browser/portal.d.ts.map +1 -1
  7. package/esm/auth/browser/portal.js +2 -0
  8. package/esm/auth/browser/session.d.ts +2 -0
  9. package/esm/auth/browser/session.d.ts.map +1 -1
  10. package/esm/auth/browser/session.js +6 -0
  11. package/esm/auth/browser.d.ts +5 -2
  12. package/esm/auth/browser.d.ts.map +1 -1
  13. package/esm/auth/browser.js +4 -2
  14. package/esm/auth/browser_recovery.d.ts +22 -0
  15. package/esm/auth/browser_recovery.d.ts.map +1 -0
  16. package/esm/auth/browser_recovery.js +238 -0
  17. package/esm/auth/mod.d.ts +2 -2
  18. package/esm/auth/mod.d.ts.map +1 -1
  19. package/esm/auth/mod.js +2 -2
  20. package/esm/auth/protocol.d.ts +1 -0
  21. package/esm/auth/protocol.d.ts.map +1 -1
  22. package/esm/auth/protocol.js +1 -0
  23. package/esm/auth/schemas.d.ts +26 -0
  24. package/esm/auth/schemas.d.ts.map +1 -1
  25. package/esm/auth/schemas.js +35 -0
  26. package/esm/browser.d.ts +2 -2
  27. package/esm/browser.d.ts.map +1 -1
  28. package/esm/browser.js +1 -1
  29. package/esm/client_connect.js +1 -1
  30. package/esm/generated-sdk/auth/api.d.ts +1 -4
  31. package/esm/generated-sdk/auth/api.d.ts.map +1 -1
  32. package/esm/generated-sdk/auth/api.js +1 -6
  33. package/esm/generated-sdk/auth/client.d.ts +0 -15
  34. package/esm/generated-sdk/auth/client.d.ts.map +1 -1
  35. package/esm/generated-sdk/auth/contract.d.ts +1 -1
  36. package/esm/generated-sdk/auth/contract.d.ts.map +1 -1
  37. package/esm/generated-sdk/auth/contract.js +11 -3
  38. package/esm/generated-sdk/auth/schemas.d.ts +2 -0
  39. package/esm/generated-sdk/auth/schemas.d.ts.map +1 -1
  40. package/esm/generated-sdk/auth/schemas.js +2 -0
  41. package/esm/generated-sdk/auth/types.d.ts +4 -2
  42. package/esm/generated-sdk/auth/types.d.ts.map +1 -1
  43. package/esm/generated-sdk/auth/types.js +1 -1
  44. package/esm/generated-sdk/trellis-core/api.d.ts +1 -4
  45. package/esm/generated-sdk/trellis-core/api.d.ts.map +1 -1
  46. package/esm/generated-sdk/trellis-core/api.js +1 -6
  47. package/esm/generated-sdk/trellis-core/client.d.ts +3 -28
  48. package/esm/generated-sdk/trellis-core/client.d.ts.map +1 -1
  49. package/esm/models/auth/rpc/Logout.d.ts.map +1 -1
  50. package/esm/models/auth/rpc/Logout.js +2 -2
  51. package/package.json +2 -2
  52. package/script/auth/browser/login.d.ts +8 -7
  53. package/script/auth/browser/login.d.ts.map +1 -1
  54. package/script/auth/browser/logout.d.ts +23 -0
  55. package/script/auth/browser/logout.d.ts.map +1 -0
  56. package/script/auth/browser/logout.js +84 -0
  57. package/script/auth/browser/portal.d.ts.map +1 -1
  58. package/script/auth/browser/portal.js +2 -0
  59. package/script/auth/browser/session.d.ts +2 -0
  60. package/script/auth/browser/session.d.ts.map +1 -1
  61. package/script/auth/browser/session.js +7 -0
  62. package/script/auth/browser.d.ts +5 -2
  63. package/script/auth/browser.d.ts.map +1 -1
  64. package/script/auth/browser.js +12 -1
  65. package/script/auth/browser_recovery.d.ts +22 -0
  66. package/script/auth/browser_recovery.d.ts.map +1 -0
  67. package/script/auth/browser_recovery.js +242 -0
  68. package/script/auth/mod.d.ts +2 -2
  69. package/script/auth/mod.d.ts.map +1 -1
  70. package/script/auth/mod.js +14 -5
  71. package/script/auth/protocol.d.ts +1 -0
  72. package/script/auth/protocol.d.ts.map +1 -1
  73. package/script/auth/protocol.js +1 -0
  74. package/script/auth/schemas.d.ts +26 -0
  75. package/script/auth/schemas.d.ts.map +1 -1
  76. package/script/auth/schemas.js +37 -1
  77. package/script/browser.d.ts +2 -2
  78. package/script/browser.d.ts.map +1 -1
  79. package/script/browser.js +4 -2
  80. package/script/client_connect.js +1 -1
  81. package/script/generated-sdk/auth/api.d.ts +1 -4
  82. package/script/generated-sdk/auth/api.d.ts.map +1 -1
  83. package/script/generated-sdk/auth/api.js +1 -6
  84. package/script/generated-sdk/auth/client.d.ts +0 -15
  85. package/script/generated-sdk/auth/client.d.ts.map +1 -1
  86. package/script/generated-sdk/auth/contract.d.ts +1 -1
  87. package/script/generated-sdk/auth/contract.d.ts.map +1 -1
  88. package/script/generated-sdk/auth/contract.js +11 -3
  89. package/script/generated-sdk/auth/schemas.d.ts +2 -0
  90. package/script/generated-sdk/auth/schemas.d.ts.map +1 -1
  91. package/script/generated-sdk/auth/schemas.js +2 -0
  92. package/script/generated-sdk/auth/types.d.ts +4 -2
  93. package/script/generated-sdk/auth/types.d.ts.map +1 -1
  94. package/script/generated-sdk/auth/types.js +1 -1
  95. package/script/generated-sdk/trellis-core/api.d.ts +1 -4
  96. package/script/generated-sdk/trellis-core/api.d.ts.map +1 -1
  97. package/script/generated-sdk/trellis-core/api.js +1 -6
  98. package/script/generated-sdk/trellis-core/client.d.ts +3 -28
  99. package/script/generated-sdk/trellis-core/client.d.ts.map +1 -1
  100. package/script/models/auth/rpc/Logout.d.ts.map +1 -1
  101. package/script/models/auth/rpc/Logout.js +2 -2
  102. package/src/auth/browser/login.ts +12 -8
  103. package/src/auth/browser/logout.ts +114 -0
  104. package/src/auth/browser/portal.ts +1 -0
  105. package/src/auth/browser/session.ts +15 -0
  106. package/src/auth/browser.ts +22 -0
  107. package/src/auth/browser_recovery.ts +319 -0
  108. package/src/auth/mod.ts +16 -0
  109. package/src/auth/protocol.ts +1 -0
  110. package/src/auth/schemas.ts +58 -0
  111. package/src/browser.ts +4 -0
  112. package/src/client_connect.ts +1 -1
  113. package/src/models/auth/rpc/Logout.ts +2 -0
  114. package/src/sdk/_generated/auth/api.ts +2 -9
  115. package/src/sdk/_generated/auth/client.ts +0 -37
  116. package/src/sdk/_generated/auth/contract.ts +11 -3
  117. package/src/sdk/_generated/auth/schemas.ts +2 -0
  118. package/src/sdk/_generated/auth/types.ts +2 -2
  119. package/src/sdk/_generated/core/api.ts +2 -9
  120. package/src/sdk/_generated/core/client.ts +2 -41
@@ -1,18 +1,9 @@
1
- import type { AsyncResult, BaseError, EventListenerContext, EventOpts, HandlerTrellis, MaybeAsync, PreparedTrellisEvent, ReceiveTransferGrant, ReceiveTransferHandle, RequestOpts, Result, RpcHandlerContext, SendTransferGrant, SendTransferHandle, TrellisConnection, UnexpectedError, ValidationError } from "@qlever-llc/trellis";
1
+ import type { AsyncResult, BaseError, HandlerTrellis, MaybeAsync, ReceiveTransferGrant, ReceiveTransferHandle, RequestOpts, RpcHandlerContext, SendTransferGrant, SendTransferHandle, TrellisConnection } from "@qlever-llc/trellis";
2
2
  import type { Api } from "./api.js";
3
3
  import type * as Types from "./types.js";
4
- import type * as HealthSdk from "@qlever-llc/trellis/sdk/health";
5
4
  type WithDeps<TDeps> = [TDeps] extends [undefined] ? {} : {
6
5
  deps: TDeps;
7
6
  };
8
- type EventCallback<TMessage> = {
9
- bivarianceHack(message: TMessage, context: EventListenerContext): MaybeAsync<void, BaseError>;
10
- }["bivarianceHack"];
11
- type ServiceEventHandler<TEvent, TDeps = undefined> = (args: {
12
- event: TEvent;
13
- context: EventListenerContext;
14
- client: HandlerClient;
15
- } & WithDeps<TDeps>) => MaybeAsync<void, BaseError>;
16
7
  type RpcHandler<TInput, TOutput, TDeps = undefined> = (args: {
17
8
  input: TInput;
18
9
  context: RpcHandlerContext;
@@ -35,15 +26,7 @@ export interface TrellisCoreClient {
35
26
  surfaceStatus(input: Types.TrellisSurfaceStatusInput, opts?: RequestOpts): AsyncResult<Types.TrellisSurfaceStatusOutput, BaseError>;
36
27
  };
37
28
  };
38
- readonly event: {
39
- readonly health: {
40
- heartbeat: {
41
- publish(event: Omit<HealthSdk.HealthHeartbeatEvent, "header">): AsyncResult<void, ValidationError | UnexpectedError>;
42
- prepare(event: Omit<HealthSdk.HealthHeartbeatEvent, "header">): Result<PreparedTrellisEvent<Omit<HealthSdk.HealthHeartbeatEvent, "header">>, ValidationError | UnexpectedError>;
43
- listen(handler: EventCallback<HealthSdk.HealthHeartbeatEvent>, subjectData?: Record<string, unknown>, opts?: EventOpts): AsyncResult<void, ValidationError | UnexpectedError>;
44
- };
45
- };
46
- };
29
+ readonly event: {};
47
30
  readonly feed: {};
48
31
  readonly operation: {};
49
32
  wait(): AsyncResult<void, BaseError>;
@@ -57,15 +40,7 @@ export type ServiceWithDeps<TDeps> = Omit<TrellisCoreClient, "event"> & {
57
40
  readonly handle: ServiceHandle<TDeps>;
58
41
  with<TNextDeps>(deps: TNextDeps): ServiceWithDeps<TNextDeps>;
59
42
  };
60
- export interface ServiceEventSurface<TDeps> {
61
- readonly health: {
62
- heartbeat: {
63
- publish(event: Omit<HealthSdk.HealthHeartbeatEvent, "header">): AsyncResult<void, ValidationError | UnexpectedError>;
64
- prepare(event: Omit<HealthSdk.HealthHeartbeatEvent, "header">): Result<PreparedTrellisEvent<Omit<HealthSdk.HealthHeartbeatEvent, "header">>, ValidationError | UnexpectedError>;
65
- listen(handler: ServiceEventHandler<HealthSdk.HealthHeartbeatEvent, TDeps>, subjectData?: Record<string, unknown>, opts?: EventOpts): AsyncResult<void, ValidationError | UnexpectedError>;
66
- };
67
- };
68
- }
43
+ export type ServiceEventSurface<TDeps> = {};
69
44
  export interface ServiceHandle<TDeps = undefined> {
70
45
  readonly rpc: {
71
46
  readonly trellis: {
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../src/sdk/_generated/core/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../src/sdk/_generated/core/client.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Logout.d.ts","sourceRoot":"","sources":["../../../../src/models/auth/rpc/Logout.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,EAAE,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAE5C,eAAO,MAAM,wBAAwB,kBAEpC,CAAC;AACF,MAAM,MAAM,uBAAuB,GAAG,MAAM,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE9E,eAAO,MAAM,gCAAgC;;EAI5C,CAAC;AACF,MAAM,MAAM,0BAA0B,GAAG,MAAM,CAC7C,OAAO,gCAAgC,CACxC,CAAC"}
1
+ {"version":3,"file":"Logout.d.ts","sourceRoot":"","sources":["../../../../src/models/auth/rpc/Logout.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,EAAE,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAE5C,eAAO,MAAM,wBAAwB,kBAGpC,CAAC;AACF,MAAM,MAAM,uBAAuB,GAAG,MAAM,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE9E,eAAO,MAAM,gCAAgC;;EAK5C,CAAC;AACF,MAAM,MAAM,0BAA0B,GAAG,MAAM,CAC7C,OAAO,gCAAgC,CACxC,CAAC"}
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.AuthSessionsLogoutResponseSchema = exports.AuthSessionsLogoutSchema = void 0;
7
7
  const typebox_1 = __importDefault(require("typebox"));
8
- exports.AuthSessionsLogoutSchema = typebox_1.default.Object({});
8
+ exports.AuthSessionsLogoutSchema = typebox_1.default.Object({}, { additionalProperties: true });
9
9
  exports.AuthSessionsLogoutResponseSchema = typebox_1.default.Object({
10
10
  success: typebox_1.default.Boolean(),
11
- });
11
+ }, { additionalProperties: false });
@@ -48,6 +48,15 @@ type BuildLoginUrlFlatArgs = {
48
48
  context?: unknown;
49
49
  };
50
50
 
51
+ type StartAuthRequestArgs = {
52
+ authUrl: string;
53
+ provider?: string;
54
+ redirectTo: string;
55
+ handle: SessionKeyHandle;
56
+ contract: Record<string, unknown>;
57
+ context?: unknown;
58
+ };
59
+
51
60
  function contextRecord(value: unknown): Record<string, unknown> | undefined {
52
61
  if (!value || typeof value !== "object" || Array.isArray(value)) {
53
62
  return undefined;
@@ -124,14 +133,9 @@ export async function buildLoginUrl(
124
133
  return response.loginUrl;
125
134
  }
126
135
 
127
- export async function startAuthRequest(args: {
128
- authUrl: string;
129
- provider?: string;
130
- redirectTo: string;
131
- handle: SessionKeyHandle;
132
- contract: Record<string, unknown>;
133
- context?: unknown;
134
- }): Promise<AuthStartResponse> {
136
+ export async function startAuthRequest(
137
+ args: StartAuthRequestArgs,
138
+ ): Promise<AuthStartResponse> {
135
139
  const context = contextRecord(args.context);
136
140
  const contractDigest = isTrellisContractV1(args.contract)
137
141
  ? digestContractManifest(args.contract)
@@ -0,0 +1,114 @@
1
+ import { Value } from "typebox/value";
2
+
3
+ import {
4
+ type AuthLogoutRequest,
5
+ type AuthLogoutResponse,
6
+ AuthLogoutResponseSchema,
7
+ } from "../schemas.js";
8
+ import {
9
+ clearSessionKey,
10
+ logoutSessionSig,
11
+ type SessionKeyHandle,
12
+ } from "./session.js";
13
+
14
+ type LogoutLocation =
15
+ & Pick<Location, "href">
16
+ & Partial<Pick<Location, "assign">>;
17
+
18
+ export type CompleteSessionLogoutArgs = {
19
+ authUrl: string;
20
+ handle: SessionKeyHandle;
21
+ returnTo?: string;
22
+ providerLogout?: boolean;
23
+ federatedProviderLogout?: boolean;
24
+ location?: LogoutLocation;
25
+ };
26
+
27
+ export async function logoutSession(args: {
28
+ authUrl: string;
29
+ handle: SessionKeyHandle;
30
+ returnTo?: string;
31
+ providerLogout?: boolean;
32
+ federatedProviderLogout?: boolean;
33
+ responseMode?: "json";
34
+ fetch?: typeof fetch;
35
+ }): Promise<AuthLogoutResponse> {
36
+ const iat = Math.floor(Date.now() / 1000);
37
+ const responseMode = args.responseMode ?? "json";
38
+ const sig = await logoutSessionSig(args.handle, {
39
+ iat,
40
+ ...(args.providerLogout === undefined
41
+ ? {}
42
+ : { providerLogout: args.providerLogout }),
43
+ ...(args.federatedProviderLogout === undefined
44
+ ? {}
45
+ : { federatedProviderLogout: args.federatedProviderLogout }),
46
+ ...(args.returnTo === undefined ? {} : { returnTo: args.returnTo }),
47
+ responseMode,
48
+ });
49
+ const body: AuthLogoutRequest = {
50
+ sessionKey: args.handle.sessionKey,
51
+ iat,
52
+ sig,
53
+ ...(args.providerLogout === undefined
54
+ ? {}
55
+ : { providerLogout: args.providerLogout }),
56
+ ...(args.federatedProviderLogout === undefined
57
+ ? {}
58
+ : { federatedProviderLogout: args.federatedProviderLogout }),
59
+ ...(args.returnTo === undefined ? {} : { returnTo: args.returnTo }),
60
+ responseMode,
61
+ };
62
+ const fetchImpl = args.fetch ?? globalThis.fetch;
63
+ const response = await fetchImpl(logoutUrl(args.authUrl), {
64
+ method: "POST",
65
+ headers: { "content-type": "application/json" },
66
+ body: JSON.stringify(body),
67
+ });
68
+
69
+ if (!response.ok) {
70
+ throw new Error(`Logout request failed with HTTP ${response.status}`);
71
+ }
72
+
73
+ let parsed: unknown;
74
+ try {
75
+ parsed = await response.json();
76
+ } catch (cause) {
77
+ throw new Error("Logout response was not valid JSON", { cause });
78
+ }
79
+ if (!Value.Check(AuthLogoutResponseSchema, parsed)) {
80
+ throw new Error("Logout response did not match expected schema");
81
+ }
82
+ return parsed;
83
+ }
84
+
85
+ export async function completeSessionLogout(
86
+ args: CompleteSessionLogoutArgs,
87
+ ): Promise<never> {
88
+ let response: AuthLogoutResponse | undefined;
89
+
90
+ try {
91
+ response = await logoutSession(args);
92
+ } catch {
93
+ response = undefined;
94
+ } finally {
95
+ try {
96
+ await clearSessionKey();
97
+ } catch {
98
+ // Preserve logout completion in non-browser/test runtimes without IndexedDB.
99
+ }
100
+ }
101
+
102
+ const target = response?.redirectTo ?? args.returnTo ?? "/";
103
+ const location = args.location ?? globalThis.location;
104
+ if (typeof location.assign === "function") {
105
+ location.assign(target);
106
+ } else {
107
+ location.href = target;
108
+ }
109
+ throw new Error("Redirecting after logout");
110
+ }
111
+
112
+ function logoutUrl(authUrl: string): string {
113
+ return `${authUrl.replace(/\/+$/, "")}/auth/sessions/logout`;
114
+ }
@@ -71,5 +71,6 @@ export function portalRedirectLocation(
71
71
  ): string | null {
72
72
  if (state?.status === "redirect") return state.location;
73
73
  if (state?.status === "approval_denied") return state.returnLocation ?? null;
74
+ if (state?.status === "expired") return state.returnLocation ?? null;
74
75
  return null;
75
76
  }
@@ -6,6 +6,10 @@ import {
6
6
  utf8,
7
7
  } from "../utils.js";
8
8
  import { createProof } from "../proof.js";
9
+ import {
10
+ buildLogoutSignaturePayload,
11
+ type LogoutSignaturePayloadInput,
12
+ } from "../schemas.js";
9
13
  import { buildNatsConnectSignaturePayload } from "../session_auth.js";
10
14
  import {
11
15
  deleteKeyPair,
@@ -159,6 +163,17 @@ export async function natsConnectSigForIat(
159
163
  return base64urlEncode(sig);
160
164
  }
161
165
 
166
+ export async function logoutSessionSig(
167
+ handle: SessionKeyHandle,
168
+ input: LogoutSignaturePayloadInput,
169
+ ): Promise<string> {
170
+ const digest = await sha256(
171
+ utf8(`logout-session:${buildLogoutSignaturePayload(input)}`),
172
+ );
173
+ const sig = await signBytes(handle, digest);
174
+ return base64urlEncode(sig);
175
+ }
176
+
162
177
  export async function createRpcProof(
163
178
  handle: SessionKeyHandle,
164
179
  subject: string,
@@ -19,6 +19,11 @@ export {
19
19
  type SentinelCreds,
20
20
  startAuthRequest,
21
21
  } from "./browser/login.js";
22
+ export {
23
+ completeSessionLogout,
24
+ type CompleteSessionLogoutArgs,
25
+ logoutSession,
26
+ } from "./browser/logout.js";
22
27
  export {
23
28
  type ApprovalDecision,
24
29
  fetchPortalFlowState,
@@ -38,6 +43,7 @@ export {
38
43
  getPublicSessionKey,
39
44
  hasSessionKey,
40
45
  loadSessionKey,
46
+ logoutSessionSig,
41
47
  natsConnectSigForIat,
42
48
  type SessionKeyHandle,
43
49
  type SessionKeyOptions,
@@ -45,10 +51,24 @@ export {
45
51
  signBytes,
46
52
  } from "./browser/session.js";
47
53
  export { deleteKeyPair, hasKeyPair } from "./browser/storage.js";
54
+ export {
55
+ classifyBrowserAuthError,
56
+ isRecoverableBrowserAuthError,
57
+ } from "./browser_recovery.js";
58
+ export type {
59
+ BrowserAuthRecoveryClassification,
60
+ BrowserAuthRecoveryKind,
61
+ } from "./browser_recovery.js";
48
62
  export {
49
63
  approvalCapabilityKeys,
50
64
  type ApprovalDecision as ApprovalDecisionData,
51
65
  ApprovalDecisionSchema,
66
+ type AuthLogoutRequest as AuthLogoutRequestData,
67
+ AuthLogoutRequestSchema,
68
+ type AuthLogoutResponse as AuthLogoutResponseData,
69
+ type AuthLogoutResponseMode as AuthLogoutResponseModeData,
70
+ AuthLogoutResponseModeSchema,
71
+ AuthLogoutResponseSchema,
52
72
  type AuthStartFlowResponse as AuthStartFlowResponseData,
53
73
  AuthStartFlowResponseSchema,
54
74
  type AuthStartRequest as AuthStartRequestData,
@@ -59,6 +79,7 @@ export {
59
79
  BindResponseSchema,
60
80
  type BindSuccessResponse as BindSuccessResponseData,
61
81
  BindSuccessResponseSchema,
82
+ buildLogoutSignaturePayload,
62
83
  type ClientTransportEndpoints as ClientTransportEndpointsData,
63
84
  ClientTransportEndpointsSchema,
64
85
  type ClientTransports as ClientTransportsData,
@@ -66,6 +87,7 @@ export {
66
87
  type ContractApproval as ContractApprovalData,
67
88
  type ContractApprovalCapability as ContractApprovalCapabilityData,
68
89
  ContractApprovalSchema,
90
+ type LogoutSignaturePayloadInput as LogoutSignaturePayloadInputData,
69
91
  type NatsAuthTokenV1 as NatsAuthTokenV1Data,
70
92
  NatsAuthTokenV1Schema,
71
93
  type SentinelCreds as SentinelCredsData,
@@ -0,0 +1,319 @@
1
+ /** Browser auth recovery classification helpers. */
2
+
3
+ /** Stable browser-auth recovery categories for app-owned recovery flows. */
4
+ export type BrowserAuthRecoveryKind =
5
+ | "recoverable_stale_session"
6
+ | "recoverable_expired_flow"
7
+ | "recoverable_auth_required"
8
+ | "policy_denied"
9
+ | "insufficient_capabilities"
10
+ | "runtime_unavailable"
11
+ | "unknown";
12
+
13
+ /** Classification result for a browser-auth related failure. */
14
+ export type BrowserAuthRecoveryClassification = {
15
+ kind: BrowserAuthRecoveryKind;
16
+ recoverable: boolean;
17
+ reason?: string;
18
+ code?: string;
19
+ };
20
+
21
+ type ErrorSignal = {
22
+ code?: string;
23
+ reason?: string;
24
+ message?: string;
25
+ };
26
+
27
+ const MAX_ERROR_DEPTH = 8;
28
+
29
+ function isRecord(value: unknown): value is Record<string, unknown> {
30
+ return value !== null && typeof value === "object";
31
+ }
32
+
33
+ function stringProperty(
34
+ record: Record<string, unknown>,
35
+ property: string,
36
+ ): string | undefined {
37
+ const value = record[property];
38
+ return typeof value === "string" ? value : undefined;
39
+ }
40
+
41
+ function normalize(value: string): string {
42
+ return value.trim().toLowerCase().replaceAll("-", "_").replaceAll(" ", "_");
43
+ }
44
+
45
+ function signalValue(signal: ErrorSignal): string | undefined {
46
+ return signal.code ?? signal.reason ?? signal.message;
47
+ }
48
+
49
+ function classification(
50
+ kind: BrowserAuthRecoveryKind,
51
+ recoverable: boolean,
52
+ signal?: ErrorSignal,
53
+ ): BrowserAuthRecoveryClassification {
54
+ const reason = signal?.reason ?? signalValue(signal ?? {});
55
+ return {
56
+ kind,
57
+ recoverable,
58
+ ...(reason ? { reason } : {}),
59
+ ...(signal?.code ? { code: signal.code } : {}),
60
+ };
61
+ }
62
+
63
+ function maybeSerializable(value: unknown): unknown {
64
+ if (!isRecord(value)) return undefined;
65
+ const toSerializable = value.toSerializable;
66
+ if (typeof toSerializable !== "function") return undefined;
67
+ try {
68
+ return toSerializable.call(value);
69
+ } catch {
70
+ return undefined;
71
+ }
72
+ }
73
+
74
+ function pushRecordSignals(
75
+ record: Record<string, unknown>,
76
+ signals: ErrorSignal[],
77
+ queue: unknown[],
78
+ ): void {
79
+ const message = stringProperty(record, "message");
80
+ const code = stringProperty(record, "code") ??
81
+ stringProperty(record, "error");
82
+ const reason = stringProperty(record, "reason") ??
83
+ stringProperty(record, "status");
84
+ if (message || code || reason) {
85
+ signals.push({
86
+ ...(code ? { code } : {}),
87
+ ...(reason ? { reason } : {}),
88
+ ...(message ? { message } : {}),
89
+ });
90
+ }
91
+
92
+ const context = record.context;
93
+ if (isRecord(context)) {
94
+ const contextReason = stringProperty(context, "reason");
95
+ const causeMessage = stringProperty(context, "causeMessage");
96
+ const contextCode = stringProperty(context, "code");
97
+ const contextMessage = stringProperty(context, "message");
98
+ if (contextReason || causeMessage || contextCode || contextMessage) {
99
+ signals.push({
100
+ ...(contextCode ? { code: contextCode } : {}),
101
+ ...(contextReason ? { reason: contextReason } : {}),
102
+ ...(causeMessage ?? contextMessage
103
+ ? { message: causeMessage ?? contextMessage }
104
+ : {}),
105
+ });
106
+ }
107
+ for (const nested of [context.cause, context.error, context.remoteError]) {
108
+ if (nested !== undefined) queue.push(nested);
109
+ }
110
+ }
111
+
112
+ for (const nested of [record.cause, record.error, record.remoteError]) {
113
+ if (nested !== undefined) queue.push(nested);
114
+ }
115
+ }
116
+
117
+ function collectErrorSignals(error: unknown): ErrorSignal[] {
118
+ const signals: ErrorSignal[] = [];
119
+ const queue: unknown[] = [error];
120
+ const seen = new WeakSet<object>();
121
+ let depth = 0;
122
+
123
+ while (queue.length > 0 && depth < MAX_ERROR_DEPTH) {
124
+ depth += 1;
125
+ const value = queue.shift();
126
+ if (typeof value === "string") {
127
+ signals.push({ message: value });
128
+ continue;
129
+ }
130
+ if (!isRecord(value)) continue;
131
+ if (seen.has(value)) continue;
132
+ seen.add(value);
133
+
134
+ if (value instanceof Error) {
135
+ signals.push({ message: value.message });
136
+ }
137
+ pushRecordSignals(value, signals, queue);
138
+
139
+ const serialized = maybeSerializable(value);
140
+ if (serialized && serialized !== value) queue.push(serialized);
141
+ }
142
+
143
+ return signals;
144
+ }
145
+
146
+ function hasNormalizedValue(
147
+ signals: ErrorSignal[],
148
+ values: ReadonlySet<string>,
149
+ ): ErrorSignal | undefined {
150
+ for (const signal of signals) {
151
+ for (const value of [signal.code, signal.reason]) {
152
+ if (value && values.has(normalize(value))) return signal;
153
+ }
154
+ }
155
+ return undefined;
156
+ }
157
+
158
+ function hasMessagePattern(
159
+ signals: ErrorSignal[],
160
+ patterns: readonly RegExp[],
161
+ ): ErrorSignal | undefined {
162
+ for (const signal of signals) {
163
+ const message = signal.message;
164
+ if (!message) continue;
165
+ const normalized = message.toLowerCase();
166
+ if (patterns.some((pattern) => pattern.test(normalized))) return signal;
167
+ }
168
+ return undefined;
169
+ }
170
+
171
+ function insufficientPermissionsAuthSignal(
172
+ signals: ErrorSignal[],
173
+ ): ErrorSignal | undefined {
174
+ for (const signal of signals) {
175
+ const reason = signal.reason ? normalize(signal.reason) : undefined;
176
+ const code = signal.code ? normalize(signal.code) : undefined;
177
+ if (reason !== "insufficient_permissions") continue;
178
+ if (code === "trellis.bootstrap.auth_required") return signal;
179
+ const message = signal.message?.toLowerCase() ?? "";
180
+ if (
181
+ message.includes("auth required") ||
182
+ message.includes("requires sign-in") ||
183
+ message.includes("requires signin") ||
184
+ message.includes("stale") ||
185
+ message.includes("session")
186
+ ) {
187
+ return signal;
188
+ }
189
+ }
190
+ return undefined;
191
+ }
192
+
193
+ const APPROVAL_DENIED_VALUES = new Set([
194
+ "approval_denied",
195
+ "trellis.auth.approval_denied",
196
+ ]);
197
+
198
+ const INSUFFICIENT_CAPABILITIES_VALUES = new Set([
199
+ "insufficient_capabilities",
200
+ "trellis.auth.insufficient_capabilities",
201
+ ]);
202
+
203
+ const RUNTIME_UNAVAILABLE_VALUES = new Set([
204
+ "trellis.bootstrap.not_ready",
205
+ "trellis.runtime.unavailable",
206
+ "runtime_unavailable",
207
+ ]);
208
+
209
+ const EXPIRED_FLOW_VALUES = new Set([
210
+ "flow_expired",
211
+ "expired",
212
+ "trellis.auth.bind_expired",
213
+ "trellis.auth.flow_expired",
214
+ ]);
215
+
216
+ const STALE_SESSION_VALUES = new Set([
217
+ "session_not_found",
218
+ "session_expired",
219
+ "user_not_found",
220
+ "contract_not_active",
221
+ "trellis.auth.session_not_found",
222
+ "trellis.auth.session_expired",
223
+ "trellis.auth.user_not_found",
224
+ "trellis.auth.contract_not_active",
225
+ ]);
226
+
227
+ const AUTH_REQUIRED_VALUES = new Set([
228
+ "auth_required",
229
+ "trellis.bootstrap.auth_required",
230
+ "trellis.auth.login_failed",
231
+ ]);
232
+
233
+ /**
234
+ * Classifies browser auth, bootstrap, callback, and transport-like failures.
235
+ *
236
+ * The classifier accepts raw errors, serialized Trellis errors, nested causes,
237
+ * and nested remote errors. Recoverable classifications are intended for
238
+ * app-owned flows that can clear stale auth and restart sign-in without showing a
239
+ * user-facing terminal error.
240
+ */
241
+ export function classifyBrowserAuthError(
242
+ error: unknown,
243
+ ): BrowserAuthRecoveryClassification {
244
+ const signals = collectErrorSignals(error);
245
+
246
+ const approvalDenied = hasNormalizedValue(signals, APPROVAL_DENIED_VALUES) ??
247
+ hasMessagePattern(signals, [/approval .*denied/, /access .*denied/]);
248
+ if (approvalDenied) {
249
+ return classification("policy_denied", false, approvalDenied);
250
+ }
251
+
252
+ const inactiveOrInvalid = hasNormalizedValue(
253
+ signals,
254
+ new Set(["invalid_credentials", "user_inactive", "inactive_account"]),
255
+ ) ?? hasMessagePattern(signals, [
256
+ /invalid credential/,
257
+ /inactive account/,
258
+ /user inactive/,
259
+ ]);
260
+ if (inactiveOrInvalid) {
261
+ return classification("policy_denied", false, inactiveOrInvalid);
262
+ }
263
+
264
+ const insufficientCapabilities = hasNormalizedValue(
265
+ signals,
266
+ INSUFFICIENT_CAPABILITIES_VALUES,
267
+ ) ?? hasMessagePattern(signals, [/insufficient capabilit/]);
268
+ if (insufficientCapabilities) {
269
+ return classification(
270
+ "insufficient_capabilities",
271
+ false,
272
+ insufficientCapabilities,
273
+ );
274
+ }
275
+
276
+ const runtimeUnavailable = hasNormalizedValue(
277
+ signals,
278
+ RUNTIME_UNAVAILABLE_VALUES,
279
+ ) ?? hasMessagePattern(signals, [/runtime unavailable/]);
280
+ if (runtimeUnavailable) {
281
+ return classification("runtime_unavailable", false, runtimeUnavailable);
282
+ }
283
+
284
+ const expiredFlow = hasNormalizedValue(signals, EXPIRED_FLOW_VALUES) ??
285
+ hasMessagePattern(signals, [/flow .*expired/, /sign\-in .*expired/]);
286
+ if (expiredFlow) {
287
+ return classification("recoverable_expired_flow", true, expiredFlow);
288
+ }
289
+
290
+ const staleSession = hasNormalizedValue(signals, STALE_SESSION_VALUES) ??
291
+ hasMessagePattern(signals, [
292
+ /session .*expired/,
293
+ /session .*not found/,
294
+ /user .*not found/,
295
+ /contract .*not active/,
296
+ ]);
297
+ if (staleSession) {
298
+ return classification("recoverable_stale_session", true, staleSession);
299
+ }
300
+
301
+ const authRequired = hasNormalizedValue(signals, AUTH_REQUIRED_VALUES) ??
302
+ insufficientPermissionsAuthSignal(signals) ??
303
+ hasMessagePattern(signals, [
304
+ /auth required/,
305
+ /requires sign\-in/,
306
+ /requires signin/,
307
+ /requires authentication/,
308
+ ]);
309
+ if (authRequired) {
310
+ return classification("recoverable_auth_required", true, authRequired);
311
+ }
312
+
313
+ return classification("unknown", false);
314
+ }
315
+
316
+ /** Returns whether a browser auth error can silently restart sign-in. */
317
+ export function isRecoverableBrowserAuthError(error: unknown): boolean {
318
+ return classifyBrowserAuthError(error).recoverable;
319
+ }