@octane-xplat/auth 0.9.0 → 0.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 (76) hide show
  1. package/README.md +115 -16
  2. package/dist/native/auth/src/base64.js +17 -0
  3. package/dist/native/auth/src/hosted.js +252 -0
  4. package/dist/native/auth/src/sha256.js +141 -0
  5. package/dist/native/index.js +6 -5
  6. package/dist/native/octane-client-build.json +1 -1
  7. package/dist/native/platform/src/a11y.js +1 -0
  8. package/dist/native/platform/src/app-info.js +1 -0
  9. package/dist/native/platform/src/auth-session.js +138 -0
  10. package/dist/native/platform/src/breakpoints.tsrx.js +5 -0
  11. package/dist/native/platform/src/clipboard.js +1 -0
  12. package/dist/native/platform/src/connectivity.js +1 -0
  13. package/dist/native/platform/src/deep-links.js +1 -0
  14. package/dist/native/platform/src/device.js +3 -0
  15. package/dist/native/platform/src/index.js +17 -0
  16. package/dist/native/platform/src/lifecycle.tsrx.js +7 -0
  17. package/dist/native/platform/src/locale.js +3 -0
  18. package/dist/native/platform/src/open-url.js +1 -0
  19. package/dist/native/platform/src/random.js +38 -0
  20. package/dist/native/platform/src/safe-area.tsrx.js +4 -0
  21. package/dist/native/platform/src/screen.tsrx.js +4 -0
  22. package/dist/native/platform/src/storage.js +1 -0
  23. package/dist/native/platform/src/system-bars.js +1 -0
  24. package/dist/native/secure-storage/src/index.js +2 -0
  25. package/dist/native/secure-storage/src/secure-storage.js +17 -0
  26. package/dist/web/auth/src/base64.js +17 -0
  27. package/dist/web/auth/src/hosted.js +251 -0
  28. package/dist/web/auth/src/sha256.js +141 -0
  29. package/dist/web/index.js +6 -5
  30. package/dist/web/octane-client-build.json +1 -1
  31. package/dist/web/platform/src/app-info.web.js +3 -0
  32. package/dist/web/platform/src/auth-session.web.js +10 -0
  33. package/dist/web/platform/src/breakpoints.web.tsrx.js +7 -0
  34. package/dist/web/platform/src/clipboard.web.js +3 -0
  35. package/dist/web/platform/src/deep-links.web.js +3 -0
  36. package/dist/web/platform/src/device.web.js +2 -0
  37. package/dist/web/platform/src/host-bridge.web.js +18 -0
  38. package/dist/web/platform/src/host-protocol.js +73 -0
  39. package/dist/web/platform/src/host-runtime.web.js +76 -0
  40. package/dist/web/platform/src/index.web.js +13 -0
  41. package/dist/web/platform/src/lifecycle.web.tsrx.js +3 -0
  42. package/dist/web/platform/src/locale.web.js +10 -0
  43. package/dist/web/platform/src/random.web.js +21 -0
  44. package/dist/web/platform/src/safe-area.web.tsrx.js +3 -0
  45. package/dist/web/platform/src/screen.web.tsrx.js +3 -0
  46. package/dist/web/platform/src/webauthn.web.js +2 -0
  47. package/dist/web/secure-storage/src/secure-storage.web.js +21 -0
  48. package/package.json +11 -5
  49. package/src/AppleSignInButton.macos.tsrx +28 -30
  50. package/src/GoogleSignInButton.macos.tsrx +18 -4
  51. package/src/apple-button.macos.ts +75 -0
  52. package/src/apple.macos.ts +87 -130
  53. package/src/base64.ts +25 -0
  54. package/src/google.macos.ts +81 -14
  55. package/src/hosted.ts +392 -0
  56. package/src/index.macos.ts +17 -0
  57. package/src/index.ts +17 -0
  58. package/src/index.web.ts +17 -0
  59. package/src/sha256.ts +118 -0
  60. package/src/types.ts +216 -4
  61. package/types/generated/.tsrx-typegen-manifest.json +3 -0
  62. package/types/generated/base64.d.ts +1 -0
  63. package/types/generated/hosted.d.ts +6 -0
  64. package/types/generated/index.d.ts +2 -1
  65. package/types/generated/index.web.d.ts +2 -1
  66. package/types/generated/sha256.d.ts +4 -0
  67. package/types/generated/types.d.ts +200 -4
  68. package/types/index.macos.d.ts +40 -0
  69. /package/dist/native/{AppleSignInButton.tsrx.js → auth/src/AppleSignInButton.tsrx.js} +0 -0
  70. /package/dist/native/{GoogleSignInButton.tsrx.js → auth/src/GoogleSignInButton.tsrx.js} +0 -0
  71. /package/dist/native/{apple.js → auth/src/apple.js} +0 -0
  72. /package/dist/native/{google.js → auth/src/google.js} +0 -0
  73. /package/dist/web/{AppleSignInButton.web.tsrx.js → auth/src/AppleSignInButton.web.tsrx.js} +0 -0
  74. /package/dist/web/{GoogleSignInButton.web.tsrx.js → auth/src/GoogleSignInButton.web.tsrx.js} +0 -0
  75. /package/dist/web/{apple.web.js → auth/src/apple.web.js} +0 -0
  76. /package/dist/web/{google.web.js → auth/src/google.web.js} +0 -0
package/src/types.ts CHANGED
@@ -87,6 +87,19 @@ export interface AppleAuth {
87
87
  getCredentialState(userId: string): Promise<AppleCredentialState>
88
88
  }
89
89
 
90
+ /** App-owned Google OAuth ceremony for the macOS system browser. */
91
+ export interface GoogleHostedAuthFlow {
92
+ /** Issue a fresh backend attempt, binding state, nonce, scopes and callback destination. */
93
+ createRequest(
94
+ options: GoogleSignInOptions &
95
+ Pick<GoogleAuthConfig, 'clientId' | 'serverClientId' | 'scopes' | 'hostedDomain'>,
96
+ ): Promise<{ url: string; callbackScheme: string }>
97
+ /** Validate/redeem the callback against that attempt on your backend; return its Google credential. */
98
+ complete(callbackURL: string): Promise<AuthCredential>
99
+ /** Optional backend logout. macOS requests ephemeral browser sessions. */
100
+ signOut?(): Promise<void>
101
+ }
102
+
90
103
  export interface GoogleAuthConfig {
91
104
  /**
92
105
  * OAuth client id — the web client id on web (required there). On iOS it
@@ -99,11 +112,13 @@ export interface GoogleAuthConfig {
99
112
  scopes?: string[]
100
113
  /** Restrict to a Google Workspace domain. */
101
114
  hostedDomain?: string
115
+ /** macOS only — hosted OAuth adapter; other targets keep using their provider SDK. */
116
+ hostedFlow?: GoogleHostedAuthFlow
102
117
  }
103
118
 
104
119
  export interface GoogleSignInOptions {
105
120
  /**
106
- * Web only — nonce bound into the id token. Scope requests go through
121
+ * Web/macOS — nonce bound into the id token. Scope requests go through
107
122
  * `GoogleAuthConfig.scopes`; neither provider SDK takes per-call scopes.
108
123
  */
109
124
  nonce?: string
@@ -111,14 +126,14 @@ export interface GoogleSignInOptions {
111
126
 
112
127
  export interface GoogleAuth {
113
128
  /**
114
- * Whether the provider SDK can run here — iOS/Android + browsers. False on
115
- * macOS (use a hosted `authSession` flow instead). Android devices without
129
+ * Whether the provider can run here — iOS/Android + browsers, or macOS
130
+ * AuthenticationServices (requires `configure({ hostedFlow })`). Android devices without
116
131
  * Play services still report true — the sign-in call surfaces the failure.
117
132
  */
118
133
  readonly supported: boolean
119
134
  configure(config?: GoogleAuthConfig): Promise<void>
120
135
  signIn(options?: GoogleSignInOptions): Promise<SignInResult>
121
- /** Clear the SDK's account selection so the next `signIn` re-prompts. */
136
+ /** Clear SDK account selection; macOS calls hostedFlow.signOut and requests ephemeral sessions. */
122
137
  signOut(): Promise<void>
123
138
  }
124
139
 
@@ -145,3 +160,200 @@ export interface GoogleSignInButtonProps extends SignInButtonBaseProps {
145
160
  /** 'wide' and 'icon' are native-only shapes; web renders 'standard'. */
146
161
  variant?: 'standard' | 'wide' | 'icon'
147
162
  }
163
+
164
+ /* ------------------------------------------------------------------ */
165
+ /* Hosted-auth client (native session transport) */
166
+ /* ------------------------------------------------------------------ */
167
+
168
+ /**
169
+ * Minimal string KV the credential store needs — satisfied by
170
+ * `@octane-xplat/secure-storage`'s `SecureStore` and any host bridge.
171
+ */
172
+ export interface HostedAuthCredentialStore {
173
+ get(key: string): Promise<string | null>
174
+ set(key: string, value: string): Promise<unknown>
175
+ remove(key: string): Promise<unknown>
176
+ }
177
+
178
+ /**
179
+ * DOM-free request init — `Response`/`RequestInit` types are not declared in
180
+ * the native typecheck program, so the client contract is this narrow shape
181
+ * which both runtimes' `fetch` accept at runtime.
182
+ */
183
+ export interface HostedAuthRequestInit {
184
+ method?: string
185
+ headers?: Record<string, string> | Iterable<readonly [string, string]>
186
+ body?: unknown
187
+ signal?: unknown
188
+ }
189
+
190
+ /** The slice of `fetch`'s `Response` the client exposes. */
191
+ export interface HostedAuthResponse {
192
+ readonly status: number
193
+ readonly ok: boolean
194
+ readonly headers: { get(name: string): string | null }
195
+ json(): Promise<unknown>
196
+ text(): Promise<string>
197
+ }
198
+
199
+ export type HostedAuthFetch = (
200
+ url: string,
201
+ init?: HostedAuthRequestInit,
202
+ ) => Promise<HostedAuthResponse>
203
+
204
+ /** What a hosted browser ceremony returns — matches `authSession`'s result. */
205
+ export type HostedAuthSessionResult =
206
+ | { type: 'success'; url: string }
207
+ | { type: 'cancel' }
208
+ | { type: 'error'; message: string }
209
+
210
+ export interface HostedAuthSession {
211
+ readonly supported: boolean
212
+ open(url: string, options: { callbackScheme: string }): Promise<HostedAuthSessionResult>
213
+ }
214
+
215
+ /** Credential record the client persists between sessions. */
216
+ export interface HostedAuthCredentials {
217
+ /** Short-lived access credential — Bearer on authorized API requests. */
218
+ token: string
219
+ /** `token` expiry in milliseconds since epoch. */
220
+ expiresAt: number
221
+ /** Durable session credential — mints access tokens; revoked on sign-out. */
222
+ sessionToken: string
223
+ }
224
+
225
+ /** Fresh single-use PKCE pair the client generates for each ceremony. */
226
+ export interface HostedAuthPkce {
227
+ /** High-entropy verifier kept out of the hosted URL and deep link. */
228
+ verifier: string
229
+ /** base64url(SHA-256(verifier)) sent in the sign-in attempt. */
230
+ challenge: string
231
+ }
232
+
233
+ /** Dependencies the client hands to the flow for each backend call. */
234
+ export interface HostedAuthFlowContext {
235
+ /** DOM-free transport bound to the client's `fetch` config. */
236
+ fetch: HostedAuthFetch
237
+ /** The ceremony's PKCE pair — present during `begin` and `complete`. */
238
+ pkce?: HostedAuthPkce
239
+ }
240
+
241
+ export interface HostedAuthAttempt {
242
+ /** Absolute URL to open in the system browser. */
243
+ url: string
244
+ /** Custom URL scheme the browser callback returns on. */
245
+ callbackScheme: string
246
+ /**
247
+ * Server-issued state the callback's `state` query parameter must echo.
248
+ * When set, the client rejects mismatched callbacks before `complete`.
249
+ */
250
+ state?: string
251
+ /** Flow-private data handed back to `complete` (e.g. an attempt id). */
252
+ data?: unknown
253
+ }
254
+
255
+ /**
256
+ * A product's hosted-auth wire contract — where requests go and what they
257
+ * carry. The client owns the ceremony lifecycle, credential storage, and
258
+ * access-token transport; the flow owns the backend's attempt, redemption,
259
+ * refresh, and revocation calls.
260
+ */
261
+ export interface HostedAuthFlow {
262
+ /**
263
+ * Issue the sign-in attempt against the backend and return the hosted
264
+ * page to open. `context.pkce` is the ceremony's verifier/challenge.
265
+ */
266
+ begin(context: HostedAuthFlowContext): Promise<HostedAuthAttempt>
267
+ /**
268
+ * Redeem the system-browser callback URL into credentials. Return `null`
269
+ * — or throw — to fail the sign-in.
270
+ */
271
+ complete(
272
+ callbackUrl: string,
273
+ attempt: HostedAuthAttempt,
274
+ context: HostedAuthFlowContext,
275
+ ): Promise<HostedAuthCredentials | null>
276
+ /**
277
+ * Mint a fresh credential record from the durable session credential.
278
+ * Return `null` when the session is expired or revoked — the client
279
+ * clears stored credentials. Throw for transient failures.
280
+ */
281
+ refresh?(
282
+ credentials: HostedAuthCredentials,
283
+ context: HostedAuthFlowContext,
284
+ ): Promise<HostedAuthCredentials | null>
285
+ /** Revoke the durable session credential — best-effort. */
286
+ revoke?(credentials: HostedAuthCredentials, context: HostedAuthFlowContext): Promise<void>
287
+ }
288
+
289
+ export interface HostedAuthConfig {
290
+ /** HTTPS origin of the hosted backend; same-origin requests may carry Bearer tokens. */
291
+ apiOrigin: string
292
+ /** The product's hosted-auth wire contract. */
293
+ flow: HostedAuthFlow
294
+ /**
295
+ * Which same-origin paths get `Authorization: Bearer <access token>` on
296
+ * `fetch`. Default: every `/api/*` path except the `/api/auth` mount.
297
+ */
298
+ authorizePath?(pathname: string): boolean
299
+ /** Credential persistence — defaults to `@octane-xplat/secure-storage`. */
300
+ storage?: HostedAuthCredentialStore
301
+ /** Secure-storage key for the credential blob — default `hosted-auth`. */
302
+ storageKey?: string
303
+ /** Transport override — defaults to the global `fetch`. */
304
+ fetch?: HostedAuthFetch
305
+ /** Ceremony override — defaults to the platform `authSession` capability. */
306
+ authSession?: HostedAuthSession
307
+ /** Clock override for expiry checks — defaults to `Date.now`. */
308
+ now?: () => number
309
+ }
310
+
311
+ export type HostedAuthSignInResult =
312
+ | { status: 'success' }
313
+ /** The user dismissed the hosted ceremony, or it ended without a callback. */
314
+ | { status: 'cancelled' }
315
+ | { status: 'error'; message: string }
316
+
317
+ export type HostedAuthStatus = 'authenticated' | 'unauthenticated'
318
+
319
+ /**
320
+ * Hosted-auth client: PKCE + a system-browser ceremony
321
+ * (ASWebAuthenticationSession / Custom Tab) driven by a `HostedAuthFlow`
322
+ * backend contract, credentials in secure storage, Bearer attach + refresh
323
+ * for authorized API calls. Works unchanged on every target — `supported`
324
+ * reports whether the hosted ceremony can run (false on web).
325
+ */
326
+ export interface HostedAuth {
327
+ /**
328
+ * Whether the hosted ceremony can run on this target — the platform
329
+ * `authSession` capability plus an OS CSPRNG. Web reports false: browser
330
+ * apps keep the cookie session flow.
331
+ */
332
+ readonly supported: boolean
333
+ /**
334
+ * Load persisted credentials into memory. Resolves `authenticated` when a
335
+ * durable session token was stored — the access token may still need a
336
+ * refresh before the first API call.
337
+ */
338
+ restore(): Promise<HostedAuthStatus>
339
+ /**
340
+ * Run the hosted sign-in ceremony: `flow.begin` → `authSession` →
341
+ * `flow.complete`. Stores the credential record on success.
342
+ */
343
+ signIn(): Promise<HostedAuthSignInResult>
344
+ /**
345
+ * A currently valid access token, minting a fresh one from the stored
346
+ * session credential when expired. Resolves `null` when there is no usable
347
+ * credential — sign in again.
348
+ */
349
+ getAccessToken(): Promise<string | null>
350
+ /**
351
+ * `fetch` that attaches `Authorization: Bearer <access token>` to
352
+ * `authorizePath`-matching requests under `apiOrigin` and replays once
353
+ * after a refresh when the server rejects the token. Other URLs pass
354
+ * through.
355
+ */
356
+ fetch(url: string, init?: HostedAuthRequestInit): Promise<HostedAuthResponse>
357
+ /** Revoke the durable session via `flow.revoke` and clear stored credentials. */
358
+ signOut(): Promise<void>
359
+ }
@@ -7,10 +7,13 @@
7
7
  "GoogleSignInButton.web.d.ts",
8
8
  "apple.d.ts",
9
9
  "apple.web.d.ts",
10
+ "base64.d.ts",
10
11
  "google.d.ts",
11
12
  "google.web.d.ts",
13
+ "hosted.d.ts",
12
14
  "index.d.ts",
13
15
  "index.web.d.ts",
16
+ "sha256.d.ts",
14
17
  "types.d.ts"
15
18
  ]
16
19
  }
@@ -0,0 +1 @@
1
+ export declare function bytesToBase64Url(bytes: Uint8Array): string;
@@ -0,0 +1,6 @@
1
+ import type { HostedAuth, HostedAuthConfig, HostedAuthFetch } from './types.js';
2
+ export declare function createHostedAuth(config: HostedAuthConfig): HostedAuth;
3
+ /** `POST` a JSON body through the flow's transport. */
4
+ export declare function postJson(transport: HostedAuthFetch, url: string, body: Record<string, string>): Promise<import("./types.js").HostedAuthResponse>;
5
+ /** `?name=value` extraction without URLSearchParams (not in the native program). */
6
+ export declare function queryParam(url: string, name: string): string | null;
@@ -2,4 +2,5 @@ export { appleAuth } from './apple.js';
2
2
  export { googleAuth } from './google.js';
3
3
  export { AppleSignInButton } from './AppleSignInButton.js';
4
4
  export { GoogleSignInButton } from './GoogleSignInButton.js';
5
- export type { AppleAuth, AppleAuthConfig, AppleCredentialState, AppleScope, AppleSignInButtonProps, AppleSignInOptions, AuthCredential, AuthUser, GoogleAuth, GoogleAuthConfig, GoogleSignInButtonProps, GoogleSignInOptions, SignInResult, } from './types.js';
5
+ export { createHostedAuth, postJson, queryParam } from './hosted.js';
6
+ export type { AppleAuth, AppleAuthConfig, AppleCredentialState, AppleScope, AppleSignInButtonProps, AppleSignInOptions, AuthCredential, AuthUser, HostedAuth, HostedAuthAttempt, HostedAuthConfig, HostedAuthCredentialStore, HostedAuthCredentials, HostedAuthFetch, HostedAuthFlow, HostedAuthFlowContext, HostedAuthPkce, HostedAuthRequestInit, HostedAuthResponse, HostedAuthSession, HostedAuthSessionResult, HostedAuthSignInResult, HostedAuthStatus, GoogleAuth, GoogleAuthConfig, GoogleHostedAuthFlow, GoogleSignInButtonProps, GoogleSignInOptions, SignInResult, } from './types.js';
@@ -2,4 +2,5 @@ export { appleAuth } from './apple.web.js';
2
2
  export { googleAuth } from './google.web.js';
3
3
  export { AppleSignInButton } from './AppleSignInButton.web.js';
4
4
  export { GoogleSignInButton } from './GoogleSignInButton.web.js';
5
- export type { AppleAuth, AppleAuthConfig, AppleCredentialState, AppleScope, AppleSignInButtonProps, AppleSignInOptions, AuthCredential, AuthUser, GoogleAuth, GoogleAuthConfig, GoogleSignInButtonProps, GoogleSignInOptions, SignInResult, } from './types.js';
5
+ export { createHostedAuth, postJson, queryParam } from './hosted.js';
6
+ export type { AppleAuth, AppleAuthConfig, AppleCredentialState, AppleScope, AppleSignInButtonProps, AppleSignInOptions, AuthCredential, AuthUser, HostedAuth, HostedAuthAttempt, HostedAuthConfig, HostedAuthCredentialStore, HostedAuthCredentials, HostedAuthFetch, HostedAuthFlow, HostedAuthFlowContext, HostedAuthPkce, HostedAuthRequestInit, HostedAuthResponse, HostedAuthSession, HostedAuthSessionResult, HostedAuthSignInResult, HostedAuthStatus, GoogleAuth, GoogleAuthConfig, GoogleHostedAuthFlow, GoogleSignInButtonProps, GoogleSignInOptions, SignInResult, } from './types.js';
@@ -0,0 +1,4 @@
1
+ export declare function utf8Bytes(input: string): Uint8Array;
2
+ export declare function sha256(bytes: Uint8Array): Uint8Array;
3
+ /** Hex SHA-256 of a UTF-8 string — e.g. the Apple request nonce binding. */
4
+ export declare function sha256Hex(input: string): string;
@@ -77,6 +77,18 @@ export interface AppleAuth {
77
77
  /** iOS and macOS — credential state for a prior `user.id`. */
78
78
  getCredentialState(userId: string): Promise<AppleCredentialState>;
79
79
  }
80
+ /** App-owned Google OAuth ceremony for the macOS system browser. */
81
+ export interface GoogleHostedAuthFlow {
82
+ /** Issue a fresh backend attempt, binding state, nonce, scopes and callback destination. */
83
+ createRequest(options: GoogleSignInOptions & Pick<GoogleAuthConfig, 'clientId' | 'serverClientId' | 'scopes' | 'hostedDomain'>): Promise<{
84
+ url: string;
85
+ callbackScheme: string;
86
+ }>;
87
+ /** Validate/redeem the callback against that attempt on your backend; return its Google credential. */
88
+ complete(callbackURL: string): Promise<AuthCredential>;
89
+ /** Optional backend logout. macOS requests ephemeral browser sessions. */
90
+ signOut?(): Promise<void>;
91
+ }
80
92
  export interface GoogleAuthConfig {
81
93
  /**
82
94
  * OAuth client id — the web client id on web (required there). On iOS it
@@ -89,24 +101,26 @@ export interface GoogleAuthConfig {
89
101
  scopes?: string[];
90
102
  /** Restrict to a Google Workspace domain. */
91
103
  hostedDomain?: string;
104
+ /** macOS only — hosted OAuth adapter; other targets keep using their provider SDK. */
105
+ hostedFlow?: GoogleHostedAuthFlow;
92
106
  }
93
107
  export interface GoogleSignInOptions {
94
108
  /**
95
- * Web only — nonce bound into the id token. Scope requests go through
109
+ * Web/macOS — nonce bound into the id token. Scope requests go through
96
110
  * `GoogleAuthConfig.scopes`; neither provider SDK takes per-call scopes.
97
111
  */
98
112
  nonce?: string;
99
113
  }
100
114
  export interface GoogleAuth {
101
115
  /**
102
- * Whether the provider SDK can run here — iOS/Android + browsers. False on
103
- * macOS (use a hosted `authSession` flow instead). Android devices without
116
+ * Whether the provider can run here — iOS/Android + browsers, or macOS
117
+ * AuthenticationServices (requires `configure({ hostedFlow })`). Android devices without
104
118
  * Play services still report true — the sign-in call surfaces the failure.
105
119
  */
106
120
  readonly supported: boolean;
107
121
  configure(config?: GoogleAuthConfig): Promise<void>;
108
122
  signIn(options?: GoogleSignInOptions): Promise<SignInResult>;
109
- /** Clear the SDK's account selection so the next `signIn` re-prompts. */
123
+ /** Clear SDK account selection; macOS calls hostedFlow.signOut and requests ephemeral sessions. */
110
124
  signOut(): Promise<void>;
111
125
  }
112
126
  interface SignInButtonBaseProps {
@@ -130,4 +144,186 @@ export interface GoogleSignInButtonProps extends SignInButtonBaseProps {
130
144
  /** 'wide' and 'icon' are native-only shapes; web renders 'standard'. */
131
145
  variant?: 'standard' | 'wide' | 'icon';
132
146
  }
147
+ /**
148
+ * Minimal string KV the credential store needs — satisfied by
149
+ * `@octane-xplat/secure-storage`'s `SecureStore` and any host bridge.
150
+ */
151
+ export interface HostedAuthCredentialStore {
152
+ get(key: string): Promise<string | null>;
153
+ set(key: string, value: string): Promise<unknown>;
154
+ remove(key: string): Promise<unknown>;
155
+ }
156
+ /**
157
+ * DOM-free request init — `Response`/`RequestInit` types are not declared in
158
+ * the native typecheck program, so the client contract is this narrow shape
159
+ * which both runtimes' `fetch` accept at runtime.
160
+ */
161
+ export interface HostedAuthRequestInit {
162
+ method?: string;
163
+ headers?: Record<string, string> | Iterable<readonly [string, string]>;
164
+ body?: unknown;
165
+ signal?: unknown;
166
+ }
167
+ /** The slice of `fetch`'s `Response` the client exposes. */
168
+ export interface HostedAuthResponse {
169
+ readonly status: number;
170
+ readonly ok: boolean;
171
+ readonly headers: {
172
+ get(name: string): string | null;
173
+ };
174
+ json(): Promise<unknown>;
175
+ text(): Promise<string>;
176
+ }
177
+ export type HostedAuthFetch = (url: string, init?: HostedAuthRequestInit) => Promise<HostedAuthResponse>;
178
+ /** What a hosted browser ceremony returns — matches `authSession`'s result. */
179
+ export type HostedAuthSessionResult = {
180
+ type: 'success';
181
+ url: string;
182
+ } | {
183
+ type: 'cancel';
184
+ } | {
185
+ type: 'error';
186
+ message: string;
187
+ };
188
+ export interface HostedAuthSession {
189
+ readonly supported: boolean;
190
+ open(url: string, options: {
191
+ callbackScheme: string;
192
+ }): Promise<HostedAuthSessionResult>;
193
+ }
194
+ /** Credential record the client persists between sessions. */
195
+ export interface HostedAuthCredentials {
196
+ /** Short-lived access credential — Bearer on authorized API requests. */
197
+ token: string;
198
+ /** `token` expiry in milliseconds since epoch. */
199
+ expiresAt: number;
200
+ /** Durable session credential — mints access tokens; revoked on sign-out. */
201
+ sessionToken: string;
202
+ }
203
+ /** Fresh single-use PKCE pair the client generates for each ceremony. */
204
+ export interface HostedAuthPkce {
205
+ /** High-entropy verifier kept out of the hosted URL and deep link. */
206
+ verifier: string;
207
+ /** base64url(SHA-256(verifier)) sent in the sign-in attempt. */
208
+ challenge: string;
209
+ }
210
+ /** Dependencies the client hands to the flow for each backend call. */
211
+ export interface HostedAuthFlowContext {
212
+ /** DOM-free transport bound to the client's `fetch` config. */
213
+ fetch: HostedAuthFetch;
214
+ /** The ceremony's PKCE pair — present during `begin` and `complete`. */
215
+ pkce?: HostedAuthPkce;
216
+ }
217
+ export interface HostedAuthAttempt {
218
+ /** Absolute URL to open in the system browser. */
219
+ url: string;
220
+ /** Custom URL scheme the browser callback returns on. */
221
+ callbackScheme: string;
222
+ /**
223
+ * Server-issued state the callback's `state` query parameter must echo.
224
+ * When set, the client rejects mismatched callbacks before `complete`.
225
+ */
226
+ state?: string;
227
+ /** Flow-private data handed back to `complete` (e.g. an attempt id). */
228
+ data?: unknown;
229
+ }
230
+ /**
231
+ * A product's hosted-auth wire contract — where requests go and what they
232
+ * carry. The client owns the ceremony lifecycle, credential storage, and
233
+ * access-token transport; the flow owns the backend's attempt, redemption,
234
+ * refresh, and revocation calls.
235
+ */
236
+ export interface HostedAuthFlow {
237
+ /**
238
+ * Issue the sign-in attempt against the backend and return the hosted
239
+ * page to open. `context.pkce` is the ceremony's verifier/challenge.
240
+ */
241
+ begin(context: HostedAuthFlowContext): Promise<HostedAuthAttempt>;
242
+ /**
243
+ * Redeem the system-browser callback URL into credentials. Return `null`
244
+ * — or throw — to fail the sign-in.
245
+ */
246
+ complete(callbackUrl: string, attempt: HostedAuthAttempt, context: HostedAuthFlowContext): Promise<HostedAuthCredentials | null>;
247
+ /**
248
+ * Mint a fresh credential record from the durable session credential.
249
+ * Return `null` when the session is expired or revoked — the client
250
+ * clears stored credentials. Throw for transient failures.
251
+ */
252
+ refresh?(credentials: HostedAuthCredentials, context: HostedAuthFlowContext): Promise<HostedAuthCredentials | null>;
253
+ /** Revoke the durable session credential — best-effort. */
254
+ revoke?(credentials: HostedAuthCredentials, context: HostedAuthFlowContext): Promise<void>;
255
+ }
256
+ export interface HostedAuthConfig {
257
+ /** HTTPS origin of the hosted backend; same-origin requests may carry Bearer tokens. */
258
+ apiOrigin: string;
259
+ /** The product's hosted-auth wire contract. */
260
+ flow: HostedAuthFlow;
261
+ /**
262
+ * Which same-origin paths get `Authorization: Bearer <access token>` on
263
+ * `fetch`. Default: every `/api/*` path except the `/api/auth` mount.
264
+ */
265
+ authorizePath?(pathname: string): boolean;
266
+ /** Credential persistence — defaults to `@octane-xplat/secure-storage`. */
267
+ storage?: HostedAuthCredentialStore;
268
+ /** Secure-storage key for the credential blob — default `hosted-auth`. */
269
+ storageKey?: string;
270
+ /** Transport override — defaults to the global `fetch`. */
271
+ fetch?: HostedAuthFetch;
272
+ /** Ceremony override — defaults to the platform `authSession` capability. */
273
+ authSession?: HostedAuthSession;
274
+ /** Clock override for expiry checks — defaults to `Date.now`. */
275
+ now?: () => number;
276
+ }
277
+ export type HostedAuthSignInResult = {
278
+ status: 'success';
279
+ }
280
+ /** The user dismissed the hosted ceremony, or it ended without a callback. */
281
+ | {
282
+ status: 'cancelled';
283
+ } | {
284
+ status: 'error';
285
+ message: string;
286
+ };
287
+ export type HostedAuthStatus = 'authenticated' | 'unauthenticated';
288
+ /**
289
+ * Hosted-auth client: PKCE + a system-browser ceremony
290
+ * (ASWebAuthenticationSession / Custom Tab) driven by a `HostedAuthFlow`
291
+ * backend contract, credentials in secure storage, Bearer attach + refresh
292
+ * for authorized API calls. Works unchanged on every target — `supported`
293
+ * reports whether the hosted ceremony can run (false on web).
294
+ */
295
+ export interface HostedAuth {
296
+ /**
297
+ * Whether the hosted ceremony can run on this target — the platform
298
+ * `authSession` capability plus an OS CSPRNG. Web reports false: browser
299
+ * apps keep the cookie session flow.
300
+ */
301
+ readonly supported: boolean;
302
+ /**
303
+ * Load persisted credentials into memory. Resolves `authenticated` when a
304
+ * durable session token was stored — the access token may still need a
305
+ * refresh before the first API call.
306
+ */
307
+ restore(): Promise<HostedAuthStatus>;
308
+ /**
309
+ * Run the hosted sign-in ceremony: `flow.begin` → `authSession` →
310
+ * `flow.complete`. Stores the credential record on success.
311
+ */
312
+ signIn(): Promise<HostedAuthSignInResult>;
313
+ /**
314
+ * A currently valid access token, minting a fresh one from the stored
315
+ * session credential when expired. Resolves `null` when there is no usable
316
+ * credential — sign in again.
317
+ */
318
+ getAccessToken(): Promise<string | null>;
319
+ /**
320
+ * `fetch` that attaches `Authorization: Bearer <access token>` to
321
+ * `authorizePath`-matching requests under `apiOrigin` and replays once
322
+ * after a refresh when the server rejects the token. Other URLs pass
323
+ * through.
324
+ */
325
+ fetch(url: string, init?: HostedAuthRequestInit): Promise<HostedAuthResponse>;
326
+ /** Revoke the durable session via `flow.revoke` and clear stored credentials. */
327
+ signOut(): Promise<void>;
328
+ }
133
329
  export {};
@@ -7,8 +7,24 @@ import type {
7
7
  AppleSignInOptions,
8
8
  AuthCredential,
9
9
  AuthUser,
10
+ HostedAuth,
11
+ HostedAuthAttempt,
12
+ HostedAuthConfig,
13
+ HostedAuthCredentialStore,
14
+ HostedAuthCredentials,
15
+ HostedAuthFetch,
16
+ HostedAuthFlow,
17
+ HostedAuthFlowContext,
18
+ HostedAuthPkce,
19
+ HostedAuthRequestInit,
20
+ HostedAuthResponse,
21
+ HostedAuthSession,
22
+ HostedAuthSessionResult,
23
+ HostedAuthSignInResult,
24
+ HostedAuthStatus,
10
25
  GoogleAuth,
11
26
  GoogleAuthConfig,
27
+ GoogleHostedAuthFlow,
12
28
  GoogleSignInButtonProps,
13
29
  GoogleSignInOptions,
14
30
  SignInResult,
@@ -23,8 +39,24 @@ export type {
23
39
  AppleSignInOptions,
24
40
  AuthCredential,
25
41
  AuthUser,
42
+ HostedAuth,
43
+ HostedAuthAttempt,
44
+ HostedAuthConfig,
45
+ HostedAuthCredentialStore,
46
+ HostedAuthCredentials,
47
+ HostedAuthFetch,
48
+ HostedAuthFlow,
49
+ HostedAuthFlowContext,
50
+ HostedAuthPkce,
51
+ HostedAuthRequestInit,
52
+ HostedAuthResponse,
53
+ HostedAuthSession,
54
+ HostedAuthSessionResult,
55
+ HostedAuthSignInResult,
56
+ HostedAuthStatus,
26
57
  GoogleAuth,
27
58
  GoogleAuthConfig,
59
+ GoogleHostedAuthFlow,
28
60
  GoogleSignInButtonProps,
29
61
  GoogleSignInOptions,
30
62
  SignInResult,
@@ -34,3 +66,11 @@ export declare const appleAuth: AppleAuth
34
66
  export declare const googleAuth: GoogleAuth
35
67
  export declare function AppleSignInButton(props: AppleSignInButtonProps): unknown
36
68
  export declare function GoogleSignInButton(props: GoogleSignInButtonProps): unknown
69
+ export declare function createHostedAuth(config: HostedAuthConfig): HostedAuth
70
+ export declare function postJson(
71
+ transport: HostedAuthFetch,
72
+ url: string,
73
+ body: Record<string, string>,
74
+ ): Promise<HostedAuthResponse>
75
+
76
+ export declare function queryParam(url: string, name: string): string | null
File without changes
File without changes