browser-git-ops 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 +291 -92
- package/dist/git/abstractAdapter.d.ts +167 -0
- package/dist/git/abstractAdapter.d.ts.map +1 -0
- package/dist/git/adapter.d.ts +23 -1
- package/dist/git/adapter.d.ts.map +1 -1
- package/dist/git/githubAdapter.d.ts +282 -35
- package/dist/git/githubAdapter.d.ts.map +1 -1
- package/dist/git/gitlabAdapter.d.ts +220 -34
- package/dist/git/gitlabAdapter.d.ts.map +1 -1
- package/dist/index.d.ts +7 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6199 -792
- package/dist/index.js.map +4 -4
- package/dist/index.mjs +6199 -792
- package/dist/index.mjs.map +4 -4
- package/dist/virtualfs/changeTracker.d.ts +66 -0
- package/dist/virtualfs/changeTracker.d.ts.map +1 -0
- package/dist/virtualfs/conflictManager.d.ts +69 -0
- package/dist/virtualfs/conflictManager.d.ts.map +1 -0
- package/dist/virtualfs/hashUtils.d.ts +13 -0
- package/dist/virtualfs/hashUtils.d.ts.map +1 -0
- package/dist/virtualfs/indexManager.d.ts +57 -0
- package/dist/virtualfs/indexManager.d.ts.map +1 -0
- package/dist/virtualfs/indexedDatabaseStorage.d.ts +7 -0
- package/dist/virtualfs/indexedDatabaseStorage.d.ts.map +1 -0
- package/dist/virtualfs/inmemoryStorage.d.ts +8 -0
- package/dist/virtualfs/inmemoryStorage.d.ts.map +1 -0
- package/dist/virtualfs/localChangeApplier.d.ts +21 -0
- package/dist/virtualfs/localChangeApplier.d.ts.map +1 -0
- package/dist/virtualfs/localFileManager.d.ts +58 -0
- package/dist/virtualfs/localFileManager.d.ts.map +1 -0
- package/dist/virtualfs/metadataManager.d.ts +14 -0
- package/dist/virtualfs/metadataManager.d.ts.map +1 -0
- package/dist/virtualfs/opfsStorage.d.ts +2 -63
- package/dist/virtualfs/opfsStorage.d.ts.map +1 -1
- package/dist/virtualfs/remoteSynchronizer.d.ts +192 -0
- package/dist/virtualfs/remoteSynchronizer.d.ts.map +1 -0
- package/dist/virtualfs/storageBackend.d.ts +57 -4
- package/dist/virtualfs/storageBackend.d.ts.map +1 -1
- package/dist/virtualfs/types.d.ts +37 -0
- package/dist/virtualfs/types.d.ts.map +1 -1
- package/dist/virtualfs/virtualfs.d.ts +454 -87
- package/dist/virtualfs/virtualfs.d.ts.map +1 -1
- package/package.json +30 -13
- package/dist/virtualfs/indexedDbStorage.d.ts +0 -62
- package/dist/virtualfs/indexedDbStorage.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -1,145 +1,344 @@
|
|
|
1
|
+
[](https://deepwiki.com/nojaja/browser-git-ops) [](https://github.com/nojaja/browser-git-ops/blob/main/README_ja.md)
|
|
2
|
+
|
|
1
3
|
# browser-git-ops
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
ブラウザの永続化レイヤは OPFS と IndexedDB を個別のバックエンド実装として提供し、VirtualFS が抽象化して利用します。
|
|
5
|
+
A browser-native Git operations library that provides a VirtualFS and platform adapters for GitHub and GitLab. It implements multiple persistent backends (OPFS, IndexedDB, and an in-memory backend) and abstracts them behind a common VirtualFS API.
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
- **Live Demo**: https://nojaja.github.io/browser-git-ops/
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
- `VirtualFS`:ローカルワークスペースとベーススナップショットを管理し、create/update/delete の変更セットを生成します。
|
|
10
|
-
- ストレージ分離:`OpfsStorage`(OPFS 対応)と `IndexedDbStorage`(IndexedDB 対応)を個別実装として提供。
|
|
11
|
-
- `GitHubAdapter` / `GitLabAdapter`:各プラットフォーム向けのアダプタ実装(HTTP 再試行や blob/tree/commit フローを含む)。
|
|
9
|
+
**[English](./README.md)** | **[日本語](./README_ja.md)**
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
## Overview
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
- ブラウザ永続化を `BrowserStorage` から分離し、`OpfsStorage` と `IndexedDbStorage` を新規追加しました。
|
|
17
|
-
- `VirtualFS` の既定バックエンドを `OpfsStorage` に切替え、従来の `canUseOpfs`(インスタンス委譲)は廃止しました。
|
|
18
|
-
- ルートエクスポートに `IndexedDbStorage` / `OpfsStorage` を追加し、examples と E2E ヘルパーを OPFS 検出の新 API に合わせて更新しました。
|
|
19
|
-
- 単体テストを複数更新・追加し、OPFS / IndexedDB の分岐やトランザクションエラー経路のカバレッジを強化しました。
|
|
13
|
+

|
|
20
14
|
|
|
21
|
-
|
|
15
|
+
## Key Features
|
|
22
16
|
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
- **VirtualFS**: Local workspace snapshotting and change-set generation (create/update/delete)
|
|
18
|
+
- **Multiple Storage Backends**:
|
|
19
|
+
- `OpfsStorage` - Origin Private File System (OPFS)
|
|
20
|
+
- `IndexedDatabaseStorage` - IndexedDB for broader browser compatibility
|
|
21
|
+
- `InMemoryStorage` - In-memory storage for testing
|
|
22
|
+
- **Platform Adapters**: `GitHubAdapter` and `GitLabAdapter` implementing common push/pull flows via Web APIs
|
|
23
|
+
- **CORS-Free Operations**: Direct API integration without proxy workarounds
|
|
24
|
+
- **TypeScript Support**: Fully typed API with TypeScript definitions
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
- `OpfsStorage` — OPFS(origin private file system)用バックエンド
|
|
28
|
-
- `IndexedDbStorage` — IndexedDB 用バックエンド
|
|
29
|
-
- `GitHubAdapter`, `GitLabAdapter` — 各プラットフォーム向けアダプタ
|
|
26
|
+
## v0.0.5: FS-compatible API
|
|
30
27
|
|
|
31
|
-
|
|
28
|
+
- Adds Node-like filesystem methods on `VirtualFS`: `stat`, `unlink`, `mkdir`, `rmdir`, `readdir`.
|
|
29
|
+
- `Stats` objects now include Git identifiers when available (`gitBlobSha`, `gitCommitSha`).
|
|
30
|
+
- `deleteFile` is removed from the public API; use `unlink` instead.
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
import { VirtualFS, OpfsStorage, GitHubAdapter } from 'browser-git-ops'
|
|
32
|
+
## Status
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
- ✅ Core VirtualFS functionality (delta generation, index management, local edits)
|
|
35
|
+
- ✅ Persistence backends for OPFS and IndexedDB
|
|
36
|
+
- ✅ GitHubAdapter with primary push/pull flows
|
|
37
|
+
- ✅ GitLabAdapter with primary push/pull flows
|
|
39
38
|
|
|
40
|
-
|
|
41
|
-
const changes = await vfs.getChangeSet()
|
|
39
|
+
## Installation
|
|
42
40
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
### For Library Consumers (npm)
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install browser-git-ops
|
|
46
45
|
```
|
|
47
46
|
|
|
48
|
-
|
|
47
|
+
### For Development
|
|
49
48
|
|
|
50
|
-
|
|
49
|
+
```bash
|
|
50
|
+
git clone https://github.com/nojaja/browser-git-ops.git
|
|
51
|
+
cd browser-git-ops
|
|
52
|
+
npm ci
|
|
53
|
+
```
|
|
51
54
|
|
|
52
|
-
|
|
53
|
-
- `virtualfs/virtualfs.ts` - `VirtualFS` 本体
|
|
54
|
-
- `virtualfs/opfsStorage.ts` - OPFS バックエンド
|
|
55
|
-
- `virtualfs/indexedDbStorage.ts` - IndexedDB バックエンド
|
|
56
|
-
- `git/githubAdapter.ts` - GitHub 向けアダプタ
|
|
57
|
-
- `git/gitlabAdapter.ts` - GitLab 向けアダプタ
|
|
58
|
-
- `examples/` - ブラウザ実行用のサンプル UI
|
|
59
|
-
- `test/` - Jest(unit)および Playwright(e2e)テスト
|
|
55
|
+
## Usage
|
|
60
56
|
|
|
61
|
-
|
|
57
|
+
### Basic Example
|
|
62
58
|
|
|
63
|
-
|
|
59
|
+
```typescript
|
|
60
|
+
import { VirtualFS, OpfsStorage, GitHubAdapter } from 'browser-git-ops'
|
|
64
61
|
|
|
65
|
-
|
|
62
|
+
async function example() {
|
|
63
|
+
// 1. Initialize VirtualFS with OPFS backend
|
|
64
|
+
const backend = new OpfsStorage('my-workspace')
|
|
65
|
+
const vfs = new VirtualFS({ backend })
|
|
66
|
+
await vfs.init()
|
|
66
67
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
// 2. Configure adapter (GitHub or GitLab)
|
|
69
|
+
await vfs.setAdapter(null, {
|
|
70
|
+
type: 'github',
|
|
71
|
+
opts: {
|
|
72
|
+
owner: 'your-username',
|
|
73
|
+
repo: 'your-repo',
|
|
74
|
+
token: 'your-github-token',
|
|
75
|
+
branch: 'main'
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
// 3. Pull latest content from remote
|
|
80
|
+
await vfs.pull()
|
|
81
|
+
|
|
82
|
+
// 4. List files (use the FS-compatible API)
|
|
83
|
+
const files = await vfs.readdir('.')
|
|
84
|
+
console.log('Files:', files)
|
|
85
|
+
|
|
86
|
+
// 5. Make local changes
|
|
87
|
+
await vfs.writeFile('README.md', '# Hello World')
|
|
88
|
+
await vfs.writeFile('docs/guide.md', '## Getting Started')
|
|
89
|
+
|
|
90
|
+
// 6. Stat a file (Stats includes gitBlobSha/gitCommitSha when available)
|
|
91
|
+
const s = await vfs.stat('README.md')
|
|
92
|
+
console.log('size=', s.size, 'isFile=', s.isFile())
|
|
93
|
+
|
|
94
|
+
// 7. Delete a file (use unlink instead of deleteFile)
|
|
95
|
+
await vfs.unlink('docs/guide.md')
|
|
96
|
+
|
|
97
|
+
// 8. Create/remove directories
|
|
98
|
+
await vfs.mkdir('notes')
|
|
99
|
+
await vfs.rmdir('notes', { recursive: true })
|
|
100
|
+
// 9. Get change set and push
|
|
101
|
+
const changes = await vfs.getChangeSet()
|
|
102
|
+
console.log('Changes:', changes)
|
|
103
|
+
|
|
104
|
+
const index = await vfs.getIndex()
|
|
105
|
+
const result = await vfs.push({
|
|
106
|
+
parentSha: index.head,
|
|
107
|
+
message: 'Update documentation',
|
|
108
|
+
changes: changes
|
|
109
|
+
})
|
|
110
|
+
console.log('Push result:', result)
|
|
111
|
+
}
|
|
112
|
+
```
|
|
70
113
|
|
|
71
|
-
|
|
114
|
+
### Using IndexedDB Backend
|
|
72
115
|
|
|
73
|
-
|
|
116
|
+
```typescript
|
|
117
|
+
import { VirtualFS, IndexedDatabaseStorage } from 'browser-git-ops'
|
|
74
118
|
|
|
75
|
-
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
- テスト
|
|
80
|
-
- unit テストは多数あり、OPFS/IndexedDB 分岐やトランザクションエラー経路をカバー
|
|
81
|
-
- E2E は Playwright ベースのサンプル UI を含む
|
|
82
|
-
- 要検証 / ⚠️ 注意
|
|
83
|
-
- GitLab の API 実装は環境差異を考慮した追加検証が必要です。
|
|
84
|
-
- OPFS の利用可否はブラウザ実装に依存します(polyfill でテストは行っていますが、実ブラウザでの動作確認を推奨)。
|
|
119
|
+
const backend = new IndexedDatabaseStorage('my-workspace')
|
|
120
|
+
const vfs = new VirtualFS({ backend })
|
|
121
|
+
await vfs.init()
|
|
122
|
+
```
|
|
85
123
|
|
|
86
|
-
|
|
124
|
+
### Using GitLab Adapter
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
await vfs.setAdapter(null, {
|
|
128
|
+
type: 'gitlab',
|
|
129
|
+
opts: {
|
|
130
|
+
projectId: 'username/project',
|
|
131
|
+
host: 'gitlab.com',
|
|
132
|
+
token: 'your-gitlab-token',
|
|
133
|
+
branch: 'main'
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
```
|
|
87
137
|
|
|
88
|
-
##
|
|
138
|
+
## Development
|
|
89
139
|
|
|
90
|
-
|
|
140
|
+
### Build
|
|
91
141
|
|
|
92
142
|
```bash
|
|
93
|
-
|
|
94
|
-
cd APIGitWorkspace01
|
|
95
|
-
npm ci
|
|
143
|
+
npm run build # Build browser bundles and TypeScript definitions
|
|
96
144
|
```
|
|
97
145
|
|
|
98
|
-
|
|
146
|
+
This generates:
|
|
147
|
+
- `dist/index.js` - IIFE bundle for browser (global `APIGitLib`)
|
|
148
|
+
- `dist/index.mjs` - ESM bundle
|
|
149
|
+
- `dist/index.d.ts` - TypeScript definitions
|
|
150
|
+
|
|
151
|
+
### Testing
|
|
99
152
|
|
|
100
153
|
```bash
|
|
101
|
-
npm run test #
|
|
102
|
-
npm run test:
|
|
154
|
+
npm run test # Unit tests (Jest)
|
|
155
|
+
npm run test:spec # Specification tests only
|
|
156
|
+
npm run test:coverage # Tests with coverage report
|
|
157
|
+
npm run test:e2e # E2E tests (Playwright)
|
|
103
158
|
npm run lint # ESLint
|
|
104
|
-
npm run build # 型定義 + ブラウザバンドル出力 (dist/)
|
|
105
159
|
```
|
|
106
160
|
|
|
107
|
-
|
|
161
|
+
### Documentation
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
npm run docs # Generate TypeDoc documentation
|
|
165
|
+
```
|
|
108
166
|
|
|
109
|
-
|
|
167
|
+
## Project Structure
|
|
110
168
|
|
|
111
|
-
|
|
169
|
+
```
|
|
170
|
+
src/
|
|
171
|
+
├── index.ts # Package entry point
|
|
172
|
+
├── virtualfs/
|
|
173
|
+
│ ├── virtualfs.ts # VirtualFS core implementation
|
|
174
|
+
│ ├── opfsStorage.ts # OPFS storage backend
|
|
175
|
+
│ ├── indexedDatabaseStorage.ts # IndexedDB storage backend
|
|
176
|
+
│ ├── inmemoryStorage.ts # In-memory storage (for testing)
|
|
177
|
+
│ ├── changeTracker.ts # Change detection and tracking
|
|
178
|
+
│ ├── conflictManager.ts # Merge conflict resolution
|
|
179
|
+
│ ├── indexManager.ts # Index file management
|
|
180
|
+
│ └── types.ts # Type definitions
|
|
181
|
+
└── git/
|
|
182
|
+
├── abstractAdapter.ts # Base adapter interface
|
|
183
|
+
├── githubAdapter.ts # GitHub API adapter
|
|
184
|
+
└── gitlabAdapter.ts # GitLab API adapter
|
|
185
|
+
|
|
186
|
+
examples/ # Browser demo application
|
|
187
|
+
test/
|
|
188
|
+
├── unit/ # Jest unit tests
|
|
189
|
+
└── e2e/ # Playwright E2E tests
|
|
190
|
+
```
|
|
112
191
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
192
|
+
## Configuration
|
|
193
|
+
|
|
194
|
+
### GitHub Adapter
|
|
195
|
+
|
|
196
|
+
To use the GitHub adapter, you need:
|
|
197
|
+
- **Personal Access Token** with `repo` scope
|
|
198
|
+
- Repository owner and name
|
|
199
|
+
- Target branch (default: `main`)
|
|
200
|
+
|
|
201
|
+
### GitLab Adapter
|
|
202
|
+
|
|
203
|
+
To use the GitLab adapter, you need:
|
|
204
|
+
- **Personal Access Token** or **Project Access Token**
|
|
205
|
+
- Project ID (format: `username/project` or numeric ID)
|
|
206
|
+
- GitLab instance host (default: `gitlab.com`)
|
|
207
|
+
- Target branch (default: `main`)
|
|
208
|
+
|
|
209
|
+
### Browser Compatibility
|
|
210
|
+
|
|
211
|
+
- **OPFS**: Requires modern browsers with OPFS support (Chrome 102+, Edge 102+)
|
|
212
|
+
- **IndexedDB**: Broader compatibility, works in most modern browsers
|
|
213
|
+
- **CORS**: No proxy required - uses direct API authentication
|
|
214
|
+
|
|
215
|
+
## API Reference
|
|
216
|
+
|
|
217
|
+
- See [docs/typedoc-md/README.md](docs/typedoc-md/README.md).
|
|
218
|
+
|
|
219
|
+
### VirtualFS
|
|
220
|
+
|
|
221
|
+
Main class for file system operations.
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
class VirtualFS {
|
|
225
|
+
constructor(options?: { backend?: StorageBackend; logger?: Logger })
|
|
226
|
+
|
|
227
|
+
// Initialization
|
|
228
|
+
async init(): Promise<void>
|
|
229
|
+
|
|
230
|
+
// File Operations
|
|
231
|
+
async writeFile(path: string, content: string): Promise<void>
|
|
232
|
+
async readFile(path: string): Promise<string>
|
|
233
|
+
async deleteFile(path: string): Promise<void>
|
|
234
|
+
async renameFile(fromPath: string, toPath: string): Promise<void>
|
|
235
|
+
async listPaths(): Promise<string[]>
|
|
236
|
+
|
|
237
|
+
// Change Management
|
|
238
|
+
async getChangeSet(): Promise<ChangeItem[]>
|
|
239
|
+
async revertChanges(): Promise<void>
|
|
240
|
+
|
|
241
|
+
// Remote Synchronization
|
|
242
|
+
async setAdapter(adapter: any, meta?: any): Promise<void>
|
|
243
|
+
async pull(reference?: string, baseSnapshot?: Record<string, string>): Promise<any>
|
|
244
|
+
async push(input: CommitInput): Promise<any>
|
|
245
|
+
|
|
246
|
+
// Conflict Resolution
|
|
247
|
+
async getConflicts(): Promise<ConflictItem[]>
|
|
248
|
+
async resolveConflict(path: string, resolution: 'local' | 'remote'): Promise<void>
|
|
249
|
+
|
|
250
|
+
// Index Management
|
|
251
|
+
async getIndex(): Promise<IndexFile>
|
|
252
|
+
async saveIndex(): Promise<void>
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Storage Backends
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
// OPFS Backend
|
|
260
|
+
class OpfsStorage implements StorageBackend {
|
|
261
|
+
constructor(rootName?: string)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// IndexedDB Backend
|
|
265
|
+
class IndexedDatabaseStorage implements StorageBackend {
|
|
266
|
+
constructor(rootName?: string)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// In-Memory Backend (for testing)
|
|
270
|
+
class InMemoryStorage implements StorageBackend {
|
|
271
|
+
constructor()
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Platform Adapters
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
// GitHub Adapter
|
|
279
|
+
class GitHubAdapter {
|
|
280
|
+
constructor(options: {
|
|
281
|
+
owner: string
|
|
282
|
+
repo: string
|
|
283
|
+
token: string
|
|
284
|
+
branch: string
|
|
285
|
+
})
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// GitLab Adapter
|
|
289
|
+
class GitLabAdapter {
|
|
290
|
+
constructor(options: {
|
|
291
|
+
projectId: string
|
|
292
|
+
host: string
|
|
293
|
+
token: string
|
|
294
|
+
branch: string
|
|
295
|
+
})
|
|
296
|
+
}
|
|
297
|
+
```
|
|
118
298
|
|
|
119
|
-
|
|
299
|
+
## Examples
|
|
120
300
|
|
|
121
|
-
|
|
301
|
+
See the [`examples/`](examples/) directory for:
|
|
302
|
+
- Interactive browser demo with UI
|
|
303
|
+
- Playwright E2E test scenarios
|
|
304
|
+
- Multiple storage backend examples
|
|
122
305
|
|
|
123
|
-
##
|
|
306
|
+
## Contributing
|
|
124
307
|
|
|
125
|
-
|
|
126
|
-
- E2E 実行前に `npm run build` を実行する必要があります(`test:e2e` の `pretest:e2e` を参照)。
|
|
308
|
+
Contributions are welcome! Please follow these guidelines:
|
|
127
309
|
|
|
128
|
-
|
|
310
|
+
1. **Open an Issue**: For significant changes, please open an issue first to discuss your proposal
|
|
311
|
+
2. **Follow Conventions**:
|
|
312
|
+
- Use TypeScript
|
|
313
|
+
- Follow ESLint rules (`npm run lint`)
|
|
314
|
+
- Write tests for new features
|
|
315
|
+
- Update documentation as needed
|
|
316
|
+
3. **Testing**: Ensure all tests pass before submitting PR
|
|
317
|
+
```bash
|
|
318
|
+
npm run lint
|
|
319
|
+
npm run build
|
|
320
|
+
npm run test
|
|
321
|
+
npm run test:e2e
|
|
322
|
+
```
|
|
129
323
|
|
|
130
|
-
##
|
|
324
|
+
## Support
|
|
131
325
|
|
|
132
|
-
-
|
|
133
|
-
-
|
|
326
|
+
- **Issues**: https://github.com/nojaja/browser-git-ops/issues
|
|
327
|
+
- **Discussions**: https://github.com/nojaja/browser-git-ops/discussions
|
|
328
|
+
- **Documentation**: https://nojaja.github.io/browser-git-ops/
|
|
134
329
|
|
|
135
|
-
|
|
330
|
+
## License
|
|
136
331
|
|
|
137
|
-
|
|
332
|
+
MIT License - see the [LICENSE](LICENSE) file for details.
|
|
138
333
|
|
|
139
|
-
|
|
334
|
+
## Author
|
|
140
335
|
|
|
141
|
-
|
|
336
|
+
Maintained by [nojaja](https://github.com/nojaja) ([free.riccia@gmail.com](mailto:free.riccia@gmail.com))
|
|
142
337
|
|
|
143
|
-
##
|
|
338
|
+
## Acknowledgments
|
|
144
339
|
|
|
145
|
-
|
|
340
|
+
This project uses:
|
|
341
|
+
- OPFS (Origin Private File System) for persistent storage
|
|
342
|
+
- GitHub and GitLab Web APIs for remote synchronization
|
|
343
|
+
- Jest for unit testing
|
|
344
|
+
- Playwright for E2E testing
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
export type FetchWithRetryFunction = (_input: RequestInfo, _init: RequestInit, _attempts?: number, _baseDelay?: number) => Promise<Response>;
|
|
2
|
+
/**
|
|
3
|
+
* Simple logger interface for dependency injection.
|
|
4
|
+
* If a caller injects an object matching this interface, the adapter
|
|
5
|
+
* will forward debug/info/warn/error messages to it. If no logger is
|
|
6
|
+
* provided, no logging will be performed by the adapter.
|
|
7
|
+
*/
|
|
8
|
+
export interface Logger {
|
|
9
|
+
debug: (..._messages: any[]) => void;
|
|
10
|
+
info: (..._messages: any[]) => void;
|
|
11
|
+
warn: (..._messages: any[]) => void;
|
|
12
|
+
error: (..._messages: any[]) => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Compute SHA-1 of string content using Web Crypto
|
|
16
|
+
* @param content The input string
|
|
17
|
+
* @returns Promise resolving to hex-encoded SHA-1
|
|
18
|
+
*/
|
|
19
|
+
export declare function shaOf(content: string): Promise<string>;
|
|
20
|
+
/**
|
|
21
|
+
* Determine whether an HTTP status should be considered retryable
|
|
22
|
+
* @param status HTTP status code
|
|
23
|
+
* @returns true if retryable (5xx or 429)
|
|
24
|
+
*/
|
|
25
|
+
export declare function classifyStatus(status: number): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Calculate delay before retrying based on response or exponential backoff
|
|
28
|
+
* @param response Response or null when not available
|
|
29
|
+
* @param index Attempt index (0-based)
|
|
30
|
+
* @param baseDelay Base delay in ms
|
|
31
|
+
* @returns delay in milliseconds
|
|
32
|
+
*/
|
|
33
|
+
export declare function getDelayForResponse(response: Response | null, index: number, baseDelay: number): number;
|
|
34
|
+
/**
|
|
35
|
+
* Process HTTP response and throw on non-ok. If retryable, delay before throwing.
|
|
36
|
+
* @param response Fetch Response
|
|
37
|
+
* @param index Attempt index
|
|
38
|
+
* @param baseDelay Base delay in ms
|
|
39
|
+
* @returns Promise resolving to the response when ok
|
|
40
|
+
*/
|
|
41
|
+
export declare function processResponseWithDelay(response: Response, index: number, baseDelay: number): Promise<Response>;
|
|
42
|
+
/**
|
|
43
|
+
* Perform fetch with retry/backoff logic
|
|
44
|
+
* @param input RequestInfo
|
|
45
|
+
* @param init RequestInit
|
|
46
|
+
* @param attempts number of attempts
|
|
47
|
+
* @param baseDelay base delay in ms
|
|
48
|
+
* @returns Promise resolving to Response
|
|
49
|
+
*/
|
|
50
|
+
export declare function fetchWithRetry(input: RequestInfo, init: RequestInit, attempts?: number, baseDelay?: number): Promise<Response>;
|
|
51
|
+
/**
|
|
52
|
+
* Error indicating the operation is retryable and may succeed on later attempts.
|
|
53
|
+
*/
|
|
54
|
+
export declare class RetryableError extends Error {
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Error indicating the operation failed in a non-retryable way.
|
|
58
|
+
*/
|
|
59
|
+
export declare class NonRetryableError extends Error {
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Map items with limited concurrency
|
|
63
|
+
* @template T,R
|
|
64
|
+
* @param items Array of items to map
|
|
65
|
+
* @param mapper Async mapper function
|
|
66
|
+
* @param concurrency concurrency limit
|
|
67
|
+
* @returns Promise resolving to array of mapped results
|
|
68
|
+
*/
|
|
69
|
+
export declare function mapWithConcurrency<T, R>(items: T[], mapper: (_t: T) => Promise<R>, concurrency?: number): Promise<R[]>;
|
|
70
|
+
/**
|
|
71
|
+
* Abstract base class providing shared utilities for Git adapters
|
|
72
|
+
*/
|
|
73
|
+
export declare abstract class AbstractGitAdapter {
|
|
74
|
+
protected baseUrl: string;
|
|
75
|
+
protected headers: Record<string, string>;
|
|
76
|
+
protected options: any;
|
|
77
|
+
protected logger?: Logger;
|
|
78
|
+
protected maxRetries: number;
|
|
79
|
+
protected baseBackoff: number;
|
|
80
|
+
/**
|
|
81
|
+
* Construct base adapter
|
|
82
|
+
* @param options adapter options
|
|
83
|
+
*/
|
|
84
|
+
constructor(options?: any);
|
|
85
|
+
/**
|
|
86
|
+
* Delegate to shared shaOf implementation
|
|
87
|
+
* @param content input string
|
|
88
|
+
* @returns hex sha1
|
|
89
|
+
*/
|
|
90
|
+
protected shaOf(content: string): Promise<string>;
|
|
91
|
+
/**
|
|
92
|
+
* Replace or set the logger at runtime.
|
|
93
|
+
* Use this if DI happens after construction.
|
|
94
|
+
* @param logger optional logger instance to set (or undefined to clear)
|
|
95
|
+
* @returns void
|
|
96
|
+
*/
|
|
97
|
+
setLogger(logger: Logger | undefined): void;
|
|
98
|
+
/**
|
|
99
|
+
* Log debug messages when a logger is present.
|
|
100
|
+
* @param _messages messages to log (unused when no logger)
|
|
101
|
+
*/
|
|
102
|
+
protected logDebug(..._messages: any[]): void;
|
|
103
|
+
/**
|
|
104
|
+
* Log an informational message if a logger is present.
|
|
105
|
+
* @param args items to log
|
|
106
|
+
*/
|
|
107
|
+
protected logInfo(..._messages: any[]): void;
|
|
108
|
+
/**
|
|
109
|
+
* Log a warning message if a logger is present.
|
|
110
|
+
* @param args items to log
|
|
111
|
+
*/
|
|
112
|
+
protected logWarn(..._messages: any[]): void;
|
|
113
|
+
/**
|
|
114
|
+
* Log an error message if a logger is present.
|
|
115
|
+
* @param args items to log
|
|
116
|
+
*/
|
|
117
|
+
protected logError(..._messages: any[]): void;
|
|
118
|
+
/**
|
|
119
|
+
* Normalize different header-like shapes into a plain object.
|
|
120
|
+
* @param headerLike headers in Headers, array, or plain object form
|
|
121
|
+
* @returns plain header map
|
|
122
|
+
*/
|
|
123
|
+
private normalizeHeaders;
|
|
124
|
+
/**
|
|
125
|
+
* Format a fetch request into a minimal object suitable for logging.
|
|
126
|
+
* @returns formatted request log object
|
|
127
|
+
*/
|
|
128
|
+
private formatRequestForLog;
|
|
129
|
+
/**
|
|
130
|
+
* Format a fetch Response into a minimal object suitable for logging.
|
|
131
|
+
* @returns formatted response log object
|
|
132
|
+
*/
|
|
133
|
+
private formatResponseForLog;
|
|
134
|
+
/**
|
|
135
|
+
* Proxy to shared `fetchWithRetry` implementation while emitting
|
|
136
|
+
* minimal request/response logs for debugging and test inspection.
|
|
137
|
+
* @param input fetch input
|
|
138
|
+
* @param init fetch init
|
|
139
|
+
* @param attempts retry attempts
|
|
140
|
+
* @param baseDelay base delay ms
|
|
141
|
+
* @returns Promise resolving to Response
|
|
142
|
+
*/
|
|
143
|
+
protected fetchWithRetry(input: RequestInfo, init: RequestInit, attempts?: number, baseDelay?: number): Promise<Response>;
|
|
144
|
+
/**
|
|
145
|
+
* Determine if a status code is retryable
|
|
146
|
+
* @param status HTTP status code
|
|
147
|
+
* @returns boolean
|
|
148
|
+
*/
|
|
149
|
+
protected isRetryableStatus(status: number): boolean;
|
|
150
|
+
/**
|
|
151
|
+
* Compute backoff milliseconds for attempt
|
|
152
|
+
* @param attempt attempt number (1..)
|
|
153
|
+
* @returns milliseconds to wait
|
|
154
|
+
*/
|
|
155
|
+
protected backoffMs(attempt: number): number;
|
|
156
|
+
/**
|
|
157
|
+
* Map items with limited concurrency by delegating to the shared helper.
|
|
158
|
+
* @template T,R
|
|
159
|
+
* @param items items to map
|
|
160
|
+
* @param mapper async mapper
|
|
161
|
+
* @param concurrency concurrency limit
|
|
162
|
+
* @returns Promise resolving to mapped results
|
|
163
|
+
*/
|
|
164
|
+
protected mapWithConcurrency<T, R>(items: T[], mapper: (_t: T) => Promise<R>, concurrency?: number): Promise<R[]>;
|
|
165
|
+
}
|
|
166
|
+
export default AbstractGitAdapter;
|
|
167
|
+
//# sourceMappingURL=abstractAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abstractAdapter.d.ts","sourceRoot":"","sources":["../../src/git/abstractAdapter.ts"],"names":[],"mappings":"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"}
|
package/dist/git/adapter.d.ts
CHANGED
|
@@ -7,10 +7,32 @@ export interface Change {
|
|
|
7
7
|
export interface CommitResult {
|
|
8
8
|
commitSha: string;
|
|
9
9
|
}
|
|
10
|
+
export type CommitHistoryQuery = {
|
|
11
|
+
ref: string;
|
|
12
|
+
perPage?: number;
|
|
13
|
+
page?: number;
|
|
14
|
+
};
|
|
15
|
+
export type CommitSummary = {
|
|
16
|
+
sha: string;
|
|
17
|
+
message: string;
|
|
18
|
+
author: string;
|
|
19
|
+
date: string;
|
|
20
|
+
parents: string[];
|
|
21
|
+
};
|
|
22
|
+
export type CommitHistoryPage = {
|
|
23
|
+
items: CommitSummary[];
|
|
24
|
+
nextPage?: number;
|
|
25
|
+
lastPage?: number;
|
|
26
|
+
};
|
|
10
27
|
export interface GitAdapter {
|
|
11
28
|
createBlobs(_changes: Change[], _concurrency?: number): Promise<Record<string, string>>;
|
|
12
29
|
createTree(_changes: Change[], _baseTreeSha?: string): Promise<string>;
|
|
13
30
|
createCommit(_message: string, _parentSha: string, _treeSha: string): Promise<string>;
|
|
14
|
-
updateRef(
|
|
31
|
+
updateRef(_reference: string, _commitSha: string, _force?: boolean): Promise<void>;
|
|
32
|
+
listCommits?(_query: CommitHistoryQuery): Promise<CommitHistoryPage>;
|
|
33
|
+
listBranches?(_query?: import('../virtualfs/types.ts').BranchListQuery): Promise<import('../virtualfs/types.ts').BranchListPage>;
|
|
34
|
+
getRepositoryMetadata?(): Promise<import('../virtualfs/types.ts').RepositoryMetadata>;
|
|
35
|
+
resolveRef?(_reference: string): Promise<string>;
|
|
36
|
+
createBranch?(_branchName: string, _fromSha: string): Promise<import('../virtualfs/types.ts').CreateBranchResult>;
|
|
15
37
|
}
|
|
16
38
|
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/git/adapter.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAA;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,UAAU;IAEzB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAEvF,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAEtE,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAErF,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/git/adapter.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAA;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,aAAa,EAAE,CAAA;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,MAAM,WAAW,UAAU;IAEzB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAEvF,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAEtE,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAErF,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAElF,WAAW,CAAC,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAA;IAEpE,YAAY,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,uBAAuB,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,uBAAuB,EAAE,cAAc,CAAC,CAAA;IAEhI,qBAAqB,CAAC,IAAI,OAAO,CAAC,OAAO,uBAAuB,EAAE,kBAAkB,CAAC,CAAA;IAErF,UAAU,CAAC,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAEhD,YAAY,CAAC,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,uBAAuB,EAAE,kBAAkB,CAAC,CAAA;CAClH"}
|