@preclaim/core 0.1.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/.turbo/turbo-build.log +4 -0
- package/dist/client.d.ts +22 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +78 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +44 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +132 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +23 -0
- package/src/client.ts +102 -0
- package/src/config.ts +49 -0
- package/src/index.ts +26 -0
- package/src/types.ts +163 -0
- package/tsconfig.json +8 -0
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ApiResponse, ClaimRequest, ClaimResult, BatchCheckRequest, BatchCheckResult, HeartbeatRequest, HeartbeatResult, SessionRegisterRequest, ReleaseRequest, ReleaseResult, Lock } from './types.js';
|
|
2
|
+
export declare class PreclaimClient {
|
|
3
|
+
private baseUrl;
|
|
4
|
+
private accessToken;
|
|
5
|
+
private timeoutMs;
|
|
6
|
+
constructor(opts: {
|
|
7
|
+
baseUrl: string;
|
|
8
|
+
accessToken: string;
|
|
9
|
+
timeoutMs?: number;
|
|
10
|
+
});
|
|
11
|
+
private request;
|
|
12
|
+
claimFile(req: ClaimRequest): Promise<ApiResponse<ClaimResult>>;
|
|
13
|
+
releaseLocks(req: ReleaseRequest): Promise<ApiResponse<ReleaseResult>>;
|
|
14
|
+
listLocks(projectId: string): Promise<ApiResponse<Lock[]>>;
|
|
15
|
+
batchCheck(req: BatchCheckRequest): Promise<ApiResponse<BatchCheckResult>>;
|
|
16
|
+
heartbeat(req: HeartbeatRequest): Promise<ApiResponse<HeartbeatResult>>;
|
|
17
|
+
registerSession(req: SessionRegisterRequest): Promise<ApiResponse<{
|
|
18
|
+
session_id: string;
|
|
19
|
+
}>>;
|
|
20
|
+
endSession(sessionId: string): Promise<ApiResponse<ReleaseResult>>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,sBAAsB,EACtB,cAAc,EACd,aAAa,EACb,IAAI,EACL,MAAM,YAAY,CAAC;AAEpB,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAS;gBAEd,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE;YAMhE,OAAO;IA+Bf,SAAS,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;IAO/D,YAAY,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;IAOtE,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;IAI1D,UAAU,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAO1E,SAAS,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;IAOvE,eAAe,CAAC,GAAG,EAAE,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAO1F,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;CAMzE"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export class PreclaimClient {
|
|
2
|
+
baseUrl;
|
|
3
|
+
accessToken;
|
|
4
|
+
timeoutMs;
|
|
5
|
+
constructor(opts) {
|
|
6
|
+
this.baseUrl = opts.baseUrl.replace(/\/$/, '');
|
|
7
|
+
this.accessToken = opts.accessToken;
|
|
8
|
+
this.timeoutMs = opts.timeoutMs ?? 5000;
|
|
9
|
+
}
|
|
10
|
+
async request(path, opts = {}) {
|
|
11
|
+
const start = Date.now();
|
|
12
|
+
const url = `${this.baseUrl}/api/v1${path}`;
|
|
13
|
+
try {
|
|
14
|
+
const res = await fetch(url, {
|
|
15
|
+
...opts,
|
|
16
|
+
headers: {
|
|
17
|
+
'Content-Type': 'application/json',
|
|
18
|
+
'Authorization': `Bearer ${this.accessToken}`,
|
|
19
|
+
...opts.headers,
|
|
20
|
+
},
|
|
21
|
+
signal: AbortSignal.timeout(this.timeoutMs),
|
|
22
|
+
});
|
|
23
|
+
if (!res.ok) {
|
|
24
|
+
const body = await res.text();
|
|
25
|
+
return { error: `HTTP ${res.status}: ${body}` };
|
|
26
|
+
}
|
|
27
|
+
const data = await res.json();
|
|
28
|
+
return { data };
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
const elapsed = Date.now() - start;
|
|
32
|
+
if (err instanceof Error && err.name === 'TimeoutError') {
|
|
33
|
+
return { error: `Request timeout after ${elapsed}ms` };
|
|
34
|
+
}
|
|
35
|
+
return { error: err instanceof Error ? err.message : 'Unknown error' };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async claimFile(req) {
|
|
39
|
+
return this.request('/locks', {
|
|
40
|
+
method: 'POST',
|
|
41
|
+
body: JSON.stringify(req),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async releaseLocks(req) {
|
|
45
|
+
return this.request('/locks', {
|
|
46
|
+
method: 'DELETE',
|
|
47
|
+
body: JSON.stringify(req),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
async listLocks(projectId) {
|
|
51
|
+
return this.request(`/locks?project_id=${projectId}`);
|
|
52
|
+
}
|
|
53
|
+
async batchCheck(req) {
|
|
54
|
+
return this.request('/locks/check', {
|
|
55
|
+
method: 'POST',
|
|
56
|
+
body: JSON.stringify(req),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async heartbeat(req) {
|
|
60
|
+
return this.request('/heartbeat', {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
body: JSON.stringify(req),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
async registerSession(req) {
|
|
66
|
+
return this.request('/sessions', {
|
|
67
|
+
method: 'POST',
|
|
68
|
+
body: JSON.stringify(req),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
async endSession(sessionId) {
|
|
72
|
+
return this.request('/sessions', {
|
|
73
|
+
method: 'DELETE',
|
|
74
|
+
body: JSON.stringify({ session_id: sessionId }),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PreclaimConfig, PreclaimCredentials } from './types.js';
|
|
2
|
+
export declare function findConfig(startDir?: string): Promise<{
|
|
3
|
+
config: PreclaimConfig;
|
|
4
|
+
configPath: string;
|
|
5
|
+
} | null>;
|
|
6
|
+
export declare function getCredentialsPath(): string;
|
|
7
|
+
export declare function loadCredentials(): Promise<PreclaimCredentials | null>;
|
|
8
|
+
export declare function defaultConfig(projectId: string, backend: string): PreclaimConfig;
|
|
9
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
const CONFIG_FILENAME = '.preclaim.json';
|
|
5
|
+
const CREDENTIALS_DIR = '.preclaim';
|
|
6
|
+
const CREDENTIALS_FILENAME = 'credentials.json';
|
|
7
|
+
export async function findConfig(startDir = process.cwd()) {
|
|
8
|
+
let dir = startDir;
|
|
9
|
+
const root = '/';
|
|
10
|
+
while (dir !== root) {
|
|
11
|
+
const configPath = join(dir, CONFIG_FILENAME);
|
|
12
|
+
try {
|
|
13
|
+
const raw = await readFile(configPath, 'utf-8');
|
|
14
|
+
return { config: JSON.parse(raw), configPath };
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
dir = join(dir, '..');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
export function getCredentialsPath() {
|
|
23
|
+
return join(homedir(), CREDENTIALS_DIR, CREDENTIALS_FILENAME);
|
|
24
|
+
}
|
|
25
|
+
export async function loadCredentials() {
|
|
26
|
+
try {
|
|
27
|
+
const raw = await readFile(getCredentialsPath(), 'utf-8');
|
|
28
|
+
return JSON.parse(raw);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function defaultConfig(projectId, backend) {
|
|
35
|
+
return {
|
|
36
|
+
version: 1,
|
|
37
|
+
projectId,
|
|
38
|
+
backend,
|
|
39
|
+
ttl: 30,
|
|
40
|
+
failOpen: true,
|
|
41
|
+
ignore: ['*.md', 'package-lock.json', '*.test.ts'],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { PreclaimClient } from './client.js';
|
|
2
|
+
export { findConfig, loadCredentials, getCredentialsPath, defaultConfig } from './config.js';
|
|
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
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
export interface Organization {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
slug: string;
|
|
5
|
+
created_at: string;
|
|
6
|
+
updated_at: string;
|
|
7
|
+
}
|
|
8
|
+
export interface Profile {
|
|
9
|
+
id: string;
|
|
10
|
+
email: string;
|
|
11
|
+
name: string | null;
|
|
12
|
+
avatar_url: string | null;
|
|
13
|
+
org_id: string | null;
|
|
14
|
+
role: 'admin' | 'member';
|
|
15
|
+
created_at: string;
|
|
16
|
+
}
|
|
17
|
+
export interface Project {
|
|
18
|
+
id: string;
|
|
19
|
+
org_id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
slug: string;
|
|
22
|
+
repo_url: string | null;
|
|
23
|
+
default_ttl: number;
|
|
24
|
+
created_at: string;
|
|
25
|
+
}
|
|
26
|
+
export interface Session {
|
|
27
|
+
id: string;
|
|
28
|
+
user_id: string;
|
|
29
|
+
project_id: string;
|
|
30
|
+
provider: string;
|
|
31
|
+
started_at: string;
|
|
32
|
+
last_heartbeat: string;
|
|
33
|
+
metadata: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
export interface Lock {
|
|
36
|
+
id: string;
|
|
37
|
+
project_id: string;
|
|
38
|
+
file_path: string;
|
|
39
|
+
session_id: string;
|
|
40
|
+
user_id: string;
|
|
41
|
+
acquired_at: string;
|
|
42
|
+
expires_at: string;
|
|
43
|
+
message: string | null;
|
|
44
|
+
}
|
|
45
|
+
export interface LockHolder {
|
|
46
|
+
user_id: string;
|
|
47
|
+
session_id: string;
|
|
48
|
+
acquired_at: string;
|
|
49
|
+
expires_at: string;
|
|
50
|
+
}
|
|
51
|
+
export interface LockHistoryEntry {
|
|
52
|
+
id: string;
|
|
53
|
+
project_id: string;
|
|
54
|
+
file_path: string;
|
|
55
|
+
user_id: string;
|
|
56
|
+
session_id: string;
|
|
57
|
+
provider: string;
|
|
58
|
+
action: 'acquire' | 'release' | 'expire' | 'force_release';
|
|
59
|
+
created_at: string;
|
|
60
|
+
}
|
|
61
|
+
export type ClaimStatus = 'acquired' | 'already_held' | 'conflict';
|
|
62
|
+
export interface ClaimResult {
|
|
63
|
+
status: ClaimStatus;
|
|
64
|
+
expires_at?: string;
|
|
65
|
+
holder?: LockHolder;
|
|
66
|
+
}
|
|
67
|
+
export interface ClaimRequest {
|
|
68
|
+
project_id: string;
|
|
69
|
+
file_path: string;
|
|
70
|
+
session_id: string;
|
|
71
|
+
ttl_minutes?: number;
|
|
72
|
+
}
|
|
73
|
+
export interface BatchCheckRequest {
|
|
74
|
+
project_id: string;
|
|
75
|
+
file_paths: string[];
|
|
76
|
+
}
|
|
77
|
+
export interface BatchCheckResult {
|
|
78
|
+
locks: Record<string, Lock | null>;
|
|
79
|
+
}
|
|
80
|
+
export interface HeartbeatRequest {
|
|
81
|
+
session_id: string;
|
|
82
|
+
}
|
|
83
|
+
export interface HeartbeatResult {
|
|
84
|
+
extended: number;
|
|
85
|
+
}
|
|
86
|
+
export interface SessionRegisterRequest {
|
|
87
|
+
session_id: string;
|
|
88
|
+
project_id: string;
|
|
89
|
+
provider?: string;
|
|
90
|
+
metadata?: Record<string, unknown>;
|
|
91
|
+
}
|
|
92
|
+
export interface ReleaseRequest {
|
|
93
|
+
project_id: string;
|
|
94
|
+
file_path?: string;
|
|
95
|
+
session_id: string;
|
|
96
|
+
}
|
|
97
|
+
export interface ReleaseResult {
|
|
98
|
+
released: number;
|
|
99
|
+
}
|
|
100
|
+
export interface PreclaimConfig {
|
|
101
|
+
version: number;
|
|
102
|
+
projectId: string;
|
|
103
|
+
backend: string;
|
|
104
|
+
ttl: number;
|
|
105
|
+
failOpen: boolean;
|
|
106
|
+
ignore: string[];
|
|
107
|
+
}
|
|
108
|
+
export interface PreclaimCredentials {
|
|
109
|
+
accessToken: string;
|
|
110
|
+
refreshToken: string;
|
|
111
|
+
expiresAt: string;
|
|
112
|
+
user: {
|
|
113
|
+
id: string;
|
|
114
|
+
email: string;
|
|
115
|
+
orgId: string;
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
export interface ApiResponse<T> {
|
|
119
|
+
data?: T;
|
|
120
|
+
error?: string;
|
|
121
|
+
}
|
|
122
|
+
export interface HookInput {
|
|
123
|
+
session_id: string;
|
|
124
|
+
tool_name?: string;
|
|
125
|
+
tool_input?: Record<string, unknown>;
|
|
126
|
+
}
|
|
127
|
+
export interface HookResult {
|
|
128
|
+
permissionDecision?: 'allow' | 'deny';
|
|
129
|
+
reason?: string;
|
|
130
|
+
systemMessage?: string;
|
|
131
|
+
}
|
|
132
|
+
//# 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 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@preclaim/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"dev": "tsc --watch",
|
|
16
|
+
"typecheck": "tsc --noEmit",
|
|
17
|
+
"clean": "rm -rf dist"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^22.0.0",
|
|
21
|
+
"typescript": "^5.8.0"
|
|
22
|
+
}
|
|
23
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ApiResponse,
|
|
3
|
+
ClaimRequest,
|
|
4
|
+
ClaimResult,
|
|
5
|
+
BatchCheckRequest,
|
|
6
|
+
BatchCheckResult,
|
|
7
|
+
HeartbeatRequest,
|
|
8
|
+
HeartbeatResult,
|
|
9
|
+
SessionRegisterRequest,
|
|
10
|
+
ReleaseRequest,
|
|
11
|
+
ReleaseResult,
|
|
12
|
+
Lock,
|
|
13
|
+
} from './types.js';
|
|
14
|
+
|
|
15
|
+
export class PreclaimClient {
|
|
16
|
+
private baseUrl: string;
|
|
17
|
+
private accessToken: string;
|
|
18
|
+
private timeoutMs: number;
|
|
19
|
+
|
|
20
|
+
constructor(opts: { baseUrl: string; accessToken: string; timeoutMs?: number }) {
|
|
21
|
+
this.baseUrl = opts.baseUrl.replace(/\/$/, '');
|
|
22
|
+
this.accessToken = opts.accessToken;
|
|
23
|
+
this.timeoutMs = opts.timeoutMs ?? 5000;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private async request<T>(path: string, opts: RequestInit = {}): Promise<ApiResponse<T>> {
|
|
27
|
+
const start = Date.now();
|
|
28
|
+
const url = `${this.baseUrl}/api/v1${path}`;
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const res = await fetch(url, {
|
|
32
|
+
...opts,
|
|
33
|
+
headers: {
|
|
34
|
+
'Content-Type': 'application/json',
|
|
35
|
+
'Authorization': `Bearer ${this.accessToken}`,
|
|
36
|
+
...opts.headers,
|
|
37
|
+
},
|
|
38
|
+
signal: AbortSignal.timeout(this.timeoutMs),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if (!res.ok) {
|
|
42
|
+
const body = await res.text();
|
|
43
|
+
return { error: `HTTP ${res.status}: ${body}` };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const data = await res.json() as T;
|
|
47
|
+
return { data };
|
|
48
|
+
} catch (err: unknown) {
|
|
49
|
+
const elapsed = Date.now() - start;
|
|
50
|
+
if (err instanceof Error && err.name === 'TimeoutError') {
|
|
51
|
+
return { error: `Request timeout after ${elapsed}ms` };
|
|
52
|
+
}
|
|
53
|
+
return { error: err instanceof Error ? err.message : 'Unknown error' };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async claimFile(req: ClaimRequest): Promise<ApiResponse<ClaimResult>> {
|
|
58
|
+
return this.request<ClaimResult>('/locks', {
|
|
59
|
+
method: 'POST',
|
|
60
|
+
body: JSON.stringify(req),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async releaseLocks(req: ReleaseRequest): Promise<ApiResponse<ReleaseResult>> {
|
|
65
|
+
return this.request<ReleaseResult>('/locks', {
|
|
66
|
+
method: 'DELETE',
|
|
67
|
+
body: JSON.stringify(req),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async listLocks(projectId: string): Promise<ApiResponse<Lock[]>> {
|
|
72
|
+
return this.request<Lock[]>(`/locks?project_id=${projectId}`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async batchCheck(req: BatchCheckRequest): Promise<ApiResponse<BatchCheckResult>> {
|
|
76
|
+
return this.request<BatchCheckResult>('/locks/check', {
|
|
77
|
+
method: 'POST',
|
|
78
|
+
body: JSON.stringify(req),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async heartbeat(req: HeartbeatRequest): Promise<ApiResponse<HeartbeatResult>> {
|
|
83
|
+
return this.request<HeartbeatResult>('/heartbeat', {
|
|
84
|
+
method: 'POST',
|
|
85
|
+
body: JSON.stringify(req),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async registerSession(req: SessionRegisterRequest): Promise<ApiResponse<{ session_id: string }>> {
|
|
90
|
+
return this.request<{ session_id: string }>('/sessions', {
|
|
91
|
+
method: 'POST',
|
|
92
|
+
body: JSON.stringify(req),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async endSession(sessionId: string): Promise<ApiResponse<ReleaseResult>> {
|
|
97
|
+
return this.request<ReleaseResult>('/sessions', {
|
|
98
|
+
method: 'DELETE',
|
|
99
|
+
body: JSON.stringify({ session_id: sessionId }),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import type { PreclaimConfig, PreclaimCredentials } from './types.js';
|
|
5
|
+
|
|
6
|
+
const CONFIG_FILENAME = '.preclaim.json';
|
|
7
|
+
const CREDENTIALS_DIR = '.preclaim';
|
|
8
|
+
const CREDENTIALS_FILENAME = 'credentials.json';
|
|
9
|
+
|
|
10
|
+
export async function findConfig(startDir: string = process.cwd()): Promise<{ config: PreclaimConfig; configPath: string } | null> {
|
|
11
|
+
let dir = startDir;
|
|
12
|
+
const root = '/';
|
|
13
|
+
|
|
14
|
+
while (dir !== root) {
|
|
15
|
+
const configPath = join(dir, CONFIG_FILENAME);
|
|
16
|
+
try {
|
|
17
|
+
const raw = await readFile(configPath, 'utf-8');
|
|
18
|
+
return { config: JSON.parse(raw) as PreclaimConfig, configPath };
|
|
19
|
+
} catch {
|
|
20
|
+
dir = join(dir, '..');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getCredentialsPath(): string {
|
|
28
|
+
return join(homedir(), CREDENTIALS_DIR, CREDENTIALS_FILENAME);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function loadCredentials(): Promise<PreclaimCredentials | null> {
|
|
32
|
+
try {
|
|
33
|
+
const raw = await readFile(getCredentialsPath(), 'utf-8');
|
|
34
|
+
return JSON.parse(raw) as PreclaimCredentials;
|
|
35
|
+
} catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function defaultConfig(projectId: string, backend: string): PreclaimConfig {
|
|
41
|
+
return {
|
|
42
|
+
version: 1,
|
|
43
|
+
projectId,
|
|
44
|
+
backend,
|
|
45
|
+
ttl: 30,
|
|
46
|
+
failOpen: true,
|
|
47
|
+
ignore: ['*.md', 'package-lock.json', '*.test.ts'],
|
|
48
|
+
};
|
|
49
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export { PreclaimClient } from './client.js';
|
|
2
|
+
export { findConfig, loadCredentials, getCredentialsPath, defaultConfig } from './config.js';
|
|
3
|
+
export type {
|
|
4
|
+
Organization,
|
|
5
|
+
Profile,
|
|
6
|
+
Project,
|
|
7
|
+
Session,
|
|
8
|
+
Lock,
|
|
9
|
+
LockHolder,
|
|
10
|
+
LockHistoryEntry,
|
|
11
|
+
ClaimStatus,
|
|
12
|
+
ClaimResult,
|
|
13
|
+
ClaimRequest,
|
|
14
|
+
BatchCheckRequest,
|
|
15
|
+
BatchCheckResult,
|
|
16
|
+
HeartbeatRequest,
|
|
17
|
+
HeartbeatResult,
|
|
18
|
+
SessionRegisterRequest,
|
|
19
|
+
ReleaseRequest,
|
|
20
|
+
ReleaseResult,
|
|
21
|
+
PreclaimConfig,
|
|
22
|
+
PreclaimCredentials,
|
|
23
|
+
ApiResponse,
|
|
24
|
+
HookInput,
|
|
25
|
+
HookResult,
|
|
26
|
+
} from './types.js';
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// === Organizations ===
|
|
2
|
+
export interface Organization {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
slug: string;
|
|
6
|
+
created_at: string;
|
|
7
|
+
updated_at: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// === Profiles ===
|
|
11
|
+
export interface Profile {
|
|
12
|
+
id: string;
|
|
13
|
+
email: string;
|
|
14
|
+
name: string | null;
|
|
15
|
+
avatar_url: string | null;
|
|
16
|
+
org_id: string | null;
|
|
17
|
+
role: 'admin' | 'member';
|
|
18
|
+
created_at: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// === Projects ===
|
|
22
|
+
export interface Project {
|
|
23
|
+
id: string;
|
|
24
|
+
org_id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
slug: string;
|
|
27
|
+
repo_url: string | null;
|
|
28
|
+
default_ttl: number;
|
|
29
|
+
created_at: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// === Sessions ===
|
|
33
|
+
export interface Session {
|
|
34
|
+
id: string;
|
|
35
|
+
user_id: string;
|
|
36
|
+
project_id: string;
|
|
37
|
+
provider: string;
|
|
38
|
+
started_at: string;
|
|
39
|
+
last_heartbeat: string;
|
|
40
|
+
metadata: Record<string, unknown>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// === Locks ===
|
|
44
|
+
export interface Lock {
|
|
45
|
+
id: string;
|
|
46
|
+
project_id: string;
|
|
47
|
+
file_path: string;
|
|
48
|
+
session_id: string;
|
|
49
|
+
user_id: string;
|
|
50
|
+
acquired_at: string;
|
|
51
|
+
expires_at: string;
|
|
52
|
+
message: string | null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface LockHolder {
|
|
56
|
+
user_id: string;
|
|
57
|
+
session_id: string;
|
|
58
|
+
acquired_at: string;
|
|
59
|
+
expires_at: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// === Lock History ===
|
|
63
|
+
export interface LockHistoryEntry {
|
|
64
|
+
id: string;
|
|
65
|
+
project_id: string;
|
|
66
|
+
file_path: string;
|
|
67
|
+
user_id: string;
|
|
68
|
+
session_id: string;
|
|
69
|
+
provider: string;
|
|
70
|
+
action: 'acquire' | 'release' | 'expire' | 'force_release';
|
|
71
|
+
created_at: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// === API Types ===
|
|
75
|
+
export type ClaimStatus = 'acquired' | 'already_held' | 'conflict';
|
|
76
|
+
|
|
77
|
+
export interface ClaimResult {
|
|
78
|
+
status: ClaimStatus;
|
|
79
|
+
expires_at?: string;
|
|
80
|
+
holder?: LockHolder;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface ClaimRequest {
|
|
84
|
+
project_id: string;
|
|
85
|
+
file_path: string;
|
|
86
|
+
session_id: string;
|
|
87
|
+
ttl_minutes?: number;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface BatchCheckRequest {
|
|
91
|
+
project_id: string;
|
|
92
|
+
file_paths: string[];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface BatchCheckResult {
|
|
96
|
+
locks: Record<string, Lock | null>;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface HeartbeatRequest {
|
|
100
|
+
session_id: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface HeartbeatResult {
|
|
104
|
+
extended: number;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface SessionRegisterRequest {
|
|
108
|
+
session_id: string;
|
|
109
|
+
project_id: string;
|
|
110
|
+
provider?: string;
|
|
111
|
+
metadata?: Record<string, unknown>;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface ReleaseRequest {
|
|
115
|
+
project_id: string;
|
|
116
|
+
file_path?: string;
|
|
117
|
+
session_id: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface ReleaseResult {
|
|
121
|
+
released: number;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// === Config ===
|
|
125
|
+
export interface PreclaimConfig {
|
|
126
|
+
version: number;
|
|
127
|
+
projectId: string;
|
|
128
|
+
backend: string;
|
|
129
|
+
ttl: number;
|
|
130
|
+
failOpen: boolean;
|
|
131
|
+
ignore: string[];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// === Credentials ===
|
|
135
|
+
export interface PreclaimCredentials {
|
|
136
|
+
accessToken: string;
|
|
137
|
+
refreshToken: string;
|
|
138
|
+
expiresAt: string;
|
|
139
|
+
user: {
|
|
140
|
+
id: string;
|
|
141
|
+
email: string;
|
|
142
|
+
orgId: string;
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// === API Response Wrapper ===
|
|
147
|
+
export interface ApiResponse<T> {
|
|
148
|
+
data?: T;
|
|
149
|
+
error?: string;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// === Hook Types ===
|
|
153
|
+
export interface HookInput {
|
|
154
|
+
session_id: string;
|
|
155
|
+
tool_name?: string;
|
|
156
|
+
tool_input?: Record<string, unknown>;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export interface HookResult {
|
|
160
|
+
permissionDecision?: 'allow' | 'deny';
|
|
161
|
+
reason?: string;
|
|
162
|
+
systemMessage?: string;
|
|
163
|
+
}
|