@pierre/storage 0.0.11 → 0.1.1
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 +159 -78
- package/dist/index.cjs +739 -72
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +560 -88
- package/dist/index.d.ts +560 -88
- package/dist/index.js +738 -73
- package/dist/index.js.map +1 -1
- package/package.json +39 -37
- package/src/commit.ts +196 -43
- package/src/errors.ts +50 -0
- package/src/fetch.ts +75 -5
- package/src/index.ts +389 -47
- package/src/schemas.ts +138 -0
- package/src/types.ts +182 -89
- package/src/util.ts +0 -18
- package/src/webhook.ts +75 -3
package/src/schemas.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export const listFilesResponseSchema = z.object({
|
|
4
|
+
paths: z.array(z.string()),
|
|
5
|
+
ref: z.string(),
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export const branchInfoSchema = z.object({
|
|
9
|
+
cursor: z.string(),
|
|
10
|
+
name: z.string(),
|
|
11
|
+
head_sha: z.string(),
|
|
12
|
+
created_at: z.string(),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export const listBranchesResponseSchema = z.object({
|
|
16
|
+
branches: z.array(branchInfoSchema),
|
|
17
|
+
next_cursor: z.string().nullable().optional(),
|
|
18
|
+
has_more: z.boolean(),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export const commitInfoRawSchema = z.object({
|
|
22
|
+
sha: z.string(),
|
|
23
|
+
message: z.string(),
|
|
24
|
+
author_name: z.string(),
|
|
25
|
+
author_email: z.string(),
|
|
26
|
+
committer_name: z.string(),
|
|
27
|
+
committer_email: z.string(),
|
|
28
|
+
date: z.string(),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export const listCommitsResponseSchema = z.object({
|
|
32
|
+
commits: z.array(commitInfoRawSchema),
|
|
33
|
+
next_cursor: z.string().nullable().optional(),
|
|
34
|
+
has_more: z.boolean(),
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
export const diffStatsSchema = z.object({
|
|
38
|
+
files: z.number(),
|
|
39
|
+
additions: z.number(),
|
|
40
|
+
deletions: z.number(),
|
|
41
|
+
changes: z.number(),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export const diffFileRawSchema = z.object({
|
|
45
|
+
path: z.string(),
|
|
46
|
+
state: z.string(),
|
|
47
|
+
old_path: z.string().nullable().optional(),
|
|
48
|
+
raw: z.string(),
|
|
49
|
+
bytes: z.number(),
|
|
50
|
+
is_eof: z.boolean(),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
export const filteredFileRawSchema = z.object({
|
|
54
|
+
path: z.string(),
|
|
55
|
+
state: z.string(),
|
|
56
|
+
old_path: z.string().nullable().optional(),
|
|
57
|
+
bytes: z.number(),
|
|
58
|
+
is_eof: z.boolean(),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
export const branchDiffResponseSchema = z.object({
|
|
62
|
+
branch: z.string(),
|
|
63
|
+
base: z.string(),
|
|
64
|
+
stats: diffStatsSchema,
|
|
65
|
+
files: z.array(diffFileRawSchema),
|
|
66
|
+
filtered_files: z.array(filteredFileRawSchema),
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
export const commitDiffResponseSchema = z.object({
|
|
70
|
+
sha: z.string(),
|
|
71
|
+
stats: diffStatsSchema,
|
|
72
|
+
files: z.array(diffFileRawSchema),
|
|
73
|
+
filtered_files: z.array(filteredFileRawSchema),
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
export const refUpdateResultSchema = z.object({
|
|
77
|
+
branch: z.string(),
|
|
78
|
+
old_sha: z.string(),
|
|
79
|
+
new_sha: z.string(),
|
|
80
|
+
success: z.boolean(),
|
|
81
|
+
status: z.string(),
|
|
82
|
+
message: z.string().optional(),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
export const commitPackCommitSchema = z.object({
|
|
86
|
+
commit_sha: z.string(),
|
|
87
|
+
tree_sha: z.string(),
|
|
88
|
+
target_branch: z.string(),
|
|
89
|
+
pack_bytes: z.number(),
|
|
90
|
+
blob_count: z.number(),
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
export const restoreCommitCommitSchema = commitPackCommitSchema.omit({ blob_count: true });
|
|
94
|
+
|
|
95
|
+
export const refUpdateResultWithOptionalsSchema = z.object({
|
|
96
|
+
branch: z.string().optional(),
|
|
97
|
+
old_sha: z.string().optional(),
|
|
98
|
+
new_sha: z.string().optional(),
|
|
99
|
+
success: z.boolean().optional(),
|
|
100
|
+
status: z.string(),
|
|
101
|
+
message: z.string().optional(),
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
export const commitPackAckSchema = z.object({
|
|
105
|
+
commit: commitPackCommitSchema,
|
|
106
|
+
result: refUpdateResultSchema,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
export const restoreCommitAckSchema = z.object({
|
|
110
|
+
commit: restoreCommitCommitSchema,
|
|
111
|
+
result: refUpdateResultSchema.extend({ success: z.literal(true) }),
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
export const commitPackResponseSchema = z.object({
|
|
115
|
+
commit: commitPackCommitSchema.partial().optional().nullable(),
|
|
116
|
+
result: refUpdateResultWithOptionalsSchema,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
export const restoreCommitResponseSchema = z.object({
|
|
120
|
+
commit: restoreCommitCommitSchema.partial().optional().nullable(),
|
|
121
|
+
result: refUpdateResultWithOptionalsSchema,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
export const errorEnvelopeSchema = z.object({
|
|
125
|
+
error: z.string(),
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
export type ListFilesResponseRaw = z.infer<typeof listFilesResponseSchema>;
|
|
129
|
+
export type RawBranchInfo = z.infer<typeof branchInfoSchema>;
|
|
130
|
+
export type ListBranchesResponseRaw = z.infer<typeof listBranchesResponseSchema>;
|
|
131
|
+
export type RawCommitInfo = z.infer<typeof commitInfoRawSchema>;
|
|
132
|
+
export type ListCommitsResponseRaw = z.infer<typeof listCommitsResponseSchema>;
|
|
133
|
+
export type RawFileDiff = z.infer<typeof diffFileRawSchema>;
|
|
134
|
+
export type RawFilteredFile = z.infer<typeof filteredFileRawSchema>;
|
|
135
|
+
export type GetBranchDiffResponseRaw = z.infer<typeof branchDiffResponseSchema>;
|
|
136
|
+
export type GetCommitDiffResponseRaw = z.infer<typeof commitDiffResponseSchema>;
|
|
137
|
+
export type CommitPackAckRaw = z.infer<typeof commitPackAckSchema>;
|
|
138
|
+
export type RestoreCommitAckRaw = z.infer<typeof restoreCommitAckSchema>;
|
package/src/types.ts
CHANGED
|
@@ -2,10 +2,23 @@
|
|
|
2
2
|
* Type definitions for Pierre Git Storage SDK
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import type {
|
|
6
|
+
GetBranchDiffResponseRaw,
|
|
7
|
+
GetCommitDiffResponseRaw,
|
|
8
|
+
ListBranchesResponseRaw,
|
|
9
|
+
ListCommitsResponseRaw,
|
|
10
|
+
ListFilesResponseRaw,
|
|
11
|
+
RawBranchInfo as SchemaRawBranchInfo,
|
|
12
|
+
RawCommitInfo as SchemaRawCommitInfo,
|
|
13
|
+
RawFileDiff as SchemaRawFileDiff,
|
|
14
|
+
RawFilteredFile as SchemaRawFilteredFile,
|
|
15
|
+
} from './schemas';
|
|
16
|
+
|
|
5
17
|
export interface OverrideableGitStorageOptions {
|
|
6
18
|
apiBaseUrl?: string;
|
|
7
19
|
storageBaseUrl?: string;
|
|
8
20
|
apiVersion?: ValidAPIVersion;
|
|
21
|
+
defaultTTL?: number;
|
|
9
22
|
}
|
|
10
23
|
|
|
11
24
|
export interface GitStorageOptions extends OverrideableGitStorageOptions {
|
|
@@ -26,13 +39,13 @@ export interface Repo {
|
|
|
26
39
|
getRemoteURL(options?: GetRemoteURLOptions): Promise<string>;
|
|
27
40
|
|
|
28
41
|
getFileStream(options: GetFileOptions): Promise<Response>;
|
|
29
|
-
listFiles(options?: ListFilesOptions): Promise<
|
|
30
|
-
listBranches(options?: ListBranchesOptions): Promise<
|
|
31
|
-
listCommits(options?: ListCommitsOptions): Promise<
|
|
32
|
-
getBranchDiff(options: GetBranchDiffOptions): Promise<
|
|
33
|
-
getCommitDiff(options: GetCommitDiffOptions): Promise<
|
|
34
|
-
getCommit(options: GetCommitOptions): Promise<GetCommitResponse>;
|
|
42
|
+
listFiles(options?: ListFilesOptions): Promise<ListFilesResult>;
|
|
43
|
+
listBranches(options?: ListBranchesOptions): Promise<ListBranchesResult>;
|
|
44
|
+
listCommits(options?: ListCommitsOptions): Promise<ListCommitsResult>;
|
|
45
|
+
getBranchDiff(options: GetBranchDiffOptions): Promise<GetBranchDiffResult>;
|
|
46
|
+
getCommitDiff(options: GetCommitDiffOptions): Promise<GetCommitDiffResult>;
|
|
35
47
|
pullUpstream(options: PullUpstreamOptions): Promise<void>;
|
|
48
|
+
restoreCommit(options: RestoreCommitOptions): Promise<RestoreCommitResult>;
|
|
36
49
|
createCommit(options: CreateCommitOptions): CommitBuilder;
|
|
37
50
|
}
|
|
38
51
|
|
|
@@ -71,11 +84,6 @@ export interface CreateRepoOptions extends GitStorageInvocationOptions {
|
|
|
71
84
|
defaultBranch?: string;
|
|
72
85
|
}
|
|
73
86
|
|
|
74
|
-
export interface CreateRepoResponse {
|
|
75
|
-
repo_id: string;
|
|
76
|
-
url: string;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
87
|
// Get File API types
|
|
80
88
|
export interface GetFileOptions extends GitStorageInvocationOptions {
|
|
81
89
|
path: string;
|
|
@@ -91,7 +99,9 @@ export interface ListFilesOptions extends GitStorageInvocationOptions {
|
|
|
91
99
|
ref?: string;
|
|
92
100
|
}
|
|
93
101
|
|
|
94
|
-
export
|
|
102
|
+
export type ListFilesResponse = ListFilesResponseRaw;
|
|
103
|
+
|
|
104
|
+
export interface ListFilesResult {
|
|
95
105
|
paths: string[];
|
|
96
106
|
ref: string;
|
|
97
107
|
}
|
|
@@ -102,17 +112,21 @@ export interface ListBranchesOptions extends GitStorageInvocationOptions {
|
|
|
102
112
|
limit?: number;
|
|
103
113
|
}
|
|
104
114
|
|
|
115
|
+
export type RawBranchInfo = SchemaRawBranchInfo;
|
|
116
|
+
|
|
105
117
|
export interface BranchInfo {
|
|
106
118
|
cursor: string;
|
|
107
119
|
name: string;
|
|
108
|
-
|
|
109
|
-
|
|
120
|
+
headSha: string;
|
|
121
|
+
createdAt: string;
|
|
110
122
|
}
|
|
111
123
|
|
|
112
|
-
export
|
|
124
|
+
export type ListBranchesResponse = ListBranchesResponseRaw;
|
|
125
|
+
|
|
126
|
+
export interface ListBranchesResult {
|
|
113
127
|
branches: BranchInfo[];
|
|
114
|
-
|
|
115
|
-
|
|
128
|
+
nextCursor?: string;
|
|
129
|
+
hasMore: boolean;
|
|
116
130
|
}
|
|
117
131
|
|
|
118
132
|
// List Commits API types
|
|
@@ -122,20 +136,25 @@ export interface ListCommitsOptions extends GitStorageInvocationOptions {
|
|
|
122
136
|
limit?: number;
|
|
123
137
|
}
|
|
124
138
|
|
|
139
|
+
export type RawCommitInfo = SchemaRawCommitInfo;
|
|
140
|
+
|
|
125
141
|
export interface CommitInfo {
|
|
126
142
|
sha: string;
|
|
127
143
|
message: string;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
date:
|
|
144
|
+
authorName: string;
|
|
145
|
+
authorEmail: string;
|
|
146
|
+
committerName: string;
|
|
147
|
+
committerEmail: string;
|
|
148
|
+
date: Date;
|
|
149
|
+
rawDate: string;
|
|
133
150
|
}
|
|
134
151
|
|
|
135
|
-
export
|
|
152
|
+
export type ListCommitsResponse = ListCommitsResponseRaw;
|
|
153
|
+
|
|
154
|
+
export interface ListCommitsResult {
|
|
136
155
|
commits: CommitInfo[];
|
|
137
|
-
|
|
138
|
-
|
|
156
|
+
nextCursor?: string;
|
|
157
|
+
hasMore: boolean;
|
|
139
158
|
}
|
|
140
159
|
|
|
141
160
|
// Branch Diff API types
|
|
@@ -144,12 +163,14 @@ export interface GetBranchDiffOptions extends GitStorageInvocationOptions {
|
|
|
144
163
|
base?: string;
|
|
145
164
|
}
|
|
146
165
|
|
|
147
|
-
export
|
|
166
|
+
export type GetBranchDiffResponse = GetBranchDiffResponseRaw;
|
|
167
|
+
|
|
168
|
+
export interface GetBranchDiffResult {
|
|
148
169
|
branch: string;
|
|
149
170
|
base: string;
|
|
150
171
|
stats: DiffStats;
|
|
151
172
|
files: FileDiff[];
|
|
152
|
-
|
|
173
|
+
filteredFiles: FilteredFile[];
|
|
153
174
|
}
|
|
154
175
|
|
|
155
176
|
// Commit Diff API types
|
|
@@ -157,11 +178,13 @@ export interface GetCommitDiffOptions extends GitStorageInvocationOptions {
|
|
|
157
178
|
sha: string;
|
|
158
179
|
}
|
|
159
180
|
|
|
160
|
-
export
|
|
181
|
+
export type GetCommitDiffResponse = GetCommitDiffResponseRaw;
|
|
182
|
+
|
|
183
|
+
export interface GetCommitDiffResult {
|
|
161
184
|
sha: string;
|
|
162
185
|
stats: DiffStats;
|
|
163
186
|
files: FileDiff[];
|
|
164
|
-
|
|
187
|
+
filteredFiles: FilteredFile[];
|
|
165
188
|
}
|
|
166
189
|
|
|
167
190
|
// Shared diff types
|
|
@@ -172,52 +195,40 @@ export interface DiffStats {
|
|
|
172
195
|
changes: number;
|
|
173
196
|
}
|
|
174
197
|
|
|
175
|
-
export
|
|
176
|
-
path: string;
|
|
177
|
-
state: string;
|
|
178
|
-
old_path?: string;
|
|
179
|
-
bytes: number;
|
|
180
|
-
is_eof: boolean;
|
|
181
|
-
diff: string;
|
|
182
|
-
}
|
|
198
|
+
export type RawFileDiff = SchemaRawFileDiff;
|
|
183
199
|
|
|
184
|
-
export
|
|
200
|
+
export type RawFilteredFile = SchemaRawFilteredFile;
|
|
201
|
+
|
|
202
|
+
export type DiffFileState =
|
|
203
|
+
| 'added'
|
|
204
|
+
| 'modified'
|
|
205
|
+
| 'deleted'
|
|
206
|
+
| 'renamed'
|
|
207
|
+
| 'copied'
|
|
208
|
+
| 'type_changed'
|
|
209
|
+
| 'unmerged'
|
|
210
|
+
| 'unknown';
|
|
211
|
+
|
|
212
|
+
export interface DiffFileBase {
|
|
185
213
|
path: string;
|
|
186
|
-
state:
|
|
187
|
-
|
|
214
|
+
state: DiffFileState;
|
|
215
|
+
rawState: string;
|
|
216
|
+
oldPath?: string;
|
|
188
217
|
bytes: number;
|
|
189
|
-
|
|
218
|
+
isEof: boolean;
|
|
190
219
|
}
|
|
191
220
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
sha: string;
|
|
221
|
+
export interface FileDiff extends DiffFileBase {
|
|
222
|
+
raw: string;
|
|
195
223
|
}
|
|
196
224
|
|
|
197
|
-
export interface
|
|
198
|
-
sha: string;
|
|
199
|
-
message: string;
|
|
200
|
-
author: {
|
|
201
|
-
name: string;
|
|
202
|
-
email: string;
|
|
203
|
-
};
|
|
204
|
-
committer: {
|
|
205
|
-
name: string;
|
|
206
|
-
email: string;
|
|
207
|
-
};
|
|
208
|
-
date: string;
|
|
209
|
-
stats: {
|
|
210
|
-
additions: number;
|
|
211
|
-
deletions: number;
|
|
212
|
-
total: number;
|
|
213
|
-
};
|
|
214
|
-
}
|
|
225
|
+
export interface FilteredFile extends DiffFileBase {}
|
|
215
226
|
|
|
216
227
|
export interface CreateCommitOptions extends GitStorageInvocationOptions {
|
|
217
|
-
|
|
228
|
+
targetBranch: string;
|
|
218
229
|
commitMessage: string;
|
|
219
|
-
|
|
220
|
-
author
|
|
230
|
+
expectedHeadSha?: string;
|
|
231
|
+
author: CommitSignature;
|
|
221
232
|
committer?: CommitSignature;
|
|
222
233
|
signal?: AbortSignal;
|
|
223
234
|
}
|
|
@@ -225,47 +236,110 @@ export interface CreateCommitOptions extends GitStorageInvocationOptions {
|
|
|
225
236
|
export interface CommitSignature {
|
|
226
237
|
name: string;
|
|
227
238
|
email: string;
|
|
228
|
-
date?: string;
|
|
229
239
|
}
|
|
230
240
|
|
|
241
|
+
export interface ReadableStreamReaderLike<T> {
|
|
242
|
+
read(): Promise<{ value?: T; done: boolean }>;
|
|
243
|
+
releaseLock?(): void;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export interface ReadableStreamLike<T> {
|
|
247
|
+
getReader(): ReadableStreamReaderLike<T>;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export interface BlobLike {
|
|
251
|
+
stream(): unknown;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export interface FileLike extends BlobLike {
|
|
255
|
+
name: string;
|
|
256
|
+
lastModified?: number;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export type GitFileMode = '100644' | '100755' | '120000' | '160000';
|
|
260
|
+
|
|
261
|
+
export type TextEncoding =
|
|
262
|
+
| 'ascii'
|
|
263
|
+
| 'utf8'
|
|
264
|
+
| 'utf-8'
|
|
265
|
+
| 'utf16le'
|
|
266
|
+
| 'utf-16le'
|
|
267
|
+
| 'ucs2'
|
|
268
|
+
| 'ucs-2'
|
|
269
|
+
| 'base64'
|
|
270
|
+
| 'base64url'
|
|
271
|
+
| 'latin1'
|
|
272
|
+
| 'binary'
|
|
273
|
+
| 'hex';
|
|
274
|
+
|
|
231
275
|
export type CommitFileSource =
|
|
232
276
|
| string
|
|
233
277
|
| Uint8Array
|
|
234
278
|
| ArrayBuffer
|
|
235
|
-
|
|
|
236
|
-
|
|
|
279
|
+
| BlobLike
|
|
280
|
+
| FileLike
|
|
281
|
+
| ReadableStreamLike<Uint8Array | ArrayBuffer | ArrayBufferView | string>
|
|
282
|
+
| AsyncIterable<Uint8Array | ArrayBuffer | ArrayBufferView | string>
|
|
283
|
+
| Iterable<Uint8Array | ArrayBuffer | ArrayBufferView | string>;
|
|
237
284
|
|
|
238
285
|
export interface CommitFileOptions {
|
|
239
|
-
mode?:
|
|
286
|
+
mode?: GitFileMode;
|
|
240
287
|
}
|
|
241
288
|
|
|
242
289
|
export interface CommitTextFileOptions extends CommitFileOptions {
|
|
243
|
-
encoding?:
|
|
290
|
+
encoding?: TextEncoding;
|
|
244
291
|
}
|
|
245
292
|
|
|
246
293
|
export interface CommitBuilder {
|
|
247
294
|
addFile(path: string, source: CommitFileSource, options?: CommitFileOptions): CommitBuilder;
|
|
248
295
|
addFileFromString(path: string, contents: string, options?: CommitTextFileOptions): CommitBuilder;
|
|
249
296
|
deletePath(path: string): CommitBuilder;
|
|
250
|
-
send(): Promise<
|
|
297
|
+
send(): Promise<CommitResult>;
|
|
251
298
|
}
|
|
252
299
|
|
|
253
|
-
export interface
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
300
|
+
export interface RefUpdate {
|
|
301
|
+
branch: string;
|
|
302
|
+
oldSha: string;
|
|
303
|
+
newSha: string;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export type RefUpdateReason =
|
|
307
|
+
| 'precondition_failed'
|
|
308
|
+
| 'conflict'
|
|
309
|
+
| 'not_found'
|
|
310
|
+
| 'invalid'
|
|
311
|
+
| 'timeout'
|
|
312
|
+
| 'unauthorized'
|
|
313
|
+
| 'forbidden'
|
|
314
|
+
| 'unavailable'
|
|
315
|
+
| 'internal'
|
|
316
|
+
| 'failed'
|
|
317
|
+
| 'unknown';
|
|
318
|
+
|
|
319
|
+
export interface CommitResult {
|
|
320
|
+
commitSha: string;
|
|
321
|
+
treeSha: string;
|
|
322
|
+
targetBranch: string;
|
|
323
|
+
packBytes: number;
|
|
324
|
+
blobCount: number;
|
|
325
|
+
refUpdate: RefUpdate;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export interface RestoreCommitOptions extends GitStorageInvocationOptions {
|
|
329
|
+
targetBranch: string;
|
|
330
|
+
targetCommitSha: string;
|
|
331
|
+
commitMessage?: string;
|
|
332
|
+
expectedHeadSha?: string;
|
|
333
|
+
author: CommitSignature;
|
|
334
|
+
committer?: CommitSignature;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export interface RestoreCommitResult {
|
|
338
|
+
commitSha: string;
|
|
339
|
+
treeSha: string;
|
|
340
|
+
targetBranch: string;
|
|
341
|
+
packBytes: number;
|
|
342
|
+
refUpdate: RefUpdate;
|
|
269
343
|
}
|
|
270
344
|
|
|
271
345
|
// Webhook types
|
|
@@ -297,7 +371,7 @@ export interface WebhookValidationResult {
|
|
|
297
371
|
}
|
|
298
372
|
|
|
299
373
|
// Webhook event payloads
|
|
300
|
-
export interface
|
|
374
|
+
export interface RawWebhookPushEvent {
|
|
301
375
|
repository: {
|
|
302
376
|
id: string;
|
|
303
377
|
url: string;
|
|
@@ -309,7 +383,26 @@ export interface WebhookPushEvent {
|
|
|
309
383
|
pushed_at: string; // RFC3339 timestamp
|
|
310
384
|
}
|
|
311
385
|
|
|
312
|
-
export
|
|
386
|
+
export interface WebhookPushEvent {
|
|
387
|
+
type: 'push';
|
|
388
|
+
repository: {
|
|
389
|
+
id: string;
|
|
390
|
+
url: string;
|
|
391
|
+
};
|
|
392
|
+
ref: string;
|
|
393
|
+
before: string;
|
|
394
|
+
after: string;
|
|
395
|
+
customerId: string;
|
|
396
|
+
pushedAt: Date;
|
|
397
|
+
rawPushedAt: string;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
export interface WebhookUnknownEvent {
|
|
401
|
+
type: string;
|
|
402
|
+
raw: unknown;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
export type WebhookEventPayload = WebhookPushEvent | WebhookUnknownEvent;
|
|
313
406
|
|
|
314
407
|
export interface ParsedWebhookSignature {
|
|
315
408
|
timestamp: string;
|
package/src/util.ts
CHANGED
|
@@ -42,21 +42,3 @@ export async function createHmac(algorithm: string, secret: string, data: string
|
|
|
42
42
|
.map((b) => b.toString(16).padStart(2, '0'))
|
|
43
43
|
.join('');
|
|
44
44
|
}
|
|
45
|
-
|
|
46
|
-
// Keep the legacy async function for backward compatibility
|
|
47
|
-
export async function createHmacAsync(secret: string, data: string): Promise<string> {
|
|
48
|
-
const crypto = await getEnvironmentCrypto();
|
|
49
|
-
const encoder = new TextEncoder();
|
|
50
|
-
const key = await crypto.subtle.importKey(
|
|
51
|
-
'raw',
|
|
52
|
-
encoder.encode(secret),
|
|
53
|
-
{ name: 'HMAC', hash: 'SHA-256' },
|
|
54
|
-
false,
|
|
55
|
-
['sign'],
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(data));
|
|
59
|
-
return Array.from(new Uint8Array(signature))
|
|
60
|
-
.map((b) => b.toString(16).padStart(2, '0'))
|
|
61
|
-
.join('');
|
|
62
|
-
}
|
package/src/webhook.ts
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
import type {
|
|
6
6
|
ParsedWebhookSignature,
|
|
7
|
+
RawWebhookPushEvent,
|
|
7
8
|
WebhookEventPayload,
|
|
9
|
+
WebhookPushEvent,
|
|
8
10
|
WebhookValidationOptions,
|
|
9
11
|
WebhookValidationResult,
|
|
10
12
|
} from './types';
|
|
@@ -231,9 +233,9 @@ export async function validateWebhook(
|
|
|
231
233
|
|
|
232
234
|
// Parse payload
|
|
233
235
|
const payloadStr = typeof payload === 'string' ? payload : payload.toString('utf8');
|
|
234
|
-
let
|
|
236
|
+
let parsedJson: unknown;
|
|
235
237
|
try {
|
|
236
|
-
|
|
238
|
+
parsedJson = JSON.parse(payloadStr);
|
|
237
239
|
} catch {
|
|
238
240
|
return {
|
|
239
241
|
valid: false,
|
|
@@ -242,10 +244,80 @@ export async function validateWebhook(
|
|
|
242
244
|
};
|
|
243
245
|
}
|
|
244
246
|
|
|
247
|
+
const conversion = convertWebhookPayload(String(eventType), parsedJson);
|
|
248
|
+
if (!conversion.valid) {
|
|
249
|
+
return {
|
|
250
|
+
valid: false,
|
|
251
|
+
error: conversion.error,
|
|
252
|
+
timestamp: validationResult.timestamp,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
245
256
|
return {
|
|
246
257
|
valid: true,
|
|
247
258
|
eventType,
|
|
248
259
|
timestamp: validationResult.timestamp,
|
|
249
|
-
payload:
|
|
260
|
+
payload: conversion.payload,
|
|
250
261
|
};
|
|
251
262
|
}
|
|
263
|
+
|
|
264
|
+
function convertWebhookPayload(
|
|
265
|
+
eventType: string,
|
|
266
|
+
raw: unknown,
|
|
267
|
+
): { valid: true; payload: WebhookEventPayload } | { valid: false; error: string } {
|
|
268
|
+
if (eventType === 'push') {
|
|
269
|
+
if (!isRawWebhookPushEvent(raw)) {
|
|
270
|
+
return {
|
|
271
|
+
valid: false,
|
|
272
|
+
error: 'Invalid push payload',
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
valid: true,
|
|
277
|
+
payload: transformPushEvent(raw),
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
const fallbackPayload = { type: eventType, raw };
|
|
281
|
+
return {
|
|
282
|
+
valid: true,
|
|
283
|
+
payload: fallbackPayload,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function transformPushEvent(raw: RawWebhookPushEvent): WebhookPushEvent {
|
|
288
|
+
return {
|
|
289
|
+
type: 'push' as const,
|
|
290
|
+
repository: {
|
|
291
|
+
id: raw.repository.id,
|
|
292
|
+
url: raw.repository.url,
|
|
293
|
+
},
|
|
294
|
+
ref: raw.ref,
|
|
295
|
+
before: raw.before,
|
|
296
|
+
after: raw.after,
|
|
297
|
+
customerId: raw.customer_id,
|
|
298
|
+
pushedAt: new Date(raw.pushed_at),
|
|
299
|
+
rawPushedAt: raw.pushed_at,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function isRawWebhookPushEvent(value: unknown): value is RawWebhookPushEvent {
|
|
304
|
+
if (!isRecord(value)) {
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
if (!isRecord(value.repository)) {
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
return (
|
|
311
|
+
typeof value.repository.id === 'string' &&
|
|
312
|
+
typeof value.repository.url === 'string' &&
|
|
313
|
+
typeof value.ref === 'string' &&
|
|
314
|
+
typeof value.before === 'string' &&
|
|
315
|
+
typeof value.after === 'string' &&
|
|
316
|
+
typeof value.customer_id === 'string' &&
|
|
317
|
+
typeof value.pushed_at === 'string'
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
322
|
+
return typeof value === 'object' && value !== null;
|
|
323
|
+
}
|