@ai-matrx/auth 0.2.0 → 0.2.2

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/dist/index.d.cts CHANGED
@@ -1,11 +1,127 @@
1
- export { A as AuthClient, S as SessionSourceLike, a as SignInError, U as UserCredentialsPort, g as getPerson, b as getSession, i as invalidatePerson, o as onSessionChange, r as refreshSession, s as sessionCredentials, c as signInWithOAuth, d as signInWithPassword, e as signOut, u as updatePerson, f as userCredentials } from './session-DdQiStp6.cjs';
2
- import { S as SessionStorage } from './storage-Dqnye4KF.cjs';
3
- export { C as ChromeStorageAreaLike, a as StorageUnavailableError, b as browserStorage, e as extensionStorage, k as keyValueStorage, m as memoryStorage } from './storage-Dqnye4KF.cjs';
4
- import { SupabaseClient } from '@supabase/supabase-js';
1
+ import { H as HeldOrganizationStore, A as AuthClient } from './active-organization-Dy4UtiyR.cjs';
2
+ export { S as SessionSourceLike, a as SignInError, U as UserCredentialsPort, g as getPerson, b as getSession, i as invalidatePerson, o as onSessionChange, r as refreshSession, s as sessionCredentials, c as signInWithOAuth, d as signInWithPassword, e as signOut, u as updatePerson, f as userCredentials } from './active-organization-Dy4UtiyR.cjs';
3
+ import { S as SessionStorage, M as MatrxOAuthClient } from './matrx-oauth-_Ji8X5Wm.cjs';
4
+ export { C as ChromeStorageAreaLike, a as StorageUnavailableError, b as browserStorage, e as extensionStorage, k as keyValueStorage, m as memoryStorage } from './matrx-oauth-_Ji8X5Wm.cjs';
5
+ import { SupabaseClient, User } from '@supabase/supabase-js';
5
6
  export { AuthChangeEvent, Session, User, UserAttributes } from '@supabase/supabase-js';
6
7
  export { CredentialsPort, MatrxCredential, MatrxCredentialKind } from './credentials.cjs';
7
8
  export { A as ApiClaimsUser, C as ClaimsCacheOptions, a as ClaimsCapableClient, b as ClaimsResult, P as PROJECT_SIGNING_KEYS, c as PROJECT_SIGNING_KEY_AUTHORITIES, d as accountFlagsFor, e as confirmUnverifiableSession, f as createClaimsCache, g as getClaimsUser, i as isAuthTransportFailure, h as isSignedOutError, j as isUnverifiableTokenError, k as isUnverifiableTokenRefusal, p as pinnedSigningKeysFor, u as userFromClaims } from './claims-DXdbe3cW.cjs';
8
9
 
10
+ /** How long a request may wait for the first auth report before going anyway. */
11
+ declare const SESSION_ATTACH_BUDGET_MS = 3000;
12
+ /** How long a refused request may wait for a session before it gives up. */
13
+ declare const SESSION_RECOVERY_BUDGET_MS = 5000;
14
+ /** After one wait expires, how long every other request skips the wait. */
15
+ declare const WAIT_COOLDOWN_MS = 30000;
16
+ /** What the client knows about its own session right now. */
17
+ type BarrierSessionState = "unknown" | "attached" | "expected" | "absent";
18
+ /** The marker written into an error capture's `session_state`. */
19
+ type BarrierSessionMarker = "attached" | "pre_attach" | "signed_out" | "unknown";
20
+ /** What the wrapper knows about the call it is about to make. */
21
+ interface BarrierCallContext {
22
+ schema?: string;
23
+ relation?: string;
24
+ }
25
+ /** A barrier announcement the host records (the host adds its own source/operation fields). */
26
+ interface BarrierReport {
27
+ code: "SESSION_BARRIER_RECOVERED" | "SESSION_BARRIER_UNRECOVERED";
28
+ message: string;
29
+ schema?: string | undefined;
30
+ relation?: string | undefined;
31
+ status: 401;
32
+ sessionState: BarrierSessionMarker;
33
+ /** True only for a failure (a repaired read is news for an inspector, not a repair queue). */
34
+ durable: boolean;
35
+ }
36
+ interface RefusalLike {
37
+ error?: {
38
+ code?: string;
39
+ message?: string;
40
+ } | null;
41
+ status?: number;
42
+ }
43
+ /** The slice of `client.auth` the barrier binds to. */
44
+ interface BarrierAuth {
45
+ getSession(): Promise<{
46
+ data: {
47
+ session: {
48
+ access_token?: string;
49
+ } | null;
50
+ };
51
+ error: unknown;
52
+ }>;
53
+ onAuthStateChange(callback: (event: string, session: unknown) => void): unknown;
54
+ getClaims?: (jwt?: string, options?: {
55
+ jwks?: {
56
+ keys: any[];
57
+ };
58
+ }) => Promise<{
59
+ data: unknown;
60
+ error: {
61
+ name?: string;
62
+ code?: string;
63
+ status?: number;
64
+ message?: string;
65
+ } | null;
66
+ }>;
67
+ signOut?: (options: {
68
+ scope: "local";
69
+ }) => Promise<unknown>;
70
+ }
71
+ interface SessionBarrierOptions {
72
+ /** Record an announcement (Error Inspector / durable repair queue). */
73
+ report(event: BarrierReport): void;
74
+ /** Doors that serve a guest honestly: a 42501 there is a real refusal, never retried. */
75
+ isAnonymousByDesign?(schema: string | undefined, relation: string | undefined): boolean;
76
+ /** The one door that must never wait (the error sink). */
77
+ bypassesSessionWait?(relation: string | undefined): boolean;
78
+ /** End a session the database can never verify on this device and send the person to sign in. */
79
+ endUnverifiable?(auth: {
80
+ signOut: NonNullable<BarrierAuth["signOut"]>;
81
+ }, where: {
82
+ door: string;
83
+ via: "postgrest" | "claims";
84
+ }): Promise<void>;
85
+ /** Stamp every capture in the host with `sessionStateMarker()` (a probe, so the store needs no import). */
86
+ setSessionStateProbe?(probe: (() => BarrierSessionMarker) | null): void;
87
+ /** URL the client talks to — decides which pinned signing keys confirm "unverifiable". */
88
+ supabaseUrl?: string | null | undefined;
89
+ attachBudgetMs?: number;
90
+ recoveryBudgetMs?: number;
91
+ waitCooldownMs?: number;
92
+ /** Where the cookie string comes from; `null` = cannot tell. Default: `document.cookie`, `null` when unreadable. */
93
+ readCookie?(): string | null;
94
+ /** Browser-only gate. Default: `typeof window !== "undefined"`. */
95
+ isBrowser?(): boolean;
96
+ now?(): number;
97
+ warn?(message: string): void;
98
+ }
99
+ interface SessionBarrier {
100
+ install(client: unknown): void;
101
+ reset(): void;
102
+ /** Drive the signal without a client (tests, or a host that hears auth elsewhere). */
103
+ announceSession(present: boolean | null): void;
104
+ authCookiePresent(): boolean | null;
105
+ sessionStateNow(): BarrierSessionState;
106
+ sessionStateMarker(): BarrierSessionMarker;
107
+ hasAttachedSession(): boolean;
108
+ whenSessionAttached(listener: () => void): () => void;
109
+ canSendImmediately(ctx: BarrierCallContext): boolean;
110
+ awaitSessionBeforeSend(ctx: BarrierCallContext): Promise<void>;
111
+ isSessionRefusal(result: RefusalLike): boolean;
112
+ shouldRecoverSession(ctx: BarrierCallContext): boolean;
113
+ endSessionIfUnverifiable(ctx: BarrierCallContext, result: RefusalLike): Promise<boolean>;
114
+ recoverSessionForRetry(ctx: BarrierCallContext): Promise<boolean>;
115
+ reportSessionRetryOutcome(ctx: BarrierCallContext, retried: RefusalLike): void;
116
+ }
117
+ /**
118
+ * Is this result the database saying "your request carried no identity"? The discriminator is HTTP 401:
119
+ * a 42501 at 403 is a REAL grant gap for `authenticated` and must never be retried.
120
+ */
121
+ declare function isSessionRefusal(result: RefusalLike): boolean;
122
+ /** One barrier per browser client (module scope in the host is the tab). */
123
+ declare function createSessionBarrier(options: SessionBarrierOptions): SessionBarrier;
124
+
9
125
  /**
10
126
  * `createAuthClient` — the one Supabase client factory OUTSIDE Next.js (Next apps use
11
127
  * `@ai-matrx/auth/next`, whose cookie clients carry the domain-wide auth cookie).
@@ -36,4 +152,44 @@ declare class SecretKeyRefusedError extends Error {
36
152
  }
37
153
  declare function createAuthClient<Database = any>(options: CreateAuthClientOptions): SupabaseClient<Database>;
38
154
 
39
- export { type CreateAuthClientOptions, SecretKeyRefusedError, SessionStorage, createAuthClient };
155
+ /**
156
+ * An app that signs in with "Sign in with AI Matrx" (`createMatrxOAuth`) keeps its OWN session; it
157
+ * has no GoTrue session behind its Supabase client (the extension's client reads its bearer through
158
+ * supabase-js's `accessToken` hook, and `client.auth` on such a client throws). The session doors
159
+ * (`getSession`, `getPerson`, `onSessionChange`), `useSession` and the active organization all read
160
+ * `client.auth`. These two helpers give them one, built from the OAuth client:
161
+ *
162
+ * const oauth = createMatrxOAuth(config, ports);
163
+ * const client = withOAuthSession(supabaseWithAccessTokenHook, oauth); // db + a real `auth`
164
+ * const { session } = useSession(client);
165
+ * const active = createActiveOrganization({ client, held: heldOrganizationInStorage(extensionStorage(chrome.storage.session)) });
166
+ *
167
+ * The `auth` is the slice those doors use: `getSession`, `getUser`, `refreshSession`, `signOut`,
168
+ * `onAuthStateChange`. Password / OAuth-provider sign-in and profile edits are not part of it and
169
+ * refuse by name.
170
+ */
171
+
172
+ interface OAuthAuthClientOptions {
173
+ /**
174
+ * The person for an access token. Default: built locally from the token's claims (id, email) with
175
+ * no network. Pass the host's verified read (the extension's JWKS claims check) to return
176
+ * more fields; return null for "this token is not a person" (signed out).
177
+ */
178
+ readonly readUser?: ((accessToken: string) => Promise<User | null>) | undefined;
179
+ }
180
+ /** `{ auth }` for the session doors, backed by an OAuth client's own session. */
181
+ declare function oauthAuthClient(oauth: MatrxOAuthClient, options?: OAuthAuthClientOptions): AuthClient;
182
+ /**
183
+ * The data client (any supabase-js client: `rpc`, `schema`, `from`) with the OAuth session as its
184
+ * `auth`. Nothing is read from the client's own `auth` (which throws on an `accessToken`-hook
185
+ * client).
186
+ */
187
+ declare function withOAuthSession<C extends object>(db: C, oauth: MatrxOAuthClient, options?: OAuthAuthClientOptions): C & AuthClient;
188
+ /**
189
+ * A held-organization store over any async {@link SessionStorage} (identity-keyed): the extension's
190
+ * `chrome.storage.session` / `.local` through `extensionStorage(area)`. A stored choice for a
191
+ * different person reads as none.
192
+ */
193
+ declare function heldOrganizationInStorage(storage: SessionStorage, key?: string): HeldOrganizationStore;
194
+
195
+ export { AuthClient, type BarrierAuth, type BarrierCallContext, type BarrierReport, type BarrierSessionMarker, type BarrierSessionState, type CreateAuthClientOptions, type OAuthAuthClientOptions, type RefusalLike, SESSION_ATTACH_BUDGET_MS, SESSION_RECOVERY_BUDGET_MS, SecretKeyRefusedError, type SessionBarrier, type SessionBarrierOptions, SessionStorage, WAIT_COOLDOWN_MS, createAuthClient, createSessionBarrier, heldOrganizationInStorage, isSessionRefusal, oauthAuthClient, withOAuthSession };
package/dist/index.d.ts CHANGED
@@ -1,11 +1,127 @@
1
- export { A as AuthClient, S as SessionSourceLike, a as SignInError, U as UserCredentialsPort, g as getPerson, b as getSession, i as invalidatePerson, o as onSessionChange, r as refreshSession, s as sessionCredentials, c as signInWithOAuth, d as signInWithPassword, e as signOut, u as updatePerson, f as userCredentials } from './session-DdQiStp6.js';
2
- import { S as SessionStorage } from './storage-Dqnye4KF.js';
3
- export { C as ChromeStorageAreaLike, a as StorageUnavailableError, b as browserStorage, e as extensionStorage, k as keyValueStorage, m as memoryStorage } from './storage-Dqnye4KF.js';
4
- import { SupabaseClient } from '@supabase/supabase-js';
1
+ import { H as HeldOrganizationStore, A as AuthClient } from './active-organization-Dy4UtiyR.js';
2
+ export { S as SessionSourceLike, a as SignInError, U as UserCredentialsPort, g as getPerson, b as getSession, i as invalidatePerson, o as onSessionChange, r as refreshSession, s as sessionCredentials, c as signInWithOAuth, d as signInWithPassword, e as signOut, u as updatePerson, f as userCredentials } from './active-organization-Dy4UtiyR.js';
3
+ import { S as SessionStorage, M as MatrxOAuthClient } from './matrx-oauth-_Ji8X5Wm.js';
4
+ export { C as ChromeStorageAreaLike, a as StorageUnavailableError, b as browserStorage, e as extensionStorage, k as keyValueStorage, m as memoryStorage } from './matrx-oauth-_Ji8X5Wm.js';
5
+ import { SupabaseClient, User } from '@supabase/supabase-js';
5
6
  export { AuthChangeEvent, Session, User, UserAttributes } from '@supabase/supabase-js';
6
7
  export { CredentialsPort, MatrxCredential, MatrxCredentialKind } from './credentials.js';
7
8
  export { A as ApiClaimsUser, C as ClaimsCacheOptions, a as ClaimsCapableClient, b as ClaimsResult, P as PROJECT_SIGNING_KEYS, c as PROJECT_SIGNING_KEY_AUTHORITIES, d as accountFlagsFor, e as confirmUnverifiableSession, f as createClaimsCache, g as getClaimsUser, i as isAuthTransportFailure, h as isSignedOutError, j as isUnverifiableTokenError, k as isUnverifiableTokenRefusal, p as pinnedSigningKeysFor, u as userFromClaims } from './claims-DXdbe3cW.js';
8
9
 
10
+ /** How long a request may wait for the first auth report before going anyway. */
11
+ declare const SESSION_ATTACH_BUDGET_MS = 3000;
12
+ /** How long a refused request may wait for a session before it gives up. */
13
+ declare const SESSION_RECOVERY_BUDGET_MS = 5000;
14
+ /** After one wait expires, how long every other request skips the wait. */
15
+ declare const WAIT_COOLDOWN_MS = 30000;
16
+ /** What the client knows about its own session right now. */
17
+ type BarrierSessionState = "unknown" | "attached" | "expected" | "absent";
18
+ /** The marker written into an error capture's `session_state`. */
19
+ type BarrierSessionMarker = "attached" | "pre_attach" | "signed_out" | "unknown";
20
+ /** What the wrapper knows about the call it is about to make. */
21
+ interface BarrierCallContext {
22
+ schema?: string;
23
+ relation?: string;
24
+ }
25
+ /** A barrier announcement the host records (the host adds its own source/operation fields). */
26
+ interface BarrierReport {
27
+ code: "SESSION_BARRIER_RECOVERED" | "SESSION_BARRIER_UNRECOVERED";
28
+ message: string;
29
+ schema?: string | undefined;
30
+ relation?: string | undefined;
31
+ status: 401;
32
+ sessionState: BarrierSessionMarker;
33
+ /** True only for a failure (a repaired read is news for an inspector, not a repair queue). */
34
+ durable: boolean;
35
+ }
36
+ interface RefusalLike {
37
+ error?: {
38
+ code?: string;
39
+ message?: string;
40
+ } | null;
41
+ status?: number;
42
+ }
43
+ /** The slice of `client.auth` the barrier binds to. */
44
+ interface BarrierAuth {
45
+ getSession(): Promise<{
46
+ data: {
47
+ session: {
48
+ access_token?: string;
49
+ } | null;
50
+ };
51
+ error: unknown;
52
+ }>;
53
+ onAuthStateChange(callback: (event: string, session: unknown) => void): unknown;
54
+ getClaims?: (jwt?: string, options?: {
55
+ jwks?: {
56
+ keys: any[];
57
+ };
58
+ }) => Promise<{
59
+ data: unknown;
60
+ error: {
61
+ name?: string;
62
+ code?: string;
63
+ status?: number;
64
+ message?: string;
65
+ } | null;
66
+ }>;
67
+ signOut?: (options: {
68
+ scope: "local";
69
+ }) => Promise<unknown>;
70
+ }
71
+ interface SessionBarrierOptions {
72
+ /** Record an announcement (Error Inspector / durable repair queue). */
73
+ report(event: BarrierReport): void;
74
+ /** Doors that serve a guest honestly: a 42501 there is a real refusal, never retried. */
75
+ isAnonymousByDesign?(schema: string | undefined, relation: string | undefined): boolean;
76
+ /** The one door that must never wait (the error sink). */
77
+ bypassesSessionWait?(relation: string | undefined): boolean;
78
+ /** End a session the database can never verify on this device and send the person to sign in. */
79
+ endUnverifiable?(auth: {
80
+ signOut: NonNullable<BarrierAuth["signOut"]>;
81
+ }, where: {
82
+ door: string;
83
+ via: "postgrest" | "claims";
84
+ }): Promise<void>;
85
+ /** Stamp every capture in the host with `sessionStateMarker()` (a probe, so the store needs no import). */
86
+ setSessionStateProbe?(probe: (() => BarrierSessionMarker) | null): void;
87
+ /** URL the client talks to — decides which pinned signing keys confirm "unverifiable". */
88
+ supabaseUrl?: string | null | undefined;
89
+ attachBudgetMs?: number;
90
+ recoveryBudgetMs?: number;
91
+ waitCooldownMs?: number;
92
+ /** Where the cookie string comes from; `null` = cannot tell. Default: `document.cookie`, `null` when unreadable. */
93
+ readCookie?(): string | null;
94
+ /** Browser-only gate. Default: `typeof window !== "undefined"`. */
95
+ isBrowser?(): boolean;
96
+ now?(): number;
97
+ warn?(message: string): void;
98
+ }
99
+ interface SessionBarrier {
100
+ install(client: unknown): void;
101
+ reset(): void;
102
+ /** Drive the signal without a client (tests, or a host that hears auth elsewhere). */
103
+ announceSession(present: boolean | null): void;
104
+ authCookiePresent(): boolean | null;
105
+ sessionStateNow(): BarrierSessionState;
106
+ sessionStateMarker(): BarrierSessionMarker;
107
+ hasAttachedSession(): boolean;
108
+ whenSessionAttached(listener: () => void): () => void;
109
+ canSendImmediately(ctx: BarrierCallContext): boolean;
110
+ awaitSessionBeforeSend(ctx: BarrierCallContext): Promise<void>;
111
+ isSessionRefusal(result: RefusalLike): boolean;
112
+ shouldRecoverSession(ctx: BarrierCallContext): boolean;
113
+ endSessionIfUnverifiable(ctx: BarrierCallContext, result: RefusalLike): Promise<boolean>;
114
+ recoverSessionForRetry(ctx: BarrierCallContext): Promise<boolean>;
115
+ reportSessionRetryOutcome(ctx: BarrierCallContext, retried: RefusalLike): void;
116
+ }
117
+ /**
118
+ * Is this result the database saying "your request carried no identity"? The discriminator is HTTP 401:
119
+ * a 42501 at 403 is a REAL grant gap for `authenticated` and must never be retried.
120
+ */
121
+ declare function isSessionRefusal(result: RefusalLike): boolean;
122
+ /** One barrier per browser client (module scope in the host is the tab). */
123
+ declare function createSessionBarrier(options: SessionBarrierOptions): SessionBarrier;
124
+
9
125
  /**
10
126
  * `createAuthClient` — the one Supabase client factory OUTSIDE Next.js (Next apps use
11
127
  * `@ai-matrx/auth/next`, whose cookie clients carry the domain-wide auth cookie).
@@ -36,4 +152,44 @@ declare class SecretKeyRefusedError extends Error {
36
152
  }
37
153
  declare function createAuthClient<Database = any>(options: CreateAuthClientOptions): SupabaseClient<Database>;
38
154
 
39
- export { type CreateAuthClientOptions, SecretKeyRefusedError, SessionStorage, createAuthClient };
155
+ /**
156
+ * An app that signs in with "Sign in with AI Matrx" (`createMatrxOAuth`) keeps its OWN session; it
157
+ * has no GoTrue session behind its Supabase client (the extension's client reads its bearer through
158
+ * supabase-js's `accessToken` hook, and `client.auth` on such a client throws). The session doors
159
+ * (`getSession`, `getPerson`, `onSessionChange`), `useSession` and the active organization all read
160
+ * `client.auth`. These two helpers give them one, built from the OAuth client:
161
+ *
162
+ * const oauth = createMatrxOAuth(config, ports);
163
+ * const client = withOAuthSession(supabaseWithAccessTokenHook, oauth); // db + a real `auth`
164
+ * const { session } = useSession(client);
165
+ * const active = createActiveOrganization({ client, held: heldOrganizationInStorage(extensionStorage(chrome.storage.session)) });
166
+ *
167
+ * The `auth` is the slice those doors use: `getSession`, `getUser`, `refreshSession`, `signOut`,
168
+ * `onAuthStateChange`. Password / OAuth-provider sign-in and profile edits are not part of it and
169
+ * refuse by name.
170
+ */
171
+
172
+ interface OAuthAuthClientOptions {
173
+ /**
174
+ * The person for an access token. Default: built locally from the token's claims (id, email) with
175
+ * no network. Pass the host's verified read (the extension's JWKS claims check) to return
176
+ * more fields; return null for "this token is not a person" (signed out).
177
+ */
178
+ readonly readUser?: ((accessToken: string) => Promise<User | null>) | undefined;
179
+ }
180
+ /** `{ auth }` for the session doors, backed by an OAuth client's own session. */
181
+ declare function oauthAuthClient(oauth: MatrxOAuthClient, options?: OAuthAuthClientOptions): AuthClient;
182
+ /**
183
+ * The data client (any supabase-js client: `rpc`, `schema`, `from`) with the OAuth session as its
184
+ * `auth`. Nothing is read from the client's own `auth` (which throws on an `accessToken`-hook
185
+ * client).
186
+ */
187
+ declare function withOAuthSession<C extends object>(db: C, oauth: MatrxOAuthClient, options?: OAuthAuthClientOptions): C & AuthClient;
188
+ /**
189
+ * A held-organization store over any async {@link SessionStorage} (identity-keyed): the extension's
190
+ * `chrome.storage.session` / `.local` through `extensionStorage(area)`. A stored choice for a
191
+ * different person reads as none.
192
+ */
193
+ declare function heldOrganizationInStorage(storage: SessionStorage, key?: string): HeldOrganizationStore;
194
+
195
+ export { AuthClient, type BarrierAuth, type BarrierCallContext, type BarrierReport, type BarrierSessionMarker, type BarrierSessionState, type CreateAuthClientOptions, type OAuthAuthClientOptions, type RefusalLike, SESSION_ATTACH_BUDGET_MS, SESSION_RECOVERY_BUDGET_MS, SecretKeyRefusedError, type SessionBarrier, type SessionBarrierOptions, SessionStorage, WAIT_COOLDOWN_MS, createAuthClient, createSessionBarrier, heldOrganizationInStorage, isSessionRefusal, oauthAuthClient, withOAuthSession };