@ankhorage/auth-supabase 0.0.0-stage → 2.0.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 (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +22 -2
  3. package/dist/authConfiguration.d.ts +15 -0
  4. package/dist/authConfiguration.d.ts.map +1 -0
  5. package/dist/authConfiguration.js +69 -0
  6. package/dist/authConfiguration.js.map +1 -0
  7. package/dist/authPasswordOperations.d.ts +10 -0
  8. package/dist/authPasswordOperations.d.ts.map +1 -0
  9. package/dist/authPasswordOperations.js +163 -0
  10. package/dist/authPasswordOperations.js.map +1 -0
  11. package/dist/authSessionContext.d.ts +19 -0
  12. package/dist/authSessionContext.d.ts.map +1 -0
  13. package/dist/authSessionContext.js +96 -0
  14. package/dist/authSessionContext.js.map +1 -0
  15. package/dist/authSessionOperations.d.ts +7 -0
  16. package/dist/authSessionOperations.d.ts.map +1 -0
  17. package/dist/authSessionOperations.js +79 -0
  18. package/dist/authSessionOperations.js.map +1 -0
  19. package/dist/createSupabaseAuthAdapter.d.ts +5 -0
  20. package/dist/createSupabaseAuthAdapter.d.ts.map +1 -0
  21. package/dist/createSupabaseAuthAdapter.js +76 -0
  22. package/dist/createSupabaseAuthAdapter.js.map +1 -0
  23. package/dist/errors.d.ts +7 -0
  24. package/dist/errors.d.ts.map +1 -0
  25. package/dist/errors.js +89 -0
  26. package/dist/errors.js.map +1 -0
  27. package/dist/index.d.ts +8 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +6 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/oauth.d.ts +5 -0
  32. package/dist/oauth.d.ts.map +1 -0
  33. package/dist/oauth.js +34 -0
  34. package/dist/oauth.js.map +1 -0
  35. package/dist/oauthAttemptId.d.ts +9 -0
  36. package/dist/oauthAttemptId.d.ts.map +1 -0
  37. package/dist/oauthAttemptId.js +51 -0
  38. package/dist/oauthAttemptId.js.map +1 -0
  39. package/dist/oauthCallback.d.ts +23 -0
  40. package/dist/oauthCallback.d.ts.map +1 -0
  41. package/dist/oauthCallback.js +81 -0
  42. package/dist/oauthCallback.js.map +1 -0
  43. package/dist/oauthComplete.d.ts +5 -0
  44. package/dist/oauthComplete.d.ts.map +1 -0
  45. package/dist/oauthComplete.js +133 -0
  46. package/dist/oauthComplete.js.map +1 -0
  47. package/dist/oauthCompletionState.d.ts +13 -0
  48. package/dist/oauthCompletionState.d.ts.map +1 -0
  49. package/dist/oauthCompletionState.js +25 -0
  50. package/dist/oauthCompletionState.js.map +1 -0
  51. package/dist/oauthErrors.d.ts +9 -0
  52. package/dist/oauthErrors.d.ts.map +1 -0
  53. package/dist/oauthErrors.js +87 -0
  54. package/dist/oauthErrors.js.map +1 -0
  55. package/dist/oauthExchange.d.ts +14 -0
  56. package/dist/oauthExchange.d.ts.map +1 -0
  57. package/dist/oauthExchange.js +100 -0
  58. package/dist/oauthExchange.js.map +1 -0
  59. package/dist/oauthLifecycle.d.ts +8 -0
  60. package/dist/oauthLifecycle.d.ts.map +1 -0
  61. package/dist/oauthLifecycle.js +24 -0
  62. package/dist/oauthLifecycle.js.map +1 -0
  63. package/dist/oauthProviderDefinitions.d.ts +77 -0
  64. package/dist/oauthProviderDefinitions.d.ts.map +1 -0
  65. package/dist/oauthProviderDefinitions.js +114 -0
  66. package/dist/oauthProviderDefinitions.js.map +1 -0
  67. package/dist/oauthRuntime.d.ts +23 -0
  68. package/dist/oauthRuntime.d.ts.map +1 -0
  69. package/dist/oauthRuntime.js +22 -0
  70. package/dist/oauthRuntime.js.map +1 -0
  71. package/dist/oauthSetupRequirements.d.ts +12 -0
  72. package/dist/oauthSetupRequirements.d.ts.map +1 -0
  73. package/dist/oauthSetupRequirements.js +39 -0
  74. package/dist/oauthSetupRequirements.js.map +1 -0
  75. package/dist/oauthStart.d.ts +4 -0
  76. package/dist/oauthStart.d.ts.map +1 -0
  77. package/dist/oauthStart.js +108 -0
  78. package/dist/oauthStart.js.map +1 -0
  79. package/dist/oauthStartSupport.d.ts +52 -0
  80. package/dist/oauthStartSupport.d.ts.map +1 -0
  81. package/dist/oauthStartSupport.js +137 -0
  82. package/dist/oauthStartSupport.js.map +1 -0
  83. package/dist/oauthStorage.d.ts +25 -0
  84. package/dist/oauthStorage.d.ts.map +1 -0
  85. package/dist/oauthStorage.js +146 -0
  86. package/dist/oauthStorage.js.map +1 -0
  87. package/dist/oauthTypes.d.ts +49 -0
  88. package/dist/oauthTypes.d.ts.map +1 -0
  89. package/dist/oauthTypes.js +6 -0
  90. package/dist/oauthTypes.js.map +1 -0
  91. package/dist/profileVerification.d.ts +24 -0
  92. package/dist/profileVerification.d.ts.map +1 -0
  93. package/dist/profileVerification.js +178 -0
  94. package/dist/profileVerification.js.map +1 -0
  95. package/dist/session.d.ts +6 -0
  96. package/dist/session.d.ts.map +1 -0
  97. package/dist/session.js +124 -0
  98. package/dist/session.js.map +1 -0
  99. package/dist/types.d.ts +63 -0
  100. package/dist/types.d.ts.map +1 -0
  101. package/dist/types.js +8 -0
  102. package/dist/types.js.map +1 -0
  103. package/package.json +70 -4
@@ -0,0 +1,124 @@
1
+ export function normalizeSupabaseSession(body, now = Date.now()) {
2
+ if (!isRecord(body))
3
+ return null;
4
+ const accessToken = stringValue(body.access_token);
5
+ const user = normalizeSupabaseUser(body.user);
6
+ if (accessToken === undefined || user === null)
7
+ return null;
8
+ const session = { accessToken, user };
9
+ const refreshToken = stringValue(body.refresh_token);
10
+ const tokenType = stringValue(body.token_type);
11
+ const expiresAt = normalizeExpiresAt(body.expires_at, body.expires_in, now);
12
+ if (refreshToken !== undefined)
13
+ session.refreshToken = refreshToken;
14
+ if (tokenType !== undefined)
15
+ session.tokenType = tokenType;
16
+ if (expiresAt !== undefined)
17
+ session.expiresAt = expiresAt;
18
+ return session;
19
+ }
20
+ export function normalizeSupabaseUser(body) {
21
+ if (!isRecord(body))
22
+ return null;
23
+ const id = stringValue(body.id);
24
+ if (id === undefined)
25
+ return null;
26
+ const metadata = mergeMetadata(body.user_metadata, body.raw_user_meta_data, body.app_metadata, body.raw_app_meta_data);
27
+ const user = { id };
28
+ const email = stringValue(body.email) ?? metadataString(metadata, ['email']);
29
+ const phone = stringValue(body.phone) ?? metadataString(metadata, ['phone']);
30
+ const username = metadataString(metadata, ['username', 'user_name', 'preferred_username']);
31
+ const displayName = metadataString(metadata, [
32
+ 'displayName',
33
+ 'display_name',
34
+ 'full_name',
35
+ 'name',
36
+ ]);
37
+ const avatarUrl = metadataString(metadata, ['avatarUrl', 'avatar_url', 'picture']);
38
+ if (email !== undefined)
39
+ user.email = email;
40
+ if (phone !== undefined)
41
+ user.phone = phone;
42
+ if (username !== undefined)
43
+ user.username = username;
44
+ if (displayName !== undefined)
45
+ user.displayName = displayName;
46
+ if (avatarUrl !== undefined)
47
+ user.avatarUrl = avatarUrl;
48
+ if (metadata !== undefined)
49
+ user.metadata = metadata;
50
+ return user;
51
+ }
52
+ export function parseStoredSession(value) {
53
+ if (value === null)
54
+ return null;
55
+ try {
56
+ const parsed = JSON.parse(value);
57
+ if (!isAuthSession(parsed))
58
+ return null;
59
+ return {
60
+ ...parsed,
61
+ ...(parsed.expiresAt !== undefined
62
+ ? { expiresAt: normalizeStoredExpiresAt(parsed.expiresAt) }
63
+ : {}),
64
+ };
65
+ }
66
+ catch {
67
+ return null;
68
+ }
69
+ }
70
+ export function isAuthSessionExpired(session, now = Date.now()) {
71
+ const expiresAt = session?.expiresAt;
72
+ return typeof expiresAt === 'number' && Number.isFinite(expiresAt) && expiresAt <= now;
73
+ }
74
+ function normalizeStoredExpiresAt(value) {
75
+ return value < 10_000_000_000 ? value * 1000 : value;
76
+ }
77
+ function normalizeExpiresAt(expiresAt, expiresIn, now) {
78
+ const directExpiresAt = numberValue(expiresAt);
79
+ if (directExpiresAt !== undefined)
80
+ return directExpiresAt < 10_000_000_000 ? directExpiresAt * 1000 : directExpiresAt;
81
+ const ttl = numberValue(expiresIn);
82
+ return ttl === undefined ? undefined : now + ttl * 1000;
83
+ }
84
+ function mergeMetadata(...values) {
85
+ const metadata = {};
86
+ for (const value of values)
87
+ if (isRecord(value))
88
+ Object.assign(metadata, value);
89
+ return Object.keys(metadata).length > 0 ? metadata : undefined;
90
+ }
91
+ function metadataString(metadata, keys) {
92
+ if (metadata === undefined)
93
+ return undefined;
94
+ for (const key of keys) {
95
+ const value = stringValue(Reflect.get(metadata, key));
96
+ if (value !== undefined)
97
+ return value;
98
+ }
99
+ return undefined;
100
+ }
101
+ function isAuthSession(value) {
102
+ if (!isRecord(value) || stringValue(value.accessToken) === undefined)
103
+ return false;
104
+ if (!isRecord(value.user) || stringValue(value.user.id) === undefined)
105
+ return false;
106
+ return (value.expiresAt === undefined ||
107
+ (typeof value.expiresAt === 'number' && Number.isFinite(value.expiresAt)));
108
+ }
109
+ function stringValue(value) {
110
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
111
+ }
112
+ function numberValue(value) {
113
+ if (typeof value === 'number' && Number.isFinite(value))
114
+ return value;
115
+ if (typeof value === 'string') {
116
+ const parsed = Number.parseInt(value, 10);
117
+ return Number.isFinite(parsed) ? parsed : undefined;
118
+ }
119
+ return undefined;
120
+ }
121
+ function isRecord(value) {
122
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
123
+ }
124
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AuthSession, AuthUser } from '@ankhorage/contracts/auth';\n\nexport function normalizeSupabaseSession(body: unknown, now = Date.now()): AuthSession | null {\n if (!isRecord(body)) return null;\n const accessToken = stringValue(body.access_token);\n const user = normalizeSupabaseUser(body.user);\n if (accessToken === undefined || user === null) return null;\n const session: AuthSession = { accessToken, user };\n const refreshToken = stringValue(body.refresh_token);\n const tokenType = stringValue(body.token_type);\n const expiresAt = normalizeExpiresAt(body.expires_at, body.expires_in, now);\n if (refreshToken !== undefined) session.refreshToken = refreshToken;\n if (tokenType !== undefined) session.tokenType = tokenType;\n if (expiresAt !== undefined) session.expiresAt = expiresAt;\n return session;\n}\n\nexport function normalizeSupabaseUser(body: unknown): AuthUser | null {\n if (!isRecord(body)) return null;\n const id = stringValue(body.id);\n if (id === undefined) return null;\n\n const metadata = mergeMetadata(\n body.user_metadata,\n body.raw_user_meta_data,\n body.app_metadata,\n body.raw_app_meta_data,\n );\n const user: AuthUser = { id };\n const email = stringValue(body.email) ?? metadataString(metadata, ['email']);\n const phone = stringValue(body.phone) ?? metadataString(metadata, ['phone']);\n const username = metadataString(metadata, ['username', 'user_name', 'preferred_username']);\n const displayName = metadataString(metadata, [\n 'displayName',\n 'display_name',\n 'full_name',\n 'name',\n ]);\n const avatarUrl = metadataString(metadata, ['avatarUrl', 'avatar_url', 'picture']);\n\n if (email !== undefined) user.email = email;\n if (phone !== undefined) user.phone = phone;\n if (username !== undefined) user.username = username;\n if (displayName !== undefined) user.displayName = displayName;\n if (avatarUrl !== undefined) user.avatarUrl = avatarUrl;\n if (metadata !== undefined) user.metadata = metadata;\n return user;\n}\n\nexport function parseStoredSession(value: string | null): AuthSession | null {\n if (value === null) return null;\n try {\n const parsed: unknown = JSON.parse(value);\n if (!isAuthSession(parsed)) return null;\n return {\n ...parsed,\n ...(parsed.expiresAt !== undefined\n ? { expiresAt: normalizeStoredExpiresAt(parsed.expiresAt) }\n : {}),\n };\n } catch {\n return null;\n }\n}\n\nexport function isAuthSessionExpired(\n session: AuthSession | null | undefined,\n now = Date.now(),\n): boolean {\n const expiresAt = session?.expiresAt;\n return typeof expiresAt === 'number' && Number.isFinite(expiresAt) && expiresAt <= now;\n}\n\nfunction normalizeStoredExpiresAt(value: number): number {\n return value < 10_000_000_000 ? value * 1000 : value;\n}\n\nfunction normalizeExpiresAt(\n expiresAt: unknown,\n expiresIn: unknown,\n now: number,\n): number | undefined {\n const directExpiresAt = numberValue(expiresAt);\n if (directExpiresAt !== undefined)\n return directExpiresAt < 10_000_000_000 ? directExpiresAt * 1000 : directExpiresAt;\n const ttl = numberValue(expiresIn);\n return ttl === undefined ? undefined : now + ttl * 1000;\n}\n\nfunction mergeMetadata(...values: unknown[]): Record<string, unknown> | undefined {\n const metadata: Record<string, unknown> = {};\n for (const value of values) if (isRecord(value)) Object.assign(metadata, value);\n return Object.keys(metadata).length > 0 ? metadata : undefined;\n}\n\nfunction metadataString(\n metadata: Record<string, unknown> | undefined,\n keys: readonly string[],\n): string | undefined {\n if (metadata === undefined) return undefined;\n for (const key of keys) {\n const value = stringValue(Reflect.get(metadata, key));\n if (value !== undefined) return value;\n }\n return undefined;\n}\n\nfunction isAuthSession(value: unknown): value is AuthSession {\n if (!isRecord(value) || stringValue(value.accessToken) === undefined) return false;\n if (!isRecord(value.user) || stringValue(value.user.id) === undefined) return false;\n return (\n value.expiresAt === undefined ||\n (typeof value.expiresAt === 'number' && Number.isFinite(value.expiresAt))\n );\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction numberValue(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (typeof value === 'string') {\n const parsed = Number.parseInt(value, 10);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"]}
@@ -0,0 +1,63 @@
1
+ import type { AuthOAuthErrorCode, AuthOAuthErrorStage, AuthOAuthProviderId, AuthSession } from '@ankhorage/contracts/auth';
2
+ export type SupabaseAuthFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
3
+ /** Returns cryptographically secure random bytes for OAuth PKCE verifier generation. */
4
+ export type SupabaseAuthRandomBytes = (length: number) => Uint8Array;
5
+ export interface SupabaseAuthStorage {
6
+ getItem(key: string): string | Promise<string | null> | null;
7
+ setItem(key: string, value: string): void | Promise<void>;
8
+ removeItem(key: string): void | Promise<void>;
9
+ }
10
+ export declare const SUPABASE_AUTH_PROFILE_FIELDS: readonly ["email", "displayName", "avatarUrl", "username", "phone"];
11
+ export type SupabaseAuthProfileField = (typeof SUPABASE_AUTH_PROFILE_FIELDS)[number];
12
+ export interface SupabaseAuthProfileVerificationConfig {
13
+ /** App-owned profile table generated by @ankhorage/infra. */
14
+ table: string;
15
+ /** Configured profile fields whose provider metadata should match when available. */
16
+ fields?: readonly SupabaseAuthProfileField[];
17
+ /** Number of reads used to allow the auth.users trigger to become visible through PostgREST. */
18
+ maxAttempts?: number;
19
+ /** Delay between profile reads. Use zero for deterministic tests. */
20
+ retryDelayMs?: number;
21
+ }
22
+ export interface SupabaseOAuthProfileVerificationInput {
23
+ correlationId: string;
24
+ provider: AuthOAuthProviderId;
25
+ session: AuthSession;
26
+ }
27
+ export type SupabaseOAuthProfileVerificationResult = {
28
+ ok: true;
29
+ } | {
30
+ ok: false;
31
+ message: string;
32
+ };
33
+ export type SupabaseOAuthProfileVerifier = (input: SupabaseOAuthProfileVerificationInput) => Promise<SupabaseOAuthProfileVerificationResult>;
34
+ export type SupabaseOAuthLifecycleStatus = 'started' | 'cancelled' | 'error' | 'profile_verified' | 'authenticated';
35
+ export interface SupabaseOAuthLifecycleEvent {
36
+ correlationId: string;
37
+ provider: AuthOAuthProviderId;
38
+ stage: AuthOAuthErrorStage;
39
+ status: SupabaseOAuthLifecycleStatus;
40
+ errorCode?: AuthOAuthErrorCode;
41
+ }
42
+ /**
43
+ * Receives metadata-only OAuth lifecycle events. Events never contain callback URLs,
44
+ * authorization codes, tokens, client secrets, private keys, or session payloads.
45
+ */
46
+ export type SupabaseOAuthLifecycleObserver = (event: SupabaseOAuthLifecycleEvent) => void | Promise<void>;
47
+ export interface SupabaseAuthConfig {
48
+ url: string;
49
+ anonKey: string;
50
+ fetch?: SupabaseAuthFetch;
51
+ storage?: SupabaseAuthStorage;
52
+ storageKey?: string;
53
+ oauthProviders?: readonly AuthOAuthProviderId[];
54
+ oauthRandomBytes?: SupabaseAuthRandomBytes;
55
+ profileVerification?: SupabaseAuthProfileVerificationConfig;
56
+ onOAuthLifecycleEvent?: SupabaseOAuthLifecycleObserver;
57
+ }
58
+ export type SupabaseAuthErrorCode = 'invalid_credentials' | 'missing_identifier' | 'missing_password' | 'missing_refresh_token' | 'network_error' | 'provider_error' | 'session_expired' | 'session_persistence_failed' | 'unsupported_identifier' | 'validation_error';
59
+ export interface SupabaseProviderErrorCause {
60
+ status?: number;
61
+ body?: unknown;
62
+ }
63
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,8 @@
1
+ export const SUPABASE_AUTH_PROFILE_FIELDS = [
2
+ 'email',
3
+ 'displayName',
4
+ 'avatarUrl',
5
+ 'username',
6
+ 'phone',
7
+ ];
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAkBA,MAAM,CAAC,MAAM,4BAA4B,GAAG;IAC1C,OAAO;IACP,aAAa;IACb,WAAW;IACX,UAAU;IACV,OAAO;CACC,CAAC","sourcesContent":["import type {\n AuthOAuthErrorCode,\n AuthOAuthErrorStage,\n AuthOAuthProviderId,\n AuthSession,\n} from '@ankhorage/contracts/auth';\n\nexport type SupabaseAuthFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n\n/** Returns cryptographically secure random bytes for OAuth PKCE verifier generation. */\nexport type SupabaseAuthRandomBytes = (length: number) => Uint8Array;\n\nexport interface SupabaseAuthStorage {\n getItem(key: string): string | Promise<string | null> | null;\n setItem(key: string, value: string): void | Promise<void>;\n removeItem(key: string): void | Promise<void>;\n}\n\nexport const SUPABASE_AUTH_PROFILE_FIELDS = [\n 'email',\n 'displayName',\n 'avatarUrl',\n 'username',\n 'phone',\n] as const;\nexport type SupabaseAuthProfileField = (typeof SUPABASE_AUTH_PROFILE_FIELDS)[number];\n\nexport interface SupabaseAuthProfileVerificationConfig {\n /** App-owned profile table generated by @ankhorage/infra. */\n table: string;\n /** Configured profile fields whose provider metadata should match when available. */\n fields?: readonly SupabaseAuthProfileField[];\n /** Number of reads used to allow the auth.users trigger to become visible through PostgREST. */\n maxAttempts?: number;\n /** Delay between profile reads. Use zero for deterministic tests. */\n retryDelayMs?: number;\n}\n\nexport interface SupabaseOAuthProfileVerificationInput {\n correlationId: string;\n provider: AuthOAuthProviderId;\n session: AuthSession;\n}\n\nexport type SupabaseOAuthProfileVerificationResult = { ok: true } | { ok: false; message: string };\n\nexport type SupabaseOAuthProfileVerifier = (\n input: SupabaseOAuthProfileVerificationInput,\n) => Promise<SupabaseOAuthProfileVerificationResult>;\n\nexport type SupabaseOAuthLifecycleStatus =\n 'started' | 'cancelled' | 'error' | 'profile_verified' | 'authenticated';\n\nexport interface SupabaseOAuthLifecycleEvent {\n correlationId: string;\n provider: AuthOAuthProviderId;\n stage: AuthOAuthErrorStage;\n status: SupabaseOAuthLifecycleStatus;\n errorCode?: AuthOAuthErrorCode;\n}\n\n/**\n * Receives metadata-only OAuth lifecycle events. Events never contain callback URLs,\n * authorization codes, tokens, client secrets, private keys, or session payloads.\n */\nexport type SupabaseOAuthLifecycleObserver = (\n event: SupabaseOAuthLifecycleEvent,\n) => void | Promise<void>;\n\nexport interface SupabaseAuthConfig {\n url: string;\n anonKey: string;\n fetch?: SupabaseAuthFetch;\n storage?: SupabaseAuthStorage;\n storageKey?: string;\n oauthProviders?: readonly AuthOAuthProviderId[];\n oauthRandomBytes?: SupabaseAuthRandomBytes;\n profileVerification?: SupabaseAuthProfileVerificationConfig;\n onOAuthLifecycleEvent?: SupabaseOAuthLifecycleObserver;\n}\n\nexport type SupabaseAuthErrorCode =\n | 'invalid_credentials'\n | 'missing_identifier'\n | 'missing_password'\n | 'missing_refresh_token'\n | 'network_error'\n | 'provider_error'\n | 'session_expired'\n | 'session_persistence_failed'\n | 'unsupported_identifier'\n | 'validation_error';\n\nexport interface SupabaseProviderErrorCause {\n status?: number;\n body?: unknown;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,72 @@
1
1
  {
2
2
  "name": "@ankhorage/auth-supabase",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "type": "module",
4
+ "version": "2.0.0",
5
+ "description": "Supabase adapter implementing the provider-neutral Ankhorage auth port.",
6
+ "homepage": "https://github.com/ankhorage/auth-supabase#readme",
7
+ "bugs": {
8
+ "url": "https://github.com/ankhorage/auth-supabase/issues"
9
+ },
10
+ "license": "MIT",
11
+ "main": "./dist/index.js",
12
+ "sideEffects": false,
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js"
18
+ }
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/ankhorage/auth-supabase.git"
23
+ },
24
+ "keywords": [
25
+ "adapter",
26
+ "ankhorage",
27
+ "auth",
28
+ "authentication",
29
+ "gotrue",
30
+ "oauth",
31
+ "secret-store",
32
+ "session",
33
+ "supabase",
34
+ "typescript"
35
+ ],
36
+ "files": [
37
+ "dist",
38
+ "README.md",
39
+ "LICENSE"
40
+ ],
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "scripts": {
45
+ "build": "rm -rf dist tsconfig.tsbuildinfo && bun x tsc -p tsconfig.json",
46
+ "changeset": "ankhorage-changeset",
47
+ "changeset:status": "ankhorage-changeset status --since=origin/main",
48
+ "docs": "paradox && ankhorage-prettier --write paradox README.md",
49
+ "lint": "ankhorage-eslint . --max-warnings=0",
50
+ "lint:fix": "ankhorage-eslint . --fix --max-warnings=0",
51
+ "format": "ankhorage-prettier --write .",
52
+ "format:check": "ankhorage-prettier --check .",
53
+ "prepack": "bun run build",
54
+ "test": "bun test src",
55
+ "typecheck": "bun x tsc --noEmit -p tsconfig.json",
56
+ "version-packages": "ankhorage-changeset version",
57
+ "knip:check": "ankhorage-knip"
58
+ },
59
+ "devDependencies": {
60
+ "@ankhorage/devtools": "^2.3.14",
61
+ "@ankhorage/paradox": "^0.3.3",
62
+ "@types/bun": "^1.4.2",
63
+ "@types/node": "^26.6.5",
64
+ "typescript": "^6.0.3"
65
+ },
66
+ "dependencies": {
67
+ "@ankhorage/auth": "^0.1.2",
68
+ "@ankhorage/contracts": "^25.2.0",
69
+ "@noble/hashes": "2.4.0"
70
+ },
71
+ "packageManager": "bun@1.4.2"
72
+ }