@pierre/storage 1.0.3 → 1.2.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/README.md CHANGED
@@ -72,6 +72,22 @@ if (foundRepo) {
72
72
  }
73
73
  ```
74
74
 
75
+ ### Hydrating a Repository Without a Request
76
+
77
+ If you already know the repo metadata, you can construct a `Repo` directly:
78
+
79
+ ```typescript
80
+ const repo = store.repo({
81
+ id: 'repo-id',
82
+ defaultBranch: 'main',
83
+ createdAt: '2024-06-15T12:00:00Z',
84
+ });
85
+
86
+ // No HTTP request is made by repo()
87
+ const url = await repo.getRemoteURL();
88
+ console.log(url);
89
+ ```
90
+
75
91
  ### Grep
76
92
 
77
93
  ```typescript
@@ -166,6 +182,13 @@ const files = await repo.listFiles({
166
182
  });
167
183
  console.log(files.paths); // Array of file paths
168
184
 
185
+ // List files with mode/size and last commit metadata
186
+ const metadata = await repo.listFilesWithMetadata({
187
+ ref: 'main',
188
+ });
189
+ console.log(metadata.files[0].lastCommitSha);
190
+ console.log(metadata.commits[metadata.files[0].lastCommitSha].author);
191
+
169
192
  // List branches
170
193
  const branches = await repo.listBranches({
171
194
  limit: 10,
@@ -363,6 +386,7 @@ class GitStorage {
363
386
  constructor(options: GitStorageOptions);
364
387
  async createRepo(options?: CreateRepoOptions): Promise<Repo>;
365
388
  async findOne(options: FindOneOptions): Promise<Repo | null>;
389
+ repo(options: RepoOptions): Repo;
366
390
  getConfig(): GitStorageOptions;
367
391
  }
368
392
  ```
@@ -400,6 +424,12 @@ interface FindOneOptions {
400
424
  id: string; // Repository ID to find
401
425
  }
402
426
 
427
+ interface RepoOptions {
428
+ id: string; // Repository ID
429
+ defaultBranch?: string; // Defaults to "main"
430
+ createdAt?: string; // Defaults to ""
431
+ }
432
+
403
433
  interface Repo {
404
434
  id: string;
405
435
  getRemoteURL(options?: GetRemoteURLOptions): Promise<string>;
@@ -408,6 +438,9 @@ interface Repo {
408
438
  getFileStream(options: GetFileOptions): Promise<Response>;
409
439
  getArchiveStream(options?: ArchiveOptions): Promise<Response>;
410
440
  listFiles(options?: ListFilesOptions): Promise<ListFilesResult>;
441
+ listFilesWithMetadata(
442
+ options?: ListFilesWithMetadataOptions
443
+ ): Promise<ListFilesWithMetadataResult>;
411
444
  listBranches(options?: ListBranchesOptions): Promise<ListBranchesResult>;
412
445
  listCommits(options?: ListCommitsOptions): Promise<ListCommitsResult>;
413
446
  getNote(options: GetNoteOptions): Promise<GetNoteResult>;
@@ -444,6 +477,7 @@ interface ArchiveOptions {
444
477
 
445
478
  interface ListFilesOptions {
446
479
  ref?: string; // Branch, tag, or commit SHA
480
+ ephemeral?: boolean; // Resolve ref in ephemeral namespace
447
481
  ttl?: number;
448
482
  }
449
483
 
@@ -457,6 +491,32 @@ interface ListFilesResult {
457
491
  ref: string;
458
492
  }
459
493
 
494
+ interface ListFilesWithMetadataOptions {
495
+ ref?: string; // Branch, tag, or commit SHA
496
+ ephemeral?: boolean; // Resolve ref in ephemeral namespace
497
+ ttl?: number;
498
+ }
499
+
500
+ interface FileWithMetadata {
501
+ path: string;
502
+ mode: string;
503
+ size: number;
504
+ lastCommitSha: string;
505
+ }
506
+
507
+ interface CommitMetadata {
508
+ author: string;
509
+ date: Date;
510
+ rawDate: string;
511
+ message: string;
512
+ }
513
+
514
+ interface ListFilesWithMetadataResult {
515
+ files: FileWithMetadata[];
516
+ commits: Record<string, CommitMetadata>;
517
+ ref: string;
518
+ }
519
+
460
520
  interface GetNoteOptions {
461
521
  sha: string; // Commit SHA to look up notes for
462
522
  ttl?: number;
package/dist/index.cjs CHANGED
@@ -51,6 +51,22 @@ var listFilesResponseSchema = zod.z.object({
51
51
  paths: zod.z.array(zod.z.string()),
52
52
  ref: zod.z.string()
53
53
  });
54
+ var fileWithMetadataRawSchema = zod.z.object({
55
+ path: zod.z.string(),
56
+ mode: zod.z.string(),
57
+ size: zod.z.number(),
58
+ last_commit_sha: zod.z.string()
59
+ });
60
+ var commitMetadataRawSchema = zod.z.object({
61
+ author: zod.z.string(),
62
+ date: zod.z.string(),
63
+ message: zod.z.string()
64
+ });
65
+ var listFilesWithMetadataResponseSchema = zod.z.object({
66
+ files: zod.z.array(fileWithMetadataRawSchema),
67
+ commits: zod.z.record(commitMetadataRawSchema),
68
+ ref: zod.z.string()
69
+ });
54
70
  var branchInfoSchema = zod.z.object({
55
71
  cursor: zod.z.string(),
56
72
  name: zod.z.string(),
@@ -514,7 +530,7 @@ function concatChunks(a, b) {
514
530
 
515
531
  // package.json
516
532
  var package_default = {
517
- version: "1.0.3"};
533
+ version: "1.2.0"};
518
534
 
519
535
  // src/version.ts
520
536
  var PACKAGE_NAME = "code-storage-sdk";
@@ -1567,6 +1583,33 @@ function transformListCommitsResult(raw) {
1567
1583
  hasMore: raw.has_more
1568
1584
  };
1569
1585
  }
1586
+ function transformFileWithMetadata(raw) {
1587
+ return {
1588
+ path: raw.path,
1589
+ mode: raw.mode,
1590
+ size: raw.size,
1591
+ lastCommitSha: raw.last_commit_sha
1592
+ };
1593
+ }
1594
+ function transformCommitMetadata(raw) {
1595
+ return {
1596
+ author: raw.author,
1597
+ date: new Date(raw.date),
1598
+ rawDate: raw.date,
1599
+ message: raw.message
1600
+ };
1601
+ }
1602
+ function transformListFilesWithMetadataResult(raw) {
1603
+ const commits = {};
1604
+ for (const [sha, commit] of Object.entries(raw.commits)) {
1605
+ commits[sha] = transformCommitMetadata(commit);
1606
+ }
1607
+ return {
1608
+ files: raw.files.map(transformFileWithMetadata),
1609
+ commits,
1610
+ ref: raw.ref
1611
+ };
1612
+ }
1570
1613
  function normalizeDiffState(rawState) {
1571
1614
  if (!rawState) {
1572
1615
  return "unknown";
@@ -1851,6 +1894,29 @@ var RepoImpl = class {
1851
1894
  const raw = listFilesResponseSchema.parse(await response.json());
1852
1895
  return { paths: raw.paths, ref: raw.ref };
1853
1896
  }
1897
+ async listFilesWithMetadata(options) {
1898
+ const ttl = resolveInvocationTtlSeconds(options, DEFAULT_TOKEN_TTL_SECONDS);
1899
+ const jwt = await this.generateJWT(this.id, {
1900
+ permissions: ["git:read"],
1901
+ ttl
1902
+ });
1903
+ const params = {};
1904
+ if (options?.ref) {
1905
+ params.ref = options.ref;
1906
+ }
1907
+ if (typeof options?.ephemeral === "boolean") {
1908
+ params.ephemeral = String(options.ephemeral);
1909
+ }
1910
+ const response = await this.api.get(
1911
+ {
1912
+ path: "repos/files/metadata",
1913
+ params: Object.keys(params).length ? params : void 0
1914
+ },
1915
+ jwt
1916
+ );
1917
+ const raw = listFilesWithMetadataResponseSchema.parse(await response.json());
1918
+ return transformListFilesWithMetadataResult(raw);
1919
+ }
1854
1920
  async listBranches(options) {
1855
1921
  const ttl = resolveInvocationTtlSeconds(options, DEFAULT_TOKEN_TTL_SECONDS);
1856
1922
  const jwt = await this.generateJWT(this.id, {
@@ -2418,13 +2484,11 @@ var GitStorage = class _GitStorage {
2418
2484
  if (resp.status === 409) {
2419
2485
  throw new Error("Repository already exists");
2420
2486
  }
2421
- return new RepoImpl(
2422
- repoId,
2423
- resolvedDefaultBranch ?? "main",
2424
- (/* @__PURE__ */ new Date()).toISOString(),
2425
- this.options,
2426
- this.generateJWT.bind(this)
2427
- );
2487
+ return this.repo({
2488
+ id: repoId,
2489
+ defaultBranch: resolvedDefaultBranch ?? "main",
2490
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
2491
+ });
2428
2492
  }
2429
2493
  /**
2430
2494
  * List repositories for the authenticated organization
@@ -2470,10 +2534,23 @@ var GitStorage = class _GitStorage {
2470
2534
  const body = await resp.json();
2471
2535
  const defaultBranch = body.default_branch ?? "main";
2472
2536
  const createdAt = body.created_at ?? "";
2537
+ return this.repo({
2538
+ id: options.id,
2539
+ defaultBranch,
2540
+ createdAt
2541
+ });
2542
+ }
2543
+ /**
2544
+ * Create a Repo handle from known metadata without making an HTTP request.
2545
+ */
2546
+ repo(options) {
2547
+ if (!options || typeof options.id !== "string" || options.id.trim() === "") {
2548
+ throw new Error("repo requires a non-empty repository id.");
2549
+ }
2473
2550
  return new RepoImpl(
2474
2551
  options.id,
2475
- defaultBranch,
2476
- createdAt,
2552
+ options.defaultBranch ?? "main",
2553
+ options.createdAt ?? "",
2477
2554
  this.options,
2478
2555
  this.generateJWT.bind(this)
2479
2556
  );