@pierre/storage 0.3.0 → 0.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pierre/storage",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "Pierre Git Storage SDK",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/index.ts CHANGED
@@ -15,6 +15,7 @@ import {
15
15
  branchDiffResponseSchema,
16
16
  commitDiffResponseSchema,
17
17
  createBranchResponseSchema,
18
+ grepResponseSchema,
18
19
  listBranchesResponseSchema,
19
20
  listCommitsResponseSchema,
20
21
  listFilesResponseSchema,
@@ -32,6 +33,8 @@ import type {
32
33
  CreateCommitFromDiffOptions,
33
34
  CreateCommitOptions,
34
35
  CreateRepoOptions,
36
+ DeleteRepoOptions,
37
+ DeleteRepoResult,
35
38
  DiffFileState,
36
39
  FileDiff,
37
40
  FilteredFile,
@@ -45,6 +48,10 @@ import type {
45
48
  GetFileOptions,
46
49
  GetRemoteURLOptions,
47
50
  GitStorageOptions,
51
+ GrepFileMatch,
52
+ GrepLine,
53
+ GrepOptions,
54
+ GrepResult,
48
55
  ListBranchesOptions,
49
56
  ListBranchesResponse,
50
57
  ListBranchesResult,
@@ -330,6 +337,24 @@ function transformCreateBranchResult(raw: CreateBranchResponse): CreateBranchRes
330
337
  };
331
338
  }
332
339
 
340
+ function transformGrepLine(raw: { line_number: number; text: string; type: string }): GrepLine {
341
+ return {
342
+ lineNumber: raw.line_number,
343
+ text: raw.text,
344
+ type: raw.type,
345
+ };
346
+ }
347
+
348
+ function transformGrepFileMatch(raw: {
349
+ path: string;
350
+ lines: { line_number: number; text: string; type: string }[];
351
+ }): GrepFileMatch {
352
+ return {
353
+ path: raw.path,
354
+ lines: raw.lines.map(transformGrepLine),
355
+ };
356
+ }
357
+
333
358
  /**
334
359
  * Implementation of the Repo interface
335
360
  */
@@ -522,6 +547,91 @@ class RepoImpl implements Repo {
522
547
  return transformCommitDiffResult(raw);
523
548
  }
524
549
 
550
+ async grep(options: GrepOptions): Promise<GrepResult> {
551
+ const pattern = options?.query?.pattern?.trim();
552
+ if (!pattern) {
553
+ throw new Error('grep query.pattern is required');
554
+ }
555
+
556
+ const ttl = resolveInvocationTtlSeconds(options, DEFAULT_TOKEN_TTL_SECONDS);
557
+ const jwt = await this.generateJWT(this.id, {
558
+ permissions: ['git:read'],
559
+ ttl,
560
+ });
561
+
562
+ const body: Record<string, unknown> = {
563
+ query: {
564
+ pattern,
565
+ ...(typeof options.query.caseSensitive === 'boolean'
566
+ ? { case_sensitive: options.query.caseSensitive }
567
+ : {}),
568
+ },
569
+ };
570
+
571
+ if (options.ref) {
572
+ body.rev = options.ref;
573
+ }
574
+ if (Array.isArray(options.paths) && options.paths.length > 0) {
575
+ body.paths = options.paths;
576
+ }
577
+ if (options.fileFilters) {
578
+ body.file_filters = {
579
+ ...(options.fileFilters.includeGlobs
580
+ ? { include_globs: options.fileFilters.includeGlobs }
581
+ : {}),
582
+ ...(options.fileFilters.excludeGlobs
583
+ ? { exclude_globs: options.fileFilters.excludeGlobs }
584
+ : {}),
585
+ ...(options.fileFilters.extensionFilters
586
+ ? { extension_filters: options.fileFilters.extensionFilters }
587
+ : {}),
588
+ };
589
+ }
590
+ if (options.context) {
591
+ body.context = {
592
+ ...(typeof options.context.before === 'number' ? { before: options.context.before } : {}),
593
+ ...(typeof options.context.after === 'number' ? { after: options.context.after } : {}),
594
+ };
595
+ }
596
+ if (options.limits) {
597
+ body.limits = {
598
+ ...(typeof options.limits.maxLines === 'number'
599
+ ? { max_lines: options.limits.maxLines }
600
+ : {}),
601
+ ...(typeof options.limits.maxMatchesPerFile === 'number'
602
+ ? { max_matches_per_file: options.limits.maxMatchesPerFile }
603
+ : {}),
604
+ };
605
+ }
606
+ if (options.pagination) {
607
+ body.pagination = {
608
+ ...(typeof options.pagination.cursor === 'string' && options.pagination.cursor.trim() !== ''
609
+ ? { cursor: options.pagination.cursor }
610
+ : {}),
611
+ ...(typeof options.pagination.limit === 'number'
612
+ ? { limit: options.pagination.limit }
613
+ : {}),
614
+ };
615
+ }
616
+
617
+ const response = await this.api.post({ path: 'repos/grep', body }, jwt);
618
+ const raw = grepResponseSchema.parse(await response.json());
619
+
620
+ return {
621
+ query: {
622
+ pattern: raw.query.pattern,
623
+ caseSensitive: raw.query.case_sensitive,
624
+ },
625
+ repo: {
626
+ ref: raw.repo.ref,
627
+ commit: raw.repo.commit,
628
+ },
629
+ matches: raw.matches.map(transformGrepFileMatch),
630
+ nextCursor: raw.next_cursor ?? undefined,
631
+ hasMore: raw.has_more,
632
+ };
633
+ }
634
+
525
635
  async pullUpstream(options: PullUpstreamOptions = {}): Promise<void> {
526
636
  const ttl = resolveInvocationTtlSeconds(options, DEFAULT_TOKEN_TTL_SECONDS);
527
637
  const jwt = await this.generateJWT(this.id, {
@@ -820,6 +930,34 @@ export class GitStorage {
820
930
  return new RepoImpl(options.id, this.options, this.generateJWT.bind(this));
821
931
  }
822
932
 
933
+ /**
934
+ * Delete a repository by ID
935
+ * @param options The delete options containing the repo ID
936
+ * @returns The deletion result
937
+ */
938
+ async deleteRepo(options: DeleteRepoOptions): Promise<DeleteRepoResult> {
939
+ const ttl = resolveInvocationTtlSeconds(options, DEFAULT_TOKEN_TTL_SECONDS);
940
+ const jwt = await this.generateJWT(options.id, {
941
+ permissions: ['repo:write'],
942
+ ttl,
943
+ });
944
+
945
+ // Allow 404 and 409 for clearer error handling
946
+ const resp = await this.api.delete('repos/delete', jwt, { allowedStatus: [404, 409] });
947
+ if (resp.status === 404) {
948
+ throw new Error('Repository not found');
949
+ }
950
+ if (resp.status === 409) {
951
+ throw new Error('Repository already deleted');
952
+ }
953
+
954
+ const body = (await resp.json()) as { repo_id: string; message: string };
955
+ return {
956
+ repoId: body.repo_id,
957
+ message: body.message,
958
+ };
959
+ }
960
+
823
961
  /**
824
962
  * Get the current configuration
825
963
  * @returns The client configuration
package/src/schemas.ts CHANGED
@@ -128,6 +128,31 @@ export const restoreCommitResponseSchema = z.object({
128
128
  result: refUpdateResultWithOptionalsSchema,
129
129
  });
130
130
 
131
+ export const grepLineSchema = z.object({
132
+ line_number: z.number(),
133
+ text: z.string(),
134
+ type: z.string(),
135
+ });
136
+
137
+ export const grepFileMatchSchema = z.object({
138
+ path: z.string(),
139
+ lines: z.array(grepLineSchema),
140
+ });
141
+
142
+ export const grepResponseSchema = z.object({
143
+ query: z.object({
144
+ pattern: z.string(),
145
+ case_sensitive: z.boolean(),
146
+ }),
147
+ repo: z.object({
148
+ ref: z.string(),
149
+ commit: z.string(),
150
+ }),
151
+ matches: z.array(grepFileMatchSchema),
152
+ next_cursor: z.string().nullable().optional(),
153
+ has_more: z.boolean(),
154
+ });
155
+
131
156
  export const errorEnvelopeSchema = z.object({
132
157
  error: z.string(),
133
158
  });
@@ -144,3 +169,4 @@ export type GetCommitDiffResponseRaw = z.infer<typeof commitDiffResponseSchema>;
144
169
  export type CreateBranchResponseRaw = z.infer<typeof createBranchResponseSchema>;
145
170
  export type CommitPackAckRaw = z.infer<typeof commitPackAckSchema>;
146
171
  export type RestoreCommitAckRaw = z.infer<typeof restoreCommitAckSchema>;
172
+ export type GrepResponseRaw = z.infer<typeof grepResponseSchema>;
package/src/types.ts CHANGED
@@ -46,6 +46,7 @@ export interface Repo {
46
46
  listCommits(options?: ListCommitsOptions): Promise<ListCommitsResult>;
47
47
  getBranchDiff(options: GetBranchDiffOptions): Promise<GetBranchDiffResult>;
48
48
  getCommitDiff(options: GetCommitDiffOptions): Promise<GetCommitDiffResult>;
49
+ grep(options: GrepOptions): Promise<GrepResult>;
49
50
  pullUpstream(options?: PullUpstreamOptions): Promise<void>;
50
51
  restoreCommit(options: RestoreCommitOptions): Promise<RestoreCommitResult>;
51
52
  createBranch(options: CreateBranchOptions): Promise<CreateBranchResult>;
@@ -88,6 +89,15 @@ export interface CreateRepoOptions extends GitStorageInvocationOptions {
88
89
  defaultBranch?: string;
89
90
  }
90
91
 
92
+ export interface DeleteRepoOptions extends GitStorageInvocationOptions {
93
+ id: string;
94
+ }
95
+
96
+ export interface DeleteRepoResult {
97
+ repoId: string;
98
+ message: string;
99
+ }
100
+
91
101
  // Get File API types
92
102
  export interface GetFileOptions extends GitStorageInvocationOptions {
93
103
  path: string;
@@ -214,6 +224,62 @@ export interface GetCommitDiffResult {
214
224
  filteredFiles: FilteredFile[];
215
225
  }
216
226
 
227
+ // Grep API types
228
+ export interface GrepOptions extends GitStorageInvocationOptions {
229
+ ref?: string;
230
+ paths?: string[];
231
+ query: {
232
+ pattern: string;
233
+ /**
234
+ * Default is case-sensitive.
235
+ * When omitted, the server default is used.
236
+ */
237
+ caseSensitive?: boolean;
238
+ };
239
+ fileFilters?: {
240
+ includeGlobs?: string[];
241
+ excludeGlobs?: string[];
242
+ extensionFilters?: string[];
243
+ };
244
+ context?: {
245
+ before?: number;
246
+ after?: number;
247
+ };
248
+ limits?: {
249
+ maxLines?: number;
250
+ maxMatchesPerFile?: number;
251
+ };
252
+ pagination?: {
253
+ cursor?: string;
254
+ limit?: number;
255
+ };
256
+ }
257
+
258
+ export interface GrepLine {
259
+ lineNumber: number;
260
+ text: string;
261
+ type: string;
262
+ }
263
+
264
+ export interface GrepFileMatch {
265
+ path: string;
266
+ lines: GrepLine[];
267
+ }
268
+
269
+ export interface GrepResult {
270
+ query: {
271
+ pattern: string;
272
+ caseSensitive: boolean;
273
+ };
274
+ repo: {
275
+ ref: string;
276
+ commit: string;
277
+ };
278
+ matches: GrepFileMatch[];
279
+ nextCursor?: string;
280
+ hasMore: boolean;
281
+ }
282
+
217
283
  // Shared diff types
218
284
  export interface DiffStats {
219
285
  files: number;