@preclaim/core 0.1.0 → 0.2.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.
package/dist/config.d.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  import type { PreclaimConfig, PreclaimCredentials } from './types.js';
2
+ export declare function getSupabaseConfig(): {
3
+ url: string;
4
+ anonKey: string;
5
+ };
2
6
  export declare function findConfig(startDir?: string): Promise<{
3
7
  config: PreclaimConfig;
4
8
  configPath: string;
@@ -6,4 +10,6 @@ export declare function findConfig(startDir?: string): Promise<{
6
10
  export declare function getCredentialsPath(): string;
7
11
  export declare function loadCredentials(): Promise<PreclaimCredentials | null>;
8
12
  export declare function defaultConfig(projectId: string, backend: string): PreclaimConfig;
13
+ export declare function saveCredentials(creds: PreclaimCredentials): Promise<void>;
14
+ export declare function refreshCredentials(): Promise<PreclaimCredentials | null>;
9
15
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAMtE,wBAAsB,UAAU,CAAC,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAejI;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAO3E;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,CAShF"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAUtE,wBAAgB,iBAAiB;;;EAKhC;AAED,wBAAsB,UAAU,CAAC,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAejI;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAO3E;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,CAShF;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAI/E;AAGD,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CA0C9E"}
package/dist/config.js CHANGED
@@ -1,9 +1,18 @@
1
- import { readFile } from 'node:fs/promises';
2
- import { join } from 'node:path';
1
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
2
+ import { join, dirname } from 'node:path';
3
3
  import { homedir } from 'node:os';
4
4
  const CONFIG_FILENAME = '.preclaim.json';
5
5
  const CREDENTIALS_DIR = '.preclaim';
6
6
  const CREDENTIALS_FILENAME = 'credentials.json';
7
+ // Supabase config — env vars met fallback voor development
8
+ const DEFAULT_SUPABASE_URL = 'https://aawbukcvngdffueowjsa.supabase.co';
9
+ const DEFAULT_SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImFhd2J1a2N2bmdkZmZ1ZW93anNhIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzM3NjI2NTcsImV4cCI6MjA4OTMzODY1N30.pwAyjgnbdoZmmJdsG2jF0nbvT4hueb8UZvstsdYhFFs';
10
+ export function getSupabaseConfig() {
11
+ return {
12
+ url: process.env.PRECLAIM_SUPABASE_URL ?? DEFAULT_SUPABASE_URL,
13
+ anonKey: process.env.PRECLAIM_SUPABASE_ANON_KEY ?? DEFAULT_SUPABASE_ANON_KEY,
14
+ };
15
+ }
7
16
  export async function findConfig(startDir = process.cwd()) {
8
17
  let dir = startDir;
9
18
  const root = '/';
@@ -41,4 +50,45 @@ export function defaultConfig(projectId, backend) {
41
50
  ignore: ['*.md', 'package-lock.json', '*.test.ts'],
42
51
  };
43
52
  }
53
+ export async function saveCredentials(creds) {
54
+ const credPath = getCredentialsPath();
55
+ await mkdir(dirname(credPath), { recursive: true });
56
+ await writeFile(credPath, JSON.stringify(creds, null, 2) + '\n', { mode: 0o600 });
57
+ }
58
+ // Token refresh via Supabase REST API
59
+ export async function refreshCredentials() {
60
+ const creds = await loadCredentials();
61
+ if (!creds?.refreshToken)
62
+ return null;
63
+ const { url, anonKey } = getSupabaseConfig();
64
+ try {
65
+ const res = await fetch(`${url}/auth/v1/token?grant_type=refresh_token`, {
66
+ method: 'POST',
67
+ headers: {
68
+ 'Content-Type': 'application/json',
69
+ 'apikey': anonKey,
70
+ },
71
+ body: JSON.stringify({ refresh_token: creds.refreshToken }),
72
+ signal: AbortSignal.timeout(5000),
73
+ });
74
+ if (!res.ok)
75
+ return null;
76
+ const data = await res.json();
77
+ const refreshed = {
78
+ accessToken: data.access_token,
79
+ refreshToken: data.refresh_token,
80
+ expiresAt: new Date(Date.now() + data.expires_in * 1000).toISOString(),
81
+ user: {
82
+ id: data.user.id,
83
+ email: data.user.email ?? creds.user.email,
84
+ orgId: creds.user.orgId,
85
+ },
86
+ };
87
+ await saveCredentials(refreshed);
88
+ return refreshed;
89
+ }
90
+ catch {
91
+ return null;
92
+ }
93
+ }
44
94
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,MAAM,eAAe,GAAG,gBAAgB,CAAC;AACzC,MAAM,eAAe,GAAG,WAAW,CAAC;AACpC,MAAM,oBAAoB,GAAG,kBAAkB,CAAC;AAEhD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,WAAmB,OAAO,CAAC,GAAG,EAAE;IAC/D,IAAI,GAAG,GAAG,QAAQ,CAAC;IACnB,MAAM,IAAI,GAAG,GAAG,CAAC;IAEjB,OAAO,GAAG,KAAK,IAAI,EAAE,CAAC;QACpB,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;QAC9C,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAChD,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmB,EAAE,UAAU,EAAE,CAAC;QACnE,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,eAAe,EAAE,oBAAoB,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,kBAAkB,EAAE,EAAE,OAAO,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAwB,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,SAAiB,EAAE,OAAe;IAC9D,OAAO;QACL,OAAO,EAAE,CAAC;QACV,SAAS;QACT,OAAO;QACP,GAAG,EAAE,EAAE;QACP,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,CAAC,MAAM,EAAE,mBAAmB,EAAE,WAAW,CAAC;KACnD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=config.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.d.ts","sourceRoot":"","sources":["../src/config.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,57 @@
1
+ import { describe, it, expect, afterEach, vi } from 'vitest';
2
+ import { resolve, relative } from 'node:path';
3
+ // Path normalization logic (extracted for testing)
4
+ function normalizeLockPath(filePath, projectRoot) {
5
+ const absolutePath = resolve(projectRoot, filePath);
6
+ return relative(projectRoot, absolutePath);
7
+ }
8
+ describe('normalizeLockPath', () => {
9
+ it('converts absolute path to relative', () => {
10
+ const result = normalizeLockPath('/Users/paul/project/src/file.ts', '/Users/paul/project');
11
+ expect(result).toBe('src/file.ts');
12
+ });
13
+ it('keeps relative path as-is', () => {
14
+ const result = normalizeLockPath('src/file.ts', '/Users/paul/project');
15
+ expect(result).toBe('src/file.ts');
16
+ });
17
+ it('normalizes double slashes', () => {
18
+ const result = normalizeLockPath('src//utils//file.ts', '/Users/paul/project');
19
+ expect(result).toBe('src/utils/file.ts');
20
+ });
21
+ it('normalizes parent traversals', () => {
22
+ const result = normalizeLockPath('src/../lib/file.ts', '/Users/paul/project');
23
+ expect(result).toBe('lib/file.ts');
24
+ });
25
+ it('absolute and relative resolve to same path', () => {
26
+ const root = '/Users/paul/project';
27
+ const fromAbsolute = normalizeLockPath('/Users/paul/project/src/file.ts', root);
28
+ const fromRelative = normalizeLockPath('src/file.ts', root);
29
+ expect(fromAbsolute).toBe(fromRelative);
30
+ });
31
+ });
32
+ describe('getSupabaseConfig', () => {
33
+ const originalEnv = process.env;
34
+ afterEach(() => {
35
+ process.env = originalEnv;
36
+ vi.resetModules();
37
+ });
38
+ it('returns default values when env vars are not set', async () => {
39
+ const { getSupabaseConfig } = await import('./config.js');
40
+ const config = getSupabaseConfig();
41
+ expect(config.url).toContain('supabase.co');
42
+ expect(config.anonKey).toBeTruthy();
43
+ });
44
+ it('uses env vars when set', async () => {
45
+ process.env = {
46
+ ...originalEnv,
47
+ PRECLAIM_SUPABASE_URL: 'https://staging.supabase.co',
48
+ PRECLAIM_SUPABASE_ANON_KEY: 'test-key',
49
+ };
50
+ vi.resetModules();
51
+ const { getSupabaseConfig } = await import('./config.js');
52
+ const config = getSupabaseConfig();
53
+ expect(config.url).toBe('https://staging.supabase.co');
54
+ expect(config.anonKey).toBe('test-key');
55
+ });
56
+ });
57
+ //# sourceMappingURL=config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.js","sourceRoot":"","sources":["../src/config.test.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { PreclaimClient } from './client.js';
2
- export { findConfig, loadCredentials, getCredentialsPath, defaultConfig } from './config.js';
2
+ export { findConfig, loadCredentials, getCredentialsPath, defaultConfig, getSupabaseConfig, saveCredentials, refreshCredentials } from './config.js';
3
3
  export type { Organization, Profile, Project, Session, Lock, LockHolder, LockHistoryEntry, ClaimStatus, ClaimResult, ClaimRequest, BatchCheckRequest, BatchCheckResult, HeartbeatRequest, HeartbeatResult, SessionRegisterRequest, ReleaseRequest, ReleaseResult, PreclaimConfig, PreclaimCredentials, ApiResponse, HookInput, HookResult, } from './types.js';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC7F,YAAY,EACV,YAAY,EACZ,OAAO,EACP,OAAO,EACP,OAAO,EACP,IAAI,EACJ,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,sBAAsB,EACtB,cAAc,EACd,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,WAAW,EACX,SAAS,EACT,UAAU,GACX,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,kBAAkB,EAAE,aAAa,EAAE,iBAAiB,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACrJ,YAAY,EACV,YAAY,EACZ,OAAO,EACP,OAAO,EACP,OAAO,EACP,IAAI,EACJ,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,sBAAsB,EACtB,cAAc,EACd,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,WAAW,EACX,SAAS,EACT,UAAU,GACX,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  export { PreclaimClient } from './client.js';
2
- export { findConfig, loadCredentials, getCredentialsPath, defaultConfig } from './config.js';
2
+ export { findConfig, loadCredentials, getCredentialsPath, defaultConfig, getSupabaseConfig, saveCredentials, refreshCredentials } from './config.js';
3
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,kBAAkB,EAAE,aAAa,EAAE,iBAAiB,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@preclaim/core",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -0,0 +1,66 @@
1
+ import { describe, it, expect, afterEach, vi } from 'vitest';
2
+ import { resolve, relative } from 'node:path';
3
+
4
+ // Path normalization logic (extracted for testing)
5
+ function normalizeLockPath(filePath: string, projectRoot: string): string {
6
+ const absolutePath = resolve(projectRoot, filePath);
7
+ return relative(projectRoot, absolutePath);
8
+ }
9
+
10
+ describe('normalizeLockPath', () => {
11
+ it('converts absolute path to relative', () => {
12
+ const result = normalizeLockPath('/Users/paul/project/src/file.ts', '/Users/paul/project');
13
+ expect(result).toBe('src/file.ts');
14
+ });
15
+
16
+ it('keeps relative path as-is', () => {
17
+ const result = normalizeLockPath('src/file.ts', '/Users/paul/project');
18
+ expect(result).toBe('src/file.ts');
19
+ });
20
+
21
+ it('normalizes double slashes', () => {
22
+ const result = normalizeLockPath('src//utils//file.ts', '/Users/paul/project');
23
+ expect(result).toBe('src/utils/file.ts');
24
+ });
25
+
26
+ it('normalizes parent traversals', () => {
27
+ const result = normalizeLockPath('src/../lib/file.ts', '/Users/paul/project');
28
+ expect(result).toBe('lib/file.ts');
29
+ });
30
+
31
+ it('absolute and relative resolve to same path', () => {
32
+ const root = '/Users/paul/project';
33
+ const fromAbsolute = normalizeLockPath('/Users/paul/project/src/file.ts', root);
34
+ const fromRelative = normalizeLockPath('src/file.ts', root);
35
+ expect(fromAbsolute).toBe(fromRelative);
36
+ });
37
+ });
38
+
39
+ describe('getSupabaseConfig', () => {
40
+ const originalEnv = process.env;
41
+
42
+ afterEach(() => {
43
+ process.env = originalEnv;
44
+ vi.resetModules();
45
+ });
46
+
47
+ it('returns default values when env vars are not set', async () => {
48
+ const { getSupabaseConfig } = await import('./config.js');
49
+ const config = getSupabaseConfig();
50
+ expect(config.url).toContain('supabase.co');
51
+ expect(config.anonKey).toBeTruthy();
52
+ });
53
+
54
+ it('uses env vars when set', async () => {
55
+ process.env = {
56
+ ...originalEnv,
57
+ PRECLAIM_SUPABASE_URL: 'https://staging.supabase.co',
58
+ PRECLAIM_SUPABASE_ANON_KEY: 'test-key',
59
+ };
60
+ vi.resetModules();
61
+ const { getSupabaseConfig } = await import('./config.js');
62
+ const config = getSupabaseConfig();
63
+ expect(config.url).toBe('https://staging.supabase.co');
64
+ expect(config.anonKey).toBe('test-key');
65
+ });
66
+ });
package/src/config.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { readFile } from 'node:fs/promises';
2
- import { join } from 'node:path';
1
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
2
+ import { join, dirname } from 'node:path';
3
3
  import { homedir } from 'node:os';
4
4
  import type { PreclaimConfig, PreclaimCredentials } from './types.js';
5
5
 
@@ -7,6 +7,17 @@ const CONFIG_FILENAME = '.preclaim.json';
7
7
  const CREDENTIALS_DIR = '.preclaim';
8
8
  const CREDENTIALS_FILENAME = 'credentials.json';
9
9
 
10
+ // Supabase config — env vars met fallback voor development
11
+ const DEFAULT_SUPABASE_URL = 'https://aawbukcvngdffueowjsa.supabase.co';
12
+ const DEFAULT_SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImFhd2J1a2N2bmdkZmZ1ZW93anNhIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzM3NjI2NTcsImV4cCI6MjA4OTMzODY1N30.pwAyjgnbdoZmmJdsG2jF0nbvT4hueb8UZvstsdYhFFs';
13
+
14
+ export function getSupabaseConfig() {
15
+ return {
16
+ url: process.env.PRECLAIM_SUPABASE_URL ?? DEFAULT_SUPABASE_URL,
17
+ anonKey: process.env.PRECLAIM_SUPABASE_ANON_KEY ?? DEFAULT_SUPABASE_ANON_KEY,
18
+ };
19
+ }
20
+
10
21
  export async function findConfig(startDir: string = process.cwd()): Promise<{ config: PreclaimConfig; configPath: string } | null> {
11
22
  let dir = startDir;
12
23
  const root = '/';
@@ -47,3 +58,54 @@ export function defaultConfig(projectId: string, backend: string): PreclaimConfi
47
58
  ignore: ['*.md', 'package-lock.json', '*.test.ts'],
48
59
  };
49
60
  }
61
+
62
+ export async function saveCredentials(creds: PreclaimCredentials): Promise<void> {
63
+ const credPath = getCredentialsPath();
64
+ await mkdir(dirname(credPath), { recursive: true });
65
+ await writeFile(credPath, JSON.stringify(creds, null, 2) + '\n', { mode: 0o600 });
66
+ }
67
+
68
+ // Token refresh via Supabase REST API
69
+ export async function refreshCredentials(): Promise<PreclaimCredentials | null> {
70
+ const creds = await loadCredentials();
71
+ if (!creds?.refreshToken) return null;
72
+
73
+ const { url, anonKey } = getSupabaseConfig();
74
+
75
+ try {
76
+ const res = await fetch(`${url}/auth/v1/token?grant_type=refresh_token`, {
77
+ method: 'POST',
78
+ headers: {
79
+ 'Content-Type': 'application/json',
80
+ 'apikey': anonKey,
81
+ },
82
+ body: JSON.stringify({ refresh_token: creds.refreshToken }),
83
+ signal: AbortSignal.timeout(5000),
84
+ });
85
+
86
+ if (!res.ok) return null;
87
+
88
+ const data = await res.json() as {
89
+ access_token: string;
90
+ refresh_token: string;
91
+ expires_in: number;
92
+ user: { id: string; email?: string };
93
+ };
94
+
95
+ const refreshed: PreclaimCredentials = {
96
+ accessToken: data.access_token,
97
+ refreshToken: data.refresh_token,
98
+ expiresAt: new Date(Date.now() + data.expires_in * 1000).toISOString(),
99
+ user: {
100
+ id: data.user.id,
101
+ email: data.user.email ?? creds.user.email,
102
+ orgId: creds.user.orgId,
103
+ },
104
+ };
105
+
106
+ await saveCredentials(refreshed);
107
+ return refreshed;
108
+ } catch {
109
+ return null;
110
+ }
111
+ }
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { PreclaimClient } from './client.js';
2
- export { findConfig, loadCredentials, getCredentialsPath, defaultConfig } from './config.js';
2
+ export { findConfig, loadCredentials, getCredentialsPath, defaultConfig, getSupabaseConfig, saveCredentials, refreshCredentials } from './config.js';
3
3
  export type {
4
4
  Organization,
5
5
  Profile,