@pierre/storage 0.0.5 → 0.0.7
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.cjs +354 -108
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +167 -31
- package/dist/index.d.ts +167 -31
- package/dist/index.js +348 -109
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
- package/src/fetch.ts +71 -0
- package/src/index.ts +164 -144
- package/src/types.ts +97 -9
- package/src/util.ts +62 -0
- package/src/webhook.ts +251 -0
package/src/index.ts
CHANGED
|
@@ -5,7 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { importPKCS8, SignJWT } from 'jose';
|
|
8
|
+
import snakecaseKeys from 'snakecase-keys';
|
|
9
|
+
import { ApiFetcher } from './fetch';
|
|
8
10
|
import type {
|
|
11
|
+
CreateRepoOptions,
|
|
12
|
+
FindOneOptions,
|
|
9
13
|
GetBranchDiffOptions,
|
|
10
14
|
GetBranchDiffResponse,
|
|
11
15
|
GetCommitDiffOptions,
|
|
@@ -14,60 +18,56 @@ import type {
|
|
|
14
18
|
GetCommitResponse,
|
|
15
19
|
GetFileOptions,
|
|
16
20
|
GetFileResponse,
|
|
21
|
+
GetRemoteURLOptions,
|
|
22
|
+
GitStorageOptions,
|
|
17
23
|
ListBranchesOptions,
|
|
18
24
|
ListBranchesResponse,
|
|
19
25
|
ListCommitsOptions,
|
|
20
26
|
ListCommitsResponse,
|
|
21
27
|
ListFilesOptions,
|
|
22
28
|
ListFilesResponse,
|
|
29
|
+
OverrideableGitStorageOptions,
|
|
23
30
|
Repo,
|
|
31
|
+
RepullOptions,
|
|
32
|
+
ValidAPIVersion,
|
|
24
33
|
} from './types';
|
|
25
34
|
|
|
26
35
|
/**
|
|
27
36
|
* Type definitions for Pierre Git Storage SDK
|
|
28
37
|
*/
|
|
29
38
|
|
|
30
|
-
export interface GitStorageOptions {
|
|
31
|
-
key: string;
|
|
32
|
-
name: string;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface GetRemoteURLOptions {
|
|
36
|
-
permissions?: ('git:write' | 'git:read' | 'repo:write')[];
|
|
37
|
-
ttl?: number;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Repo interface is now imported from types.ts
|
|
41
|
-
|
|
42
|
-
export interface FindOneOptions {
|
|
43
|
-
id: string;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface CreateRepoOptions {
|
|
47
|
-
id?: string;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export interface CreateRepoResponse {
|
|
51
|
-
repo_id: string;
|
|
52
|
-
url: string;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
39
|
// Import additional types from types.ts
|
|
56
40
|
export * from './types';
|
|
57
41
|
|
|
42
|
+
// Export webhook validation utilities
|
|
43
|
+
export { parseSignatureHeader, validateWebhook, validateWebhookSignature } from './webhook';
|
|
44
|
+
|
|
58
45
|
/**
|
|
59
46
|
* Git Storage API
|
|
60
47
|
*/
|
|
61
|
-
|
|
48
|
+
|
|
62
49
|
declare const __STORAGE_BASE_URL__: string;
|
|
50
|
+
declare const __API_BASE_URL__: string;
|
|
63
51
|
|
|
64
52
|
const API_BASE_URL = __API_BASE_URL__;
|
|
65
53
|
const STORAGE_BASE_URL = __STORAGE_BASE_URL__;
|
|
54
|
+
const API_VERSION: ValidAPIVersion = 1;
|
|
55
|
+
|
|
56
|
+
const apiInstanceMap = new Map<string, ApiFetcher>();
|
|
57
|
+
|
|
58
|
+
function getApiInstance(baseUrl: string, version: ValidAPIVersion) {
|
|
59
|
+
if (!apiInstanceMap.has(`${baseUrl}--${version}`)) {
|
|
60
|
+
apiInstanceMap.set(`${baseUrl}--${version}`, new ApiFetcher(baseUrl, version));
|
|
61
|
+
}
|
|
62
|
+
return apiInstanceMap.get(`${baseUrl}--${version}`)!;
|
|
63
|
+
}
|
|
66
64
|
|
|
67
65
|
/**
|
|
68
66
|
* Implementation of the Repo interface
|
|
69
67
|
*/
|
|
70
68
|
class RepoImpl implements Repo {
|
|
69
|
+
private readonly api: ApiFetcher;
|
|
70
|
+
|
|
71
71
|
constructor(
|
|
72
72
|
public readonly id: string,
|
|
73
73
|
private readonly options: GitStorageOptions,
|
|
@@ -75,10 +75,16 @@ class RepoImpl implements Repo {
|
|
|
75
75
|
repoId: string,
|
|
76
76
|
options?: GetRemoteURLOptions,
|
|
77
77
|
) => Promise<string>,
|
|
78
|
-
) {
|
|
78
|
+
) {
|
|
79
|
+
this.api = getApiInstance(
|
|
80
|
+
this.options.apiBaseUrl ?? API_BASE_URL,
|
|
81
|
+
this.options.apiVersion ?? API_VERSION,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
79
84
|
|
|
80
85
|
async getRemoteURL(urlOptions?: GetRemoteURLOptions): Promise<string> {
|
|
81
|
-
const
|
|
86
|
+
const storageBaseUrl = this.options.storageBaseUrl ?? STORAGE_BASE_URL;
|
|
87
|
+
const url = new URL(`https://${this.options.name}.${storageBaseUrl}/${this.id}.git`);
|
|
82
88
|
url.username = `t`;
|
|
83
89
|
url.password = await this.generateJWT(this.id, urlOptions);
|
|
84
90
|
return url.toString();
|
|
@@ -87,25 +93,18 @@ class RepoImpl implements Repo {
|
|
|
87
93
|
async getFile(options: GetFileOptions): Promise<GetFileResponse> {
|
|
88
94
|
const jwt = await this.generateJWT(this.id, {
|
|
89
95
|
permissions: ['git:read'],
|
|
90
|
-
ttl: 1 * 60 * 60, // 1hr in seconds
|
|
96
|
+
ttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds
|
|
91
97
|
});
|
|
92
98
|
|
|
93
|
-
const
|
|
94
|
-
|
|
99
|
+
const params: Record<string, string> = {
|
|
100
|
+
path: options.path,
|
|
101
|
+
};
|
|
102
|
+
|
|
95
103
|
if (options.ref) {
|
|
96
|
-
|
|
104
|
+
params.ref = options.ref;
|
|
97
105
|
}
|
|
98
106
|
|
|
99
|
-
const response = await
|
|
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
|
-
}
|
|
107
|
+
const response = await this.api.get({ path: 'repos/file', params }, jwt);
|
|
109
108
|
|
|
110
109
|
return (await response.json()) as GetFileResponse;
|
|
111
110
|
}
|
|
@@ -113,24 +112,13 @@ class RepoImpl implements Repo {
|
|
|
113
112
|
async listFiles(options?: ListFilesOptions): Promise<ListFilesResponse> {
|
|
114
113
|
const jwt = await this.generateJWT(this.id, {
|
|
115
114
|
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
|
-
},
|
|
115
|
+
ttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds
|
|
129
116
|
});
|
|
130
117
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
118
|
+
const params: Record<string, string> | undefined = options?.ref
|
|
119
|
+
? { ref: options.ref }
|
|
120
|
+
: undefined;
|
|
121
|
+
const response = await this.api.get({ path: 'repos/files', params }, jwt);
|
|
134
122
|
|
|
135
123
|
return (await response.json()) as ListFilesResponse;
|
|
136
124
|
}
|
|
@@ -138,58 +126,48 @@ class RepoImpl implements Repo {
|
|
|
138
126
|
async listBranches(options?: ListBranchesOptions): Promise<ListBranchesResponse> {
|
|
139
127
|
const jwt = await this.generateJWT(this.id, {
|
|
140
128
|
permissions: ['git:read'],
|
|
141
|
-
ttl: 1 * 60 * 60, // 1hr in seconds
|
|
129
|
+
ttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds
|
|
142
130
|
});
|
|
143
131
|
|
|
144
|
-
|
|
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
|
-
});
|
|
132
|
+
let params: Record<string, string> | undefined;
|
|
158
133
|
|
|
159
|
-
if (!
|
|
160
|
-
|
|
134
|
+
if (options?.cursor || !options?.limit) {
|
|
135
|
+
params = {};
|
|
136
|
+
if (options?.cursor) {
|
|
137
|
+
params.cursor = options.cursor;
|
|
138
|
+
}
|
|
139
|
+
if (typeof options?.limit == 'number') {
|
|
140
|
+
params.limit = options.limit.toString();
|
|
141
|
+
}
|
|
161
142
|
}
|
|
162
143
|
|
|
144
|
+
const response = await this.api.get({ path: 'repos/branches', params }, jwt);
|
|
145
|
+
|
|
163
146
|
return (await response.json()) as ListBranchesResponse;
|
|
164
147
|
}
|
|
165
148
|
|
|
166
149
|
async listCommits(options?: ListCommitsOptions): Promise<ListCommitsResponse> {
|
|
167
150
|
const jwt = await this.generateJWT(this.id, {
|
|
168
151
|
permissions: ['git:read'],
|
|
169
|
-
ttl: 1 * 60 * 60, // 1hr in seconds
|
|
152
|
+
ttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds
|
|
170
153
|
});
|
|
171
154
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
155
|
+
let params: Record<string, string> | undefined;
|
|
156
|
+
|
|
157
|
+
if (options?.branch || options?.cursor || options?.limit) {
|
|
158
|
+
params = {};
|
|
159
|
+
if (options?.branch) {
|
|
160
|
+
params.branch = options.branch;
|
|
161
|
+
}
|
|
162
|
+
if (options?.cursor) {
|
|
163
|
+
params.cursor = options.cursor;
|
|
164
|
+
}
|
|
165
|
+
if (typeof options?.limit == 'number') {
|
|
166
|
+
params.limit = options.limit.toString();
|
|
167
|
+
}
|
|
181
168
|
}
|
|
182
169
|
|
|
183
|
-
const response = await
|
|
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
|
-
}
|
|
170
|
+
const response = await this.api.get({ path: 'repos/commits', params }, jwt);
|
|
193
171
|
|
|
194
172
|
return (await response.json()) as ListCommitsResponse;
|
|
195
173
|
}
|
|
@@ -197,25 +175,18 @@ class RepoImpl implements Repo {
|
|
|
197
175
|
async getBranchDiff(options: GetBranchDiffOptions): Promise<GetBranchDiffResponse> {
|
|
198
176
|
const jwt = await this.generateJWT(this.id, {
|
|
199
177
|
permissions: ['git:read'],
|
|
200
|
-
ttl: 1 * 60 * 60, // 1hr in seconds
|
|
178
|
+
ttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds
|
|
201
179
|
});
|
|
202
180
|
|
|
203
|
-
const
|
|
204
|
-
|
|
181
|
+
const params: Record<string, string> = {
|
|
182
|
+
branch: options.branch,
|
|
183
|
+
};
|
|
184
|
+
|
|
205
185
|
if (options.base) {
|
|
206
|
-
|
|
186
|
+
params.base = options.base;
|
|
207
187
|
}
|
|
208
188
|
|
|
209
|
-
const response = await
|
|
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
|
-
}
|
|
189
|
+
const response = await this.api.get({ path: 'repos/branches/diff', params }, jwt);
|
|
219
190
|
|
|
220
191
|
return (await response.json()) as GetBranchDiffResponse;
|
|
221
192
|
}
|
|
@@ -223,22 +194,14 @@ class RepoImpl implements Repo {
|
|
|
223
194
|
async getCommitDiff(options: GetCommitDiffOptions): Promise<GetCommitDiffResponse> {
|
|
224
195
|
const jwt = await this.generateJWT(this.id, {
|
|
225
196
|
permissions: ['git:read'],
|
|
226
|
-
ttl: 1 * 60 * 60, // 1hr in seconds
|
|
197
|
+
ttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds
|
|
227
198
|
});
|
|
228
199
|
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
const response = await fetch(url.toString(), {
|
|
233
|
-
method: 'GET',
|
|
234
|
-
headers: {
|
|
235
|
-
Authorization: `Bearer ${jwt}`,
|
|
236
|
-
},
|
|
237
|
-
});
|
|
200
|
+
const params: Record<string, string> = {
|
|
201
|
+
sha: options.sha,
|
|
202
|
+
};
|
|
238
203
|
|
|
239
|
-
|
|
240
|
-
throw new Error(`Failed to get commit diff: ${response.statusText}`);
|
|
241
|
-
}
|
|
204
|
+
const response = await this.api.get({ path: 'repos/diff', params }, jwt);
|
|
242
205
|
|
|
243
206
|
return (await response.json()) as GetCommitDiffResponse;
|
|
244
207
|
}
|
|
@@ -246,30 +209,44 @@ class RepoImpl implements Repo {
|
|
|
246
209
|
async getCommit(options: GetCommitOptions): Promise<GetCommitResponse> {
|
|
247
210
|
const jwt = await this.generateJWT(this.id, {
|
|
248
211
|
permissions: ['git:read'],
|
|
249
|
-
ttl: 1 * 60 * 60, // 1hr in seconds
|
|
212
|
+
ttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds
|
|
250
213
|
});
|
|
251
214
|
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
215
|
+
const params: Record<string, string> = {
|
|
216
|
+
repo: this.id,
|
|
217
|
+
sha: options.sha,
|
|
218
|
+
};
|
|
219
|
+
const response = await this.api.get({ path: 'commit', params }, jwt);
|
|
220
|
+
|
|
221
|
+
return (await response.json()) as GetCommitResponse;
|
|
222
|
+
}
|
|
255
223
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
},
|
|
224
|
+
async repull(options: RepullOptions): Promise<void> {
|
|
225
|
+
const jwt = await this.generateJWT(this.id, {
|
|
226
|
+
permissions: ['git:write'],
|
|
227
|
+
ttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds
|
|
261
228
|
});
|
|
262
229
|
|
|
263
|
-
|
|
264
|
-
|
|
230
|
+
const body: Record<string, string> = {};
|
|
231
|
+
|
|
232
|
+
if (options.ref) {
|
|
233
|
+
body.ref = options.ref;
|
|
265
234
|
}
|
|
266
235
|
|
|
267
|
-
|
|
236
|
+
const response = await this.api.post({ path: 'repos/repull', body }, jwt);
|
|
237
|
+
|
|
238
|
+
if (response.status !== 202) {
|
|
239
|
+
throw new Error(`Repull failed: ${response.status} ${await response.text()}`);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return;
|
|
268
243
|
}
|
|
269
244
|
}
|
|
270
245
|
|
|
271
246
|
export class GitStorage {
|
|
247
|
+
private static overrides: OverrideableGitStorageOptions = {};
|
|
272
248
|
private options: GitStorageOptions;
|
|
249
|
+
private api: ApiFetcher;
|
|
273
250
|
|
|
274
251
|
constructor(options: GitStorageOptions) {
|
|
275
252
|
if (
|
|
@@ -292,12 +269,27 @@ export class GitStorage {
|
|
|
292
269
|
throw new Error('GitStorage key must be a non-empty string.');
|
|
293
270
|
}
|
|
294
271
|
|
|
272
|
+
const resolvedApiBaseUrl =
|
|
273
|
+
options.apiBaseUrl ?? GitStorage.overrides.apiBaseUrl ?? API_BASE_URL;
|
|
274
|
+
const resolvedApiVersion = options.apiVersion ?? GitStorage.overrides.apiVersion ?? API_VERSION;
|
|
275
|
+
const resolvedStorageBaseUrl =
|
|
276
|
+
options.storageBaseUrl ?? GitStorage.overrides.storageBaseUrl ?? STORAGE_BASE_URL;
|
|
277
|
+
|
|
278
|
+
this.api = getApiInstance(resolvedApiBaseUrl, resolvedApiVersion);
|
|
279
|
+
|
|
295
280
|
this.options = {
|
|
296
281
|
key: options.key,
|
|
297
282
|
name: options.name,
|
|
283
|
+
apiBaseUrl: resolvedApiBaseUrl,
|
|
284
|
+
apiVersion: resolvedApiVersion,
|
|
285
|
+
storageBaseUrl: resolvedStorageBaseUrl,
|
|
298
286
|
};
|
|
299
287
|
}
|
|
300
288
|
|
|
289
|
+
static override(options: OverrideableGitStorageOptions): void {
|
|
290
|
+
this.overrides = Object.assign({}, this.overrides, options);
|
|
291
|
+
}
|
|
292
|
+
|
|
301
293
|
/**
|
|
302
294
|
* Create a new repository
|
|
303
295
|
* @returns The created repository
|
|
@@ -307,18 +299,34 @@ export class GitStorage {
|
|
|
307
299
|
|
|
308
300
|
const jwt = await this.generateJWT(repoId, {
|
|
309
301
|
permissions: ['repo:write'],
|
|
310
|
-
ttl: 1 * 60 * 60, // 1hr in seconds
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
const response = await fetch(`${API_BASE_URL}/api/v1/repos`, {
|
|
314
|
-
method: 'POST',
|
|
315
|
-
headers: {
|
|
316
|
-
Authorization: `Bearer ${jwt}`,
|
|
317
|
-
},
|
|
302
|
+
ttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds
|
|
318
303
|
});
|
|
319
304
|
|
|
320
|
-
|
|
321
|
-
|
|
305
|
+
const baseRepoOptions = options?.baseRepo
|
|
306
|
+
? {
|
|
307
|
+
provider: 'github',
|
|
308
|
+
...snakecaseKeys(options.baseRepo as unknown as Record<string, unknown>),
|
|
309
|
+
}
|
|
310
|
+
: null;
|
|
311
|
+
|
|
312
|
+
// Default defaultBranch to 'main' if not provided
|
|
313
|
+
const defaultBranch = options?.defaultBranch ?? 'main';
|
|
314
|
+
|
|
315
|
+
const createRepoPath =
|
|
316
|
+
baseRepoOptions || defaultBranch
|
|
317
|
+
? {
|
|
318
|
+
path: 'repos',
|
|
319
|
+
body: {
|
|
320
|
+
...(baseRepoOptions && { base_repo: baseRepoOptions }),
|
|
321
|
+
default_branch: defaultBranch,
|
|
322
|
+
},
|
|
323
|
+
}
|
|
324
|
+
: 'repos';
|
|
325
|
+
|
|
326
|
+
// Allow 409 so we can map it to a clearer error message
|
|
327
|
+
const resp = await this.api.post(createRepoPath, jwt, { allowedStatus: [409] });
|
|
328
|
+
if (resp.status === 409) {
|
|
329
|
+
throw new Error('Repository already exists');
|
|
322
330
|
}
|
|
323
331
|
|
|
324
332
|
return new RepoImpl(repoId, this.options, this.generateJWT.bind(this));
|
|
@@ -330,6 +338,18 @@ export class GitStorage {
|
|
|
330
338
|
* @returns The found repository
|
|
331
339
|
*/
|
|
332
340
|
async findOne(options: FindOneOptions): Promise<Repo | null> {
|
|
341
|
+
const jwt = await this.generateJWT(options.id, {
|
|
342
|
+
permissions: ['git:read'],
|
|
343
|
+
ttl: 1 * 60 * 60,
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// Allow 404 to indicate "not found" without throwing
|
|
347
|
+
const resp = await this.api.get('repo', jwt, { allowedStatus: [404] });
|
|
348
|
+
if (resp.status === 404) {
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
// On 200, we could validate response, but RepoImpl only needs the repo URL/id
|
|
352
|
+
// const body = await resp.json(); // not required for now
|
|
333
353
|
return new RepoImpl(options.id, this.options, this.generateJWT.bind(this));
|
|
334
354
|
}
|
|
335
355
|
|
package/src/types.ts
CHANGED
|
@@ -2,11 +2,20 @@
|
|
|
2
2
|
* Type definitions for Pierre Git Storage SDK
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
export interface
|
|
5
|
+
export interface OverrideableGitStorageOptions {
|
|
6
|
+
apiBaseUrl?: string;
|
|
7
|
+
storageBaseUrl?: string;
|
|
8
|
+
apiVersion?: ValidAPIVersion;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface GitStorageOptions extends OverrideableGitStorageOptions {
|
|
6
12
|
key: string;
|
|
7
13
|
name: string;
|
|
14
|
+
defaultTTL?: number;
|
|
8
15
|
}
|
|
9
16
|
|
|
17
|
+
export type ValidAPIVersion = 1;
|
|
18
|
+
|
|
10
19
|
export interface GetRemoteURLOptions {
|
|
11
20
|
permissions?: ('git:write' | 'git:read' | 'repo:write')[];
|
|
12
21
|
ttl?: number;
|
|
@@ -24,12 +33,39 @@ export interface Repo {
|
|
|
24
33
|
getCommit(options: GetCommitOptions): Promise<GetCommitResponse>;
|
|
25
34
|
}
|
|
26
35
|
|
|
36
|
+
export type ValidMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
37
|
+
type SimplePath = string;
|
|
38
|
+
type ComplexPath = {
|
|
39
|
+
path: string;
|
|
40
|
+
params?: Record<string, string>;
|
|
41
|
+
body?: Record<string, any>;
|
|
42
|
+
};
|
|
43
|
+
export type ValidPath = SimplePath | ComplexPath;
|
|
44
|
+
|
|
45
|
+
interface GitStorageInvocationOptions {
|
|
46
|
+
ttl?: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
27
49
|
export interface FindOneOptions {
|
|
28
50
|
id: string;
|
|
29
51
|
}
|
|
30
52
|
|
|
31
|
-
export
|
|
53
|
+
export type SupportedRepoProvider = 'github';
|
|
54
|
+
|
|
55
|
+
export interface BaseRepo {
|
|
56
|
+
/**
|
|
57
|
+
* @default github
|
|
58
|
+
*/
|
|
59
|
+
provider?: SupportedRepoProvider;
|
|
60
|
+
owner: string;
|
|
61
|
+
name: string;
|
|
62
|
+
defaultBranch?: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface CreateRepoOptions extends GitStorageInvocationOptions {
|
|
32
66
|
id?: string;
|
|
67
|
+
baseRepo?: BaseRepo;
|
|
68
|
+
defaultBranch?: string;
|
|
33
69
|
}
|
|
34
70
|
|
|
35
71
|
export interface CreateRepoResponse {
|
|
@@ -38,7 +74,7 @@ export interface CreateRepoResponse {
|
|
|
38
74
|
}
|
|
39
75
|
|
|
40
76
|
// Get File API types
|
|
41
|
-
export interface GetFileOptions {
|
|
77
|
+
export interface GetFileOptions extends GitStorageInvocationOptions {
|
|
42
78
|
path: string;
|
|
43
79
|
ref?: string;
|
|
44
80
|
}
|
|
@@ -51,8 +87,12 @@ export interface GetFileResponse {
|
|
|
51
87
|
is_binary: boolean;
|
|
52
88
|
}
|
|
53
89
|
|
|
90
|
+
export interface RepullOptions extends GitStorageInvocationOptions {
|
|
91
|
+
ref?: string;
|
|
92
|
+
}
|
|
93
|
+
|
|
54
94
|
// List Files API types
|
|
55
|
-
export interface ListFilesOptions {
|
|
95
|
+
export interface ListFilesOptions extends GitStorageInvocationOptions {
|
|
56
96
|
ref?: string;
|
|
57
97
|
}
|
|
58
98
|
|
|
@@ -62,7 +102,7 @@ export interface ListFilesResponse {
|
|
|
62
102
|
}
|
|
63
103
|
|
|
64
104
|
// List Branches API types
|
|
65
|
-
export interface ListBranchesOptions {
|
|
105
|
+
export interface ListBranchesOptions extends GitStorageInvocationOptions {
|
|
66
106
|
cursor?: string;
|
|
67
107
|
limit?: number;
|
|
68
108
|
}
|
|
@@ -81,7 +121,7 @@ export interface ListBranchesResponse {
|
|
|
81
121
|
}
|
|
82
122
|
|
|
83
123
|
// List Commits API types
|
|
84
|
-
export interface ListCommitsOptions {
|
|
124
|
+
export interface ListCommitsOptions extends GitStorageInvocationOptions {
|
|
85
125
|
branch?: string;
|
|
86
126
|
cursor?: string;
|
|
87
127
|
limit?: number;
|
|
@@ -104,7 +144,7 @@ export interface ListCommitsResponse {
|
|
|
104
144
|
}
|
|
105
145
|
|
|
106
146
|
// Branch Diff API types
|
|
107
|
-
export interface GetBranchDiffOptions {
|
|
147
|
+
export interface GetBranchDiffOptions extends GitStorageInvocationOptions {
|
|
108
148
|
branch: string;
|
|
109
149
|
base?: string;
|
|
110
150
|
}
|
|
@@ -118,7 +158,7 @@ export interface GetBranchDiffResponse {
|
|
|
118
158
|
}
|
|
119
159
|
|
|
120
160
|
// Commit Diff API types
|
|
121
|
-
export interface GetCommitDiffOptions {
|
|
161
|
+
export interface GetCommitDiffOptions extends GitStorageInvocationOptions {
|
|
122
162
|
sha: string;
|
|
123
163
|
}
|
|
124
164
|
|
|
@@ -155,7 +195,7 @@ export interface FilteredFile {
|
|
|
155
195
|
}
|
|
156
196
|
|
|
157
197
|
// Get Commit API types
|
|
158
|
-
export interface GetCommitOptions {
|
|
198
|
+
export interface GetCommitOptions extends GitStorageInvocationOptions {
|
|
159
199
|
sha: string;
|
|
160
200
|
}
|
|
161
201
|
|
|
@@ -177,3 +217,51 @@ export interface GetCommitResponse {
|
|
|
177
217
|
total: number;
|
|
178
218
|
};
|
|
179
219
|
}
|
|
220
|
+
|
|
221
|
+
// Webhook types
|
|
222
|
+
export interface WebhookValidationOptions {
|
|
223
|
+
/**
|
|
224
|
+
* Maximum age of webhook in seconds (default: 300 seconds / 5 minutes)
|
|
225
|
+
* Set to 0 to disable timestamp validation
|
|
226
|
+
*/
|
|
227
|
+
maxAgeSeconds?: number;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface WebhookValidationResult {
|
|
231
|
+
/**
|
|
232
|
+
* Whether the webhook signature and timestamp are valid
|
|
233
|
+
*/
|
|
234
|
+
valid: boolean;
|
|
235
|
+
/**
|
|
236
|
+
* Error message if validation failed
|
|
237
|
+
*/
|
|
238
|
+
error?: string;
|
|
239
|
+
/**
|
|
240
|
+
* The parsed webhook event type (e.g., "push")
|
|
241
|
+
*/
|
|
242
|
+
eventType?: string;
|
|
243
|
+
/**
|
|
244
|
+
* The timestamp from the signature (Unix seconds)
|
|
245
|
+
*/
|
|
246
|
+
timestamp?: number;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Webhook event payloads
|
|
250
|
+
export interface WebhookPushEvent {
|
|
251
|
+
repository: {
|
|
252
|
+
id: string;
|
|
253
|
+
url: string;
|
|
254
|
+
};
|
|
255
|
+
ref: string;
|
|
256
|
+
before: string;
|
|
257
|
+
after: string;
|
|
258
|
+
customer_id: string;
|
|
259
|
+
pushed_at: string; // RFC3339 timestamp
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export type WebhookEventPayload = WebhookPushEvent;
|
|
263
|
+
|
|
264
|
+
export interface ParsedWebhookSignature {
|
|
265
|
+
timestamp: string;
|
|
266
|
+
signature: string;
|
|
267
|
+
}
|