@pierre/storage 0.0.2 → 0.0.5
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/README.md +170 -0
- package/dist/index.cjs +170 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +133 -5
- package/dist/index.d.ts +133 -5
- package/dist/index.js +170 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +227 -23
- package/src/types.ts +148 -0
package/src/index.ts
CHANGED
|
@@ -5,6 +5,23 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { importPKCS8, SignJWT } from 'jose';
|
|
8
|
+
import type {
|
|
9
|
+
GetBranchDiffOptions,
|
|
10
|
+
GetBranchDiffResponse,
|
|
11
|
+
GetCommitDiffOptions,
|
|
12
|
+
GetCommitDiffResponse,
|
|
13
|
+
GetCommitOptions,
|
|
14
|
+
GetCommitResponse,
|
|
15
|
+
GetFileOptions,
|
|
16
|
+
GetFileResponse,
|
|
17
|
+
ListBranchesOptions,
|
|
18
|
+
ListBranchesResponse,
|
|
19
|
+
ListCommitsOptions,
|
|
20
|
+
ListCommitsResponse,
|
|
21
|
+
ListFilesOptions,
|
|
22
|
+
ListFilesResponse,
|
|
23
|
+
Repo,
|
|
24
|
+
} from './types';
|
|
8
25
|
|
|
9
26
|
/**
|
|
10
27
|
* Type definitions for Pierre Git Storage SDK
|
|
@@ -20,10 +37,7 @@ export interface GetRemoteURLOptions {
|
|
|
20
37
|
ttl?: number;
|
|
21
38
|
}
|
|
22
39
|
|
|
23
|
-
|
|
24
|
-
id: string;
|
|
25
|
-
getRemoteURL(options?: GetRemoteURLOptions): Promise<string>;
|
|
26
|
-
}
|
|
40
|
+
// Repo interface is now imported from types.ts
|
|
27
41
|
|
|
28
42
|
export interface FindOneOptions {
|
|
29
43
|
id: string;
|
|
@@ -38,6 +52,9 @@ export interface CreateRepoResponse {
|
|
|
38
52
|
url: string;
|
|
39
53
|
}
|
|
40
54
|
|
|
55
|
+
// Import additional types from types.ts
|
|
56
|
+
export * from './types';
|
|
57
|
+
|
|
41
58
|
/**
|
|
42
59
|
* Git Storage API
|
|
43
60
|
*/
|
|
@@ -47,6 +64,210 @@ declare const __STORAGE_BASE_URL__: string;
|
|
|
47
64
|
const API_BASE_URL = __API_BASE_URL__;
|
|
48
65
|
const STORAGE_BASE_URL = __STORAGE_BASE_URL__;
|
|
49
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Implementation of the Repo interface
|
|
69
|
+
*/
|
|
70
|
+
class RepoImpl implements Repo {
|
|
71
|
+
constructor(
|
|
72
|
+
public readonly id: string,
|
|
73
|
+
private readonly options: GitStorageOptions,
|
|
74
|
+
private readonly generateJWT: (
|
|
75
|
+
repoId: string,
|
|
76
|
+
options?: GetRemoteURLOptions,
|
|
77
|
+
) => Promise<string>,
|
|
78
|
+
) {}
|
|
79
|
+
|
|
80
|
+
async getRemoteURL(urlOptions?: GetRemoteURLOptions): Promise<string> {
|
|
81
|
+
const url = new URL(`https://${this.options.name}.${STORAGE_BASE_URL}/${this.id}.git`);
|
|
82
|
+
url.username = `t`;
|
|
83
|
+
url.password = await this.generateJWT(this.id, urlOptions);
|
|
84
|
+
return url.toString();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async getFile(options: GetFileOptions): Promise<GetFileResponse> {
|
|
88
|
+
const jwt = await this.generateJWT(this.id, {
|
|
89
|
+
permissions: ['git:read'],
|
|
90
|
+
ttl: 1 * 60 * 60, // 1hr in seconds
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const url = new URL(`${API_BASE_URL}/api/v1/repos/file`);
|
|
94
|
+
url.searchParams.set('path', options.path);
|
|
95
|
+
if (options.ref) {
|
|
96
|
+
url.searchParams.set('ref', options.ref);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const response = await fetch(url.toString(), {
|
|
100
|
+
method: 'GET',
|
|
101
|
+
headers: {
|
|
102
|
+
Authorization: `Bearer ${jwt}`,
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
if (!response.ok) {
|
|
107
|
+
throw new Error(`Failed to get file: ${response.statusText}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return (await response.json()) as GetFileResponse;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async listFiles(options?: ListFilesOptions): Promise<ListFilesResponse> {
|
|
114
|
+
const jwt = await this.generateJWT(this.id, {
|
|
115
|
+
permissions: ['git:read'],
|
|
116
|
+
ttl: 1 * 60 * 60, // 1hr in seconds
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const url = new URL(`${API_BASE_URL}/api/v1/repos/files`);
|
|
120
|
+
if (options?.ref) {
|
|
121
|
+
url.searchParams.set('ref', options.ref);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const response = await fetch(url.toString(), {
|
|
125
|
+
method: 'GET',
|
|
126
|
+
headers: {
|
|
127
|
+
Authorization: `Bearer ${jwt}`,
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
if (!response.ok) {
|
|
132
|
+
throw new Error(`Failed to list files: ${response.statusText}`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return (await response.json()) as ListFilesResponse;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async listBranches(options?: ListBranchesOptions): Promise<ListBranchesResponse> {
|
|
139
|
+
const jwt = await this.generateJWT(this.id, {
|
|
140
|
+
permissions: ['git:read'],
|
|
141
|
+
ttl: 1 * 60 * 60, // 1hr in seconds
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const url = new URL(`${API_BASE_URL}/api/v1/repos/branches`);
|
|
145
|
+
if (options?.cursor) {
|
|
146
|
+
url.searchParams.set('cursor', options.cursor);
|
|
147
|
+
}
|
|
148
|
+
if (options?.limit) {
|
|
149
|
+
url.searchParams.set('limit', options.limit.toString());
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const response = await fetch(url.toString(), {
|
|
153
|
+
method: 'GET',
|
|
154
|
+
headers: {
|
|
155
|
+
Authorization: `Bearer ${jwt}`,
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
if (!response.ok) {
|
|
160
|
+
throw new Error(`Failed to list branches: ${response.statusText}`);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return (await response.json()) as ListBranchesResponse;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async listCommits(options?: ListCommitsOptions): Promise<ListCommitsResponse> {
|
|
167
|
+
const jwt = await this.generateJWT(this.id, {
|
|
168
|
+
permissions: ['git:read'],
|
|
169
|
+
ttl: 1 * 60 * 60, // 1hr in seconds
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
const url = new URL(`${API_BASE_URL}/api/v1/repos/commits`);
|
|
173
|
+
if (options?.branch) {
|
|
174
|
+
url.searchParams.set('branch', options.branch);
|
|
175
|
+
}
|
|
176
|
+
if (options?.cursor) {
|
|
177
|
+
url.searchParams.set('cursor', options.cursor);
|
|
178
|
+
}
|
|
179
|
+
if (options?.limit) {
|
|
180
|
+
url.searchParams.set('limit', options.limit.toString());
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const response = await fetch(url.toString(), {
|
|
184
|
+
method: 'GET',
|
|
185
|
+
headers: {
|
|
186
|
+
Authorization: `Bearer ${jwt}`,
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
if (!response.ok) {
|
|
191
|
+
throw new Error(`Failed to list commits: ${response.statusText}`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return (await response.json()) as ListCommitsResponse;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async getBranchDiff(options: GetBranchDiffOptions): Promise<GetBranchDiffResponse> {
|
|
198
|
+
const jwt = await this.generateJWT(this.id, {
|
|
199
|
+
permissions: ['git:read'],
|
|
200
|
+
ttl: 1 * 60 * 60, // 1hr in seconds
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
const url = new URL(`${API_BASE_URL}/api/v1/repos/branches/diff`);
|
|
204
|
+
url.searchParams.set('branch', options.branch);
|
|
205
|
+
if (options.base) {
|
|
206
|
+
url.searchParams.set('base', options.base);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const response = await fetch(url.toString(), {
|
|
210
|
+
method: 'GET',
|
|
211
|
+
headers: {
|
|
212
|
+
Authorization: `Bearer ${jwt}`,
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
if (!response.ok) {
|
|
217
|
+
throw new Error(`Failed to get branch diff: ${response.statusText}`);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return (await response.json()) as GetBranchDiffResponse;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async getCommitDiff(options: GetCommitDiffOptions): Promise<GetCommitDiffResponse> {
|
|
224
|
+
const jwt = await this.generateJWT(this.id, {
|
|
225
|
+
permissions: ['git:read'],
|
|
226
|
+
ttl: 1 * 60 * 60, // 1hr in seconds
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
const url = new URL(`${API_BASE_URL}/api/v1/repos/diff`);
|
|
230
|
+
url.searchParams.set('sha', options.sha);
|
|
231
|
+
|
|
232
|
+
const response = await fetch(url.toString(), {
|
|
233
|
+
method: 'GET',
|
|
234
|
+
headers: {
|
|
235
|
+
Authorization: `Bearer ${jwt}`,
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
if (!response.ok) {
|
|
240
|
+
throw new Error(`Failed to get commit diff: ${response.statusText}`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return (await response.json()) as GetCommitDiffResponse;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async getCommit(options: GetCommitOptions): Promise<GetCommitResponse> {
|
|
247
|
+
const jwt = await this.generateJWT(this.id, {
|
|
248
|
+
permissions: ['git:read'],
|
|
249
|
+
ttl: 1 * 60 * 60, // 1hr in seconds
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
const url = new URL(`${API_BASE_URL}/commit`);
|
|
253
|
+
url.searchParams.set('repo', this.id);
|
|
254
|
+
url.searchParams.set('sha', options.sha);
|
|
255
|
+
|
|
256
|
+
const response = await fetch(url.toString(), {
|
|
257
|
+
method: 'GET',
|
|
258
|
+
headers: {
|
|
259
|
+
Authorization: `Bearer ${jwt}`,
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
if (!response.ok) {
|
|
264
|
+
throw new Error(`Failed to get commit: ${response.statusText}`);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return (await response.json()) as GetCommitResponse;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
50
271
|
export class GitStorage {
|
|
51
272
|
private options: GitStorageOptions;
|
|
52
273
|
|
|
@@ -100,15 +321,7 @@ export class GitStorage {
|
|
|
100
321
|
throw new Error(`Failed to create repository: ${response.statusText}`);
|
|
101
322
|
}
|
|
102
323
|
|
|
103
|
-
return
|
|
104
|
-
id: repoId,
|
|
105
|
-
getRemoteURL: async (urlOptions?: GetRemoteURLOptions): Promise<string> => {
|
|
106
|
-
const url = new URL(`https://${this.options.name}.${STORAGE_BASE_URL}/${repoId}.git`);
|
|
107
|
-
url.username = `t`;
|
|
108
|
-
url.password = await this.generateJWT(repoId, urlOptions);
|
|
109
|
-
return url.toString();
|
|
110
|
-
},
|
|
111
|
-
};
|
|
324
|
+
return new RepoImpl(repoId, this.options, this.generateJWT.bind(this));
|
|
112
325
|
}
|
|
113
326
|
|
|
114
327
|
/**
|
|
@@ -117,15 +330,7 @@ export class GitStorage {
|
|
|
117
330
|
* @returns The found repository
|
|
118
331
|
*/
|
|
119
332
|
async findOne(options: FindOneOptions): Promise<Repo | null> {
|
|
120
|
-
return
|
|
121
|
-
id: options.id,
|
|
122
|
-
getRemoteURL: async (urlOptions?: GetRemoteURLOptions): Promise<string> => {
|
|
123
|
-
const url = new URL(`https://${this.options.name}.${STORAGE_BASE_URL}/${options.id}.git`);
|
|
124
|
-
url.username = `t`;
|
|
125
|
-
url.password = await this.generateJWT(options.id, urlOptions);
|
|
126
|
-
return url.toString();
|
|
127
|
-
},
|
|
128
|
-
};
|
|
333
|
+
return new RepoImpl(options.id, this.options, this.generateJWT.bind(this));
|
|
129
334
|
}
|
|
130
335
|
|
|
131
336
|
/**
|
|
@@ -148,7 +353,6 @@ export class GitStorage {
|
|
|
148
353
|
// Create the JWT payload
|
|
149
354
|
const now = Math.floor(Date.now() / 1000);
|
|
150
355
|
const payload = {
|
|
151
|
-
aud: 'git.pierre.co', // todo this should be updated to git.storage
|
|
152
356
|
iss: this.options.name,
|
|
153
357
|
sub: '@pierre/storage',
|
|
154
358
|
repo: repoId,
|
package/src/types.ts
CHANGED
|
@@ -15,6 +15,13 @@ export interface GetRemoteURLOptions {
|
|
|
15
15
|
export interface Repo {
|
|
16
16
|
id: string;
|
|
17
17
|
getRemoteURL(options?: GetRemoteURLOptions): Promise<string>;
|
|
18
|
+
getFile(options: GetFileOptions): Promise<GetFileResponse>;
|
|
19
|
+
listFiles(options?: ListFilesOptions): Promise<ListFilesResponse>;
|
|
20
|
+
listBranches(options?: ListBranchesOptions): Promise<ListBranchesResponse>;
|
|
21
|
+
listCommits(options?: ListCommitsOptions): Promise<ListCommitsResponse>;
|
|
22
|
+
getBranchDiff(options: GetBranchDiffOptions): Promise<GetBranchDiffResponse>;
|
|
23
|
+
getCommitDiff(options: GetCommitDiffOptions): Promise<GetCommitDiffResponse>;
|
|
24
|
+
getCommit(options: GetCommitOptions): Promise<GetCommitResponse>;
|
|
18
25
|
}
|
|
19
26
|
|
|
20
27
|
export interface FindOneOptions {
|
|
@@ -29,3 +36,144 @@ export interface CreateRepoResponse {
|
|
|
29
36
|
repo_id: string;
|
|
30
37
|
url: string;
|
|
31
38
|
}
|
|
39
|
+
|
|
40
|
+
// Get File API types
|
|
41
|
+
export interface GetFileOptions {
|
|
42
|
+
path: string;
|
|
43
|
+
ref?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface GetFileResponse {
|
|
47
|
+
path: string;
|
|
48
|
+
ref: string;
|
|
49
|
+
content: string;
|
|
50
|
+
size: number;
|
|
51
|
+
is_binary: boolean;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// List Files API types
|
|
55
|
+
export interface ListFilesOptions {
|
|
56
|
+
ref?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface ListFilesResponse {
|
|
60
|
+
paths: string[];
|
|
61
|
+
ref: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// List Branches API types
|
|
65
|
+
export interface ListBranchesOptions {
|
|
66
|
+
cursor?: string;
|
|
67
|
+
limit?: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface BranchInfo {
|
|
71
|
+
cursor: string;
|
|
72
|
+
name: string;
|
|
73
|
+
head_sha: string;
|
|
74
|
+
created_at: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface ListBranchesResponse {
|
|
78
|
+
branches: BranchInfo[];
|
|
79
|
+
next_cursor?: string;
|
|
80
|
+
has_more: boolean;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// List Commits API types
|
|
84
|
+
export interface ListCommitsOptions {
|
|
85
|
+
branch?: string;
|
|
86
|
+
cursor?: string;
|
|
87
|
+
limit?: number;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface CommitInfo {
|
|
91
|
+
sha: string;
|
|
92
|
+
message: string;
|
|
93
|
+
author_name: string;
|
|
94
|
+
author_email: string;
|
|
95
|
+
committer_name: string;
|
|
96
|
+
committer_email: string;
|
|
97
|
+
date: string;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface ListCommitsResponse {
|
|
101
|
+
commits: CommitInfo[];
|
|
102
|
+
next_cursor?: string;
|
|
103
|
+
has_more: boolean;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Branch Diff API types
|
|
107
|
+
export interface GetBranchDiffOptions {
|
|
108
|
+
branch: string;
|
|
109
|
+
base?: string;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface GetBranchDiffResponse {
|
|
113
|
+
branch: string;
|
|
114
|
+
base: string;
|
|
115
|
+
stats: DiffStats;
|
|
116
|
+
files: FileDiff[];
|
|
117
|
+
filtered_files: FilteredFile[];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Commit Diff API types
|
|
121
|
+
export interface GetCommitDiffOptions {
|
|
122
|
+
sha: string;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export interface GetCommitDiffResponse {
|
|
126
|
+
sha: string;
|
|
127
|
+
stats: DiffStats;
|
|
128
|
+
files: FileDiff[];
|
|
129
|
+
filtered_files: FilteredFile[];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Shared diff types
|
|
133
|
+
export interface DiffStats {
|
|
134
|
+
files: number;
|
|
135
|
+
additions: number;
|
|
136
|
+
deletions: number;
|
|
137
|
+
changes: number;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface FileDiff {
|
|
141
|
+
path: string;
|
|
142
|
+
state: string;
|
|
143
|
+
old_path?: string;
|
|
144
|
+
bytes: number;
|
|
145
|
+
is_eof: boolean;
|
|
146
|
+
diff: string;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface FilteredFile {
|
|
150
|
+
path: string;
|
|
151
|
+
state: string;
|
|
152
|
+
old_path?: string;
|
|
153
|
+
bytes: number;
|
|
154
|
+
is_eof: boolean;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Get Commit API types
|
|
158
|
+
export interface GetCommitOptions {
|
|
159
|
+
sha: string;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface GetCommitResponse {
|
|
163
|
+
sha: string;
|
|
164
|
+
message: string;
|
|
165
|
+
author: {
|
|
166
|
+
name: string;
|
|
167
|
+
email: string;
|
|
168
|
+
};
|
|
169
|
+
committer: {
|
|
170
|
+
name: string;
|
|
171
|
+
email: string;
|
|
172
|
+
};
|
|
173
|
+
date: string;
|
|
174
|
+
stats: {
|
|
175
|
+
additions: number;
|
|
176
|
+
deletions: number;
|
|
177
|
+
total: number;
|
|
178
|
+
};
|
|
179
|
+
}
|