0c9b918
commit 0c9b918
46 files changed
+4069 -1093
Showing 46 changed files+4069-1093
.astro/settings.jsonCHANGELOG.mdcli/bin/och.tscli/src/commands/auth.tscli/src/commands/stack/index.tscli/src/lib/config.tspackage-lock.jsonpackage.jsonscripts/ssh-server.tssrc/components/dashboard/StackCard.astrosrc/components/dashboard/UserAvatar.tsxsrc/db/schema/merge-queue.tssrc/lib/analysis.tssrc/lib/auth-basic.tssrc/lib/env-validation.tssrc/lib/git-server.tssrc/lib/git-storage.tssrc/lib/git.tssrc/lib/queue-worker.tssrc/lib/storage.tssrc/middleware.tssrc/pages/[owner]/[repo].git/[...path].tssrc/pages/[owner]/[repo].git/index.tssrc/pages/[owner]/[repo]/commit/[sha].astrosrc/pages/[owner]/[repo]/pulls/[number].astrosrc/pages/[owner]/[repo]/raw/[branch]/[...path].tssrc/pages/[owner]/[repo]/tree/[...ref].astrosrc/pages/[owner]/[repo]/tree/[branch]/[...path].astrosrc/pages/api/cron/gc.tssrc/pages/api/repos/[owner]/[repo]/branches/[branch].tssrc/pages/api/repos/[owner]/[repo]/branches/index.tssrc/pages/api/repos/[owner]/[repo]/compare/index.tssrc/pages/api/repos/[owner]/[repo]/git/push.tssrc/pages/api/repos/[owner]/[repo]/pulls/[number]/merge.tssrc/pages/api/repos/[owner]/[repo]/pulls/index.tssrc/pages/api/repos/[owner]/[repo]/queue/join.tssrc/pages/api/repos/[owner]/[repo]/security/scan.tssrc/pages/api/repos/[repoId]/commit.tssrc/pages/api/repos/index.tssrc/pages/api/stacks/index.tssrc/pages/api/stacks/user.tssrc/pages/dashboard.astrosrc/pages/git/[owner]/[repo]/git-receive-pack.tssrc/pages/git/[owner]/[repo]/git-upload-pack.tssrc/pages/git/[owner]/[repo]/info/refs.tssrc/pages/stacks.astro
▼.astro/settings.json
+1-1
| @@ -1,5 +1,5 @@ | ||
1 | 1 | { |
2 | 2 | "_variables": { |
3 | - "lastUpdateCheck": 1768929857510 | |
3 | + "lastUpdateCheck": 1769015135620 | |
4 | 4 | } |
5 | 5 | } |
6 | 6 | |
▼CHANGELOG.md
+47-0
| @@ -32,7 +32,54 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | ||
32 | 32 | - Added permission check to prevent unauthorized users from enumerating members of private repositories. |
33 | 33 | - **CLI**: Fixed incorrect binary path in `cli/package.json` that prevented global execution. |
34 | 34 | |
35 | +## [0.2.0] - 2026-01-21 | |
36 | + | |
37 | +### Added | |
38 | +- **Cloudflare R2 Storage Integration**: | |
39 | + - Full support for Cloudflare R2 as a repository storage backend. | |
40 | + - Configure with `STORAGE_TYPE=s3` and R2-specific environment variables. | |
41 | + - Repositories are automatically uploaded to R2 on creation. | |
42 | + - Repositories are automatically deleted from R2 on deletion. | |
43 | + - Git clone/push operations now work with cloud-stored repositories. | |
44 | +- **UI Modernization**: | |
45 | + - Added global toast notification system using `sonner` package. | |
46 | + - Created `src/components/ui/sonner.tsx` Shadcn UI wrapper. | |
47 | + - Added `<Toaster />` component to `BaseLayout.astro` for app-wide notifications. | |
48 | + - New `RepoSettings.tsx` React component for repository settings management. | |
49 | + - Replaced native `alert()` and `confirm()` with Shadcn `AlertDialog` components. | |
50 | +- **New Pages & Features**: | |
51 | + - `src/pages/insights.astro` - Platform-wide analytics dashboard. | |
52 | + - `src/pages/merge-queue.astro` - Merge queue management interface. | |
53 | + - `src/pages/settings/ai-review-rules.astro` - AI code review configuration. | |
54 | + - `src/pages/settings/automations.astro` - Workflow automation settings. | |
55 | + - `src/pages/settings/notification-preferences.astro` - User notification settings. | |
56 | + - `src/pages/api/user/notification-preferences.ts` - New API endpoint. | |
57 | + | |
58 | +### Changed | |
59 | +- **Database**: Migrated all schema files to use `pgTable` with PostgreSQL types. | |
60 | +- **API Routes**: Standardized logging and error handling across 60+ API files. | |
61 | +- **Drizzle ORM**: Automated TypeScript casting fixes across the codebase. | |
62 | +- **Repository Creation**: Made cloud storage sync asynchronous for faster API responses. | |
63 | +- **Git Operations**: Refactored `initRepository` to separate cloud storage concerns from git initialization. | |
64 | + | |
65 | +### Fixed | |
66 | +- **Cloud Storage**: Fixed `S3StorageAdapter` incorrectly prepending base path to S3 keys (caused `NoSuchKey` errors). | |
67 | +- **Cloud Storage**: Fixed `uploadRepoToStorage` uploading 0 files due to duplicate `initRepoInStorage` calls. | |
68 | +- **Cloud Storage**: Fixed `triggerRepoWorkflows` failing with "directory does not exist" for R2-backed repos. | |
69 | +- **Cloud Storage**: Fixed repository deletion not cleaning up objects from R2 storage. | |
70 | +- **Git Backend**: Fixed `git clone` and `git push` operations for cloud-stored repositories. | |
71 | +- **Git Operations**: Added `resolveRepoPath` for resolving logical cloud paths to local temp directories. | |
72 | +- **Admin Pages**: Fixed TypeScript errors in `admin/settings.astro` and `admin/users.astro`. | |
73 | +- **Tree Pages**: Fixed layout issues by replacing missing `RepositoryLayout.astro`. | |
74 | +- **API**: Fixed Drizzle ORM "count" property errors in admin pages. | |
75 | +- **Stacks API**: Fixed TypeScript type limitations. | |
76 | + | |
77 | +### Security | |
78 | +- **Postgres Support**: Full PostgreSQL support with `node-postgres` driver. | |
79 | +- **Environment Variables**: Improved `isCloudStorage()` detection using `STORAGE_TYPE` env directly. | |
80 | + | |
35 | 81 | ## [0.1.0] - 2026-01-14 |
36 | 82 | ### Added |
37 | 83 | - Initial release of OpenCodeHub. |
38 | 84 | - Basic repo management, issue tracking, and PR workflow. |
85 | + | |
39 | 86 | |
▼cli/bin/och.ts
+97-29
| @@ -147,6 +147,63 @@ program.addCommand(apiCommands); | ||
147 | 147 | // Shorthand Commands |
148 | 148 | // ================================ |
149 | 149 | |
150 | +// Stacking Commands (Graphite-inspired) | |
151 | +program | |
152 | + .command("stack") | |
153 | + .description("Manage stacked pull requests") | |
154 | + .command("submit") | |
155 | + .description("Submit the current branch as a stacked PR") | |
156 | + .option("-m, --message <message>", "PR Title/Description") | |
157 | + .action(async (options) => { | |
158 | + console.log("🚀 Submitting stack..."); | |
159 | + | |
160 | + // 1. Git Push | |
161 | + try { | |
162 | + const { execSync } = require('child_process'); | |
163 | + const branch = execSync('git iconv -futf-8 -tutf-8 branch --show-current').toString().trim(); | |
164 | + console.log(`Pushing branch ${branch}...`); | |
165 | + execSync(`git push origin ${branch}`); // Assumes 'origin' is set | |
166 | + } catch (e: any) { | |
167 | + console.error("Failed to push branch:", e.message); | |
168 | + return; | |
169 | + } | |
170 | + | |
171 | + // 2. Identify PR Context | |
172 | + // We need to know who we are (config) and where we are (remote) | |
173 | + // For MVP, just log instructions | |
174 | + console.log(`✅ Branch pushed. To create/update stack, visit OpenCodeHub or use 'och pr create' (coming soon).`); | |
175 | + }); | |
176 | + | |
177 | +program | |
178 | + .command("queue") | |
179 | + .description("Manage merge queue") | |
180 | + .command("join") | |
181 | + .description("Add the current PR to the merge queue") | |
182 | + .action(async () => { | |
183 | + console.log("⏳ Adding to merge queue..."); | |
184 | + | |
185 | + try { | |
186 | + const { execSync } = require('child_process'); | |
187 | + const branch = execSync('git branch --show-current').toString().trim(); | |
188 | + // Parse remote to get owner/repo | |
189 | + const remoteUrl = execSync('git remote get-url origin').toString().trim(); | |
190 | + // Regex to match http://host/owner/repo.git or git@... | |
191 | + // MVP: Assume standard format | |
192 | + // This requires robust parsing. | |
193 | + | |
194 | + console.log(`Detected branch: ${branch}`); | |
195 | + console.log(`Use 'cho queue join <pr-id>' implementation pending API client config.`); | |
196 | + | |
197 | + // Real implementation requires Authenticated API Client | |
198 | + // which involves reading ~/.och/config.json | |
199 | + // I will stub this with a TODO for the user to configure auth first. | |
200 | + | |
201 | + console.log("⚠️ Please configure CLI authentication first."); | |
202 | + } catch (e: any) { | |
203 | + console.error("Error:", e.message); | |
204 | + } | |
205 | + }); | |
206 | + | |
150 | 207 | // och push (shorthand for repo push) |
151 | 208 | program |
152 | 209 | .command("push") |
| @@ -223,40 +280,51 @@ program | ||
223 | 280 | .alias("st") |
224 | 281 | .description("Show current stack and branch status") |
225 | 282 | .action(async () => { |
226 | - const branches = await git.branchLocal(); | |
227 | - const currentBranch = branches.current; | |
228 | - const stackBranches = branches.all.filter(b => b.startsWith("stack/")); | |
229 | - | |
230 | - console.log(chalk.bold("\n📊 Status\n")); | |
231 | - console.log(`Current branch: ${chalk.cyan(currentBranch)}`); | |
232 | - | |
233 | - if (stackBranches.length > 0) { | |
234 | - console.log(`\nStack branches: ${stackBranches.length}`); | |
235 | - for (const branch of stackBranches) { | |
236 | - const isCurrent = branch === currentBranch; | |
237 | - const marker = isCurrent ? chalk.yellow("●") : chalk.dim("○"); | |
238 | - console.log(` ${marker} ${isCurrent ? chalk.bold(branch) : branch}`); | |
283 | + try { | |
284 | + const isRepo = await git.checkIsRepo(); | |
285 | + if (!isRepo) { | |
286 | + console.log(chalk.yellow("Not a git repository. Run this command inside a git repository.")); | |
287 | + return; | |
239 | 288 | } |
240 | - } | |
241 | 289 | |
242 | - // Show git status | |
243 | - const status = await git.status(); | |
244 | - if (status.modified.length > 0 || status.not_added.length > 0 || status.staged.length > 0) { | |
245 | - console.log(chalk.bold("\nChanges:")); | |
246 | - if (status.staged.length > 0) { | |
247 | - console.log(chalk.green(` Staged: ${status.staged.length} files`)); | |
248 | - } | |
249 | - if (status.modified.length > 0) { | |
250 | - console.log(chalk.yellow(` Modified: ${status.modified.length} files`)); | |
290 | + const branches = await git.branchLocal(); | |
291 | + const currentBranch = branches.current; | |
292 | + const stackBranches = branches.all.filter(b => b.startsWith("stack/")); | |
293 | + | |
294 | + console.log(chalk.bold("\n📊 Status\n")); | |
295 | + console.log(`Current branch: ${chalk.cyan(currentBranch)}`); | |
296 | + | |
297 | + if (stackBranches.length > 0) { | |
298 | + console.log(`\nStack branches: ${stackBranches.length}`); | |
299 | + for (const branch of stackBranches) { | |
300 | + const isCurrent = branch === currentBranch; | |
301 | + const marker = isCurrent ? chalk.yellow("●") : chalk.dim("○"); | |
302 | + console.log(` ${marker} ${isCurrent ? chalk.bold(branch) : branch}`); | |
303 | + } | |
251 | 304 | } |
252 | - if (status.not_added.length > 0) { | |
253 | - console.log(chalk.red(` Untracked: ${status.not_added.length} files`)); | |
305 | + | |
306 | + // Show git status | |
307 | + const status = await git.status(); | |
308 | + if (status.modified.length > 0 || status.not_added.length > 0 || status.staged.length > 0) { | |
309 | + console.log(chalk.bold("\nChanges:")); | |
310 | + if (status.staged.length > 0) { | |
311 | + console.log(chalk.green(` Staged: ${status.staged.length} files`)); | |
312 | + } | |
313 | + if (status.modified.length > 0) { | |
314 | + console.log(chalk.yellow(` Modified: ${status.modified.length} files`)); | |
315 | + } | |
316 | + if (status.not_added.length > 0) { | |
317 | + console.log(chalk.red(` Untracked: ${status.not_added.length} files`)); | |
318 | + } | |
319 | + } else { | |
320 | + console.log(chalk.dim("\nWorking tree clean")); | |
254 | 321 | } |
255 | - } else { | |
256 | - console.log(chalk.dim("\nWorking tree clean")); | |
257 | - } | |
258 | 322 | |
259 | - console.log(""); | |
323 | + console.log(""); | |
324 | + } catch (error) { | |
325 | + console.error(chalk.red("\nError checking status:")); | |
326 | + console.error(chalk.dim(error instanceof Error ? error.message : "Unknown error")); | |
327 | + } | |
260 | 328 | }); |
261 | 329 | |
262 | 330 | // och whoami (alias for auth status) |
263 | 331 | |
▼cli/src/commands/auth.ts
+1-0
| @@ -106,6 +106,7 @@ authCommands | ||
106 | 106 | saveConfig({ |
107 | 107 | serverUrl, |
108 | 108 | token, |
109 | + username, | |
109 | 110 | }); |
110 | 111 | |
111 | 112 | console.log(chalk.green("\n✓ Logged in to " + serverUrl)); |
112 | 113 | |
▼cli/src/commands/stack/index.ts
+26-4
| @@ -81,8 +81,10 @@ stackCommands | ||
81 | 81 | } |
82 | 82 | |
83 | 83 | // Parse owner/repo from remote URL |
84 | + // Handles both SSH (git@host:owner/repo) and HTTP (http://host/owner/repo.git) formats | |
84 | 85 | const remoteUrl = origin.refs.push; |
85 | - const match = remoteUrl.match(/[:/]([^/]+)\/([^/.]+)/); | |
86 | + // Match the last two path segments before .git (owner/repo) | |
87 | + const match = remoteUrl.match(/\/([^/]+)\/([^/]+?)(?:\.git)?$/); | |
86 | 88 | |
87 | 89 | if (!match) { |
88 | 90 | spinner.fail("Could not parse repository from remote URL"); |
| @@ -91,16 +93,36 @@ stackCommands | ||
91 | 93 | |
92 | 94 | const [, owner, repoName] = match; |
93 | 95 | |
94 | - // Push all stack branches | |
96 | + // Push all stack branches with authentication | |
95 | 97 | spinner.text = "Pushing branches..."; |
96 | 98 | const pushedBranches: string[] = []; |
97 | 99 | |
100 | + // Build authenticated URL for push (format: http://user:token@host/owner/repo.git) | |
101 | + const urlParts = new URL(config.serverUrl); | |
102 | + const pushUrl = `${urlParts.protocol}//${config.username || owner}:${config.token}@${urlParts.host}/${owner}/${repoName}.git`; | |
103 | + | |
104 | + console.log(chalk.dim(`\n Remote URL: ${origin.refs.push}`)); | |
105 | + console.log(chalk.dim(` Parsed: owner=${owner}, repo=${repoName}`)); | |
106 | + console.log(chalk.dim(` Push URL: ${pushUrl.replace(config.token, '[TOKEN]')}`)); | |
107 | + | |
98 | 108 | for (const branch of stackBranches) { |
99 | 109 | try { |
100 | - await git.push(["-u", "origin", branch, "--force-with-lease"]); | |
110 | + // Use the authenticated URL for pushing | |
111 | + console.log(chalk.dim(` Pushing ${branch} to authenticated URL...`)); | |
112 | + await git.push([pushUrl, branch, "--force-with-lease"]); | |
101 | 113 | pushedBranches.push(branch); |
114 | + console.log(chalk.green(` ✓ Pushed ${branch}`)); | |
102 | 115 | } catch (e) { |
103 | - console.log(chalk.yellow(`\n Warning: Could not push ${branch}`)); | |
116 | + console.log(chalk.yellow(`\n First push attempt failed: ${e instanceof Error ? e.message : 'Unknown error'}`)); | |
117 | + // Try regular push if authenticated push fails | |
118 | + try { | |
119 | + console.log(chalk.dim(` Trying fallback push to origin...`)); | |
120 | + await git.push(["-u", "origin", branch, "--force-with-lease"]); | |
121 | + pushedBranches.push(branch); | |
122 | + console.log(chalk.green(` ✓ Pushed ${branch} via origin`)); | |
123 | + } catch (e2) { | |
124 | + console.log(chalk.red(`\n ✗ Could not push ${branch}: ${e2 instanceof Error ? e2.message : 'Unknown error'}`)); | |
125 | + } | |
104 | 126 | } |
105 | 127 | } |
106 | 128 | |
107 | 129 | |
▼cli/src/lib/config.ts
+5-0
| @@ -8,6 +8,7 @@ import Conf from "conf"; | ||
8 | 8 | interface OchConfig { |
9 | 9 | serverUrl: string; |
10 | 10 | token: string; |
11 | + username?: string; | |
11 | 12 | defaultBranch?: string; |
12 | 13 | } |
13 | 14 | |
| @@ -24,6 +25,7 @@ export function getConfig(): OchConfig { | ||
24 | 25 | return { |
25 | 26 | serverUrl: config.get("serverUrl"), |
26 | 27 | token: config.get("token"), |
28 | + username: config.get("username"), | |
27 | 29 | defaultBranch: config.get("defaultBranch"), |
28 | 30 | }; |
29 | 31 | } |
| @@ -35,6 +37,9 @@ export function saveConfig(updates: Partial<OchConfig>): void { | ||
35 | 37 | if (updates.token !== undefined) { |
36 | 38 | config.set("token", updates.token); |
37 | 39 | } |
40 | + if (updates.username !== undefined) { | |
41 | + config.set("username", updates.username); | |
42 | + } | |
38 | 43 | if (updates.defaultBranch !== undefined) { |
39 | 44 | config.set("defaultBranch", updates.defaultBranch); |
40 | 45 | } |
41 | 46 | |
▼package-lock.json
+1539-508
| @@ -14,6 +14,7 @@ | ||
14 | 14 | "@astrojs/tailwind": "^5.1.0", |
15 | 15 | "@astrojs/vercel": "^7.7.0", |
16 | 16 | "@aws-sdk/client-s3": "^3.948.0", |
17 | + "@aws-sdk/lib-storage": "^3.972.0", | |
17 | 18 | "@aws-sdk/s3-request-presigner": "^3.948.0", |
18 | 19 | "@libsql/client": "^0.15.15", |
19 | 20 | "@monaco-editor/react": "^4.6.0", |
| @@ -1246,6 +1247,8 @@ | ||
1246 | 1247 | }, |
1247 | 1248 | "node_modules/@aws-crypto/crc32": { |
1248 | 1249 | "version": "5.2.0", |
1250 | + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", | |
1251 | + "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", | |
1249 | 1252 | "license": "Apache-2.0", |
1250 | 1253 | "dependencies": { |
1251 | 1254 | "@aws-crypto/util": "^5.2.0", |
| @@ -1258,6 +1261,8 @@ | ||
1258 | 1261 | }, |
1259 | 1262 | "node_modules/@aws-crypto/crc32c": { |
1260 | 1263 | "version": "5.2.0", |
1264 | + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-5.2.0.tgz", | |
1265 | + "integrity": "sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==", | |
1261 | 1266 | "license": "Apache-2.0", |
1262 | 1267 | "dependencies": { |
1263 | 1268 | "@aws-crypto/util": "^5.2.0", |
| @@ -1415,67 +1420,174 @@ | ||
1415 | 1420 | } |
1416 | 1421 | }, |
1417 | 1422 | "node_modules/@aws-sdk/client-s3": { |
1418 | - "version": "3.948.0", | |
1423 | + "version": "3.972.0", | |
1424 | + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.972.0.tgz", | |
1425 | + "integrity": "sha512-ghpDQtjZvbhbnHWymq/V5TL8NppdAGF2THAxYRRBLCJ5JRlq71T24NdovAzvzYaGdH7HtcRkgErBRsFT1gtq4g==", | |
1419 | 1426 | "license": "Apache-2.0", |
1420 | 1427 | "dependencies": { |
1421 | 1428 | "@aws-crypto/sha1-browser": "5.2.0", |
1422 | 1429 | "@aws-crypto/sha256-browser": "5.2.0", |
1423 | 1430 | "@aws-crypto/sha256-js": "5.2.0", |
1424 | - "@aws-sdk/core": "3.947.0", | |
1425 | - "@aws-sdk/credential-provider-node": "3.948.0", | |
1426 | - "@aws-sdk/middleware-bucket-endpoint": "3.936.0", | |
1427 | - "@aws-sdk/middleware-expect-continue": "3.936.0", | |
1428 | - "@aws-sdk/middleware-flexible-checksums": "3.947.0", | |
1429 | - "@aws-sdk/middleware-host-header": "3.936.0", | |
1430 | - "@aws-sdk/middleware-location-constraint": "3.936.0", | |
1431 | - "@aws-sdk/middleware-logger": "3.936.0", | |
1432 | - "@aws-sdk/middleware-recursion-detection": "3.948.0", | |
1433 | - "@aws-sdk/middleware-sdk-s3": "3.947.0", | |
1434 | - "@aws-sdk/middleware-ssec": "3.936.0", | |
1435 | - "@aws-sdk/middleware-user-agent": "3.947.0", | |
1436 | - "@aws-sdk/region-config-resolver": "3.936.0", | |
1437 | - "@aws-sdk/signature-v4-multi-region": "3.947.0", | |
1438 | - "@aws-sdk/types": "3.936.0", | |
1439 | - "@aws-sdk/util-endpoints": "3.936.0", | |
1440 | - "@aws-sdk/util-user-agent-browser": "3.936.0", | |
1441 | - "@aws-sdk/util-user-agent-node": "3.947.0", | |
1442 | - "@smithy/config-resolver": "^4.4.3", | |
1443 | - "@smithy/core": "^3.18.7", | |
1444 | - "@smithy/eventstream-serde-browser": "^4.2.5", | |
1445 | - "@smithy/eventstream-serde-config-resolver": "^4.3.5", | |
1446 | - "@smithy/eventstream-serde-node": "^4.2.5", | |
1447 | - "@smithy/fetch-http-handler": "^5.3.6", | |
1448 | - "@smithy/hash-blob-browser": "^4.2.6", | |
1449 | - "@smithy/hash-node": "^4.2.5", | |
1450 | - "@smithy/hash-stream-node": "^4.2.5", | |
1451 | - "@smithy/invalid-dependency": "^4.2.5", | |
1452 | - "@smithy/md5-js": "^4.2.5", | |
1453 | - "@smithy/middleware-content-length": "^4.2.5", | |
1454 | - "@smithy/middleware-endpoint": "^4.3.14", | |
1455 | - "@smithy/middleware-retry": "^4.4.14", | |
1456 | - "@smithy/middleware-serde": "^4.2.6", | |
1457 | - "@smithy/middleware-stack": "^4.2.5", | |
1458 | - "@smithy/node-config-provider": "^4.3.5", | |
1459 | - "@smithy/node-http-handler": "^4.4.5", | |
1460 | - "@smithy/protocol-http": "^5.3.5", | |
1461 | - "@smithy/smithy-client": "^4.9.10", | |
1462 | - "@smithy/types": "^4.9.0", | |
1463 | - "@smithy/url-parser": "^4.2.5", | |
1431 | + "@aws-sdk/core": "3.972.0", | |
1432 | + "@aws-sdk/credential-provider-node": "3.972.0", | |
1433 | + "@aws-sdk/middleware-bucket-endpoint": "3.972.0", | |
1434 | + "@aws-sdk/middleware-expect-continue": "3.972.0", | |
1435 | + "@aws-sdk/middleware-flexible-checksums": "3.972.0", | |
1436 | + "@aws-sdk/middleware-host-header": "3.972.0", | |
1437 | + "@aws-sdk/middleware-location-constraint": "3.972.0", | |
1438 | + "@aws-sdk/middleware-logger": "3.972.0", | |
1439 | + "@aws-sdk/middleware-recursion-detection": "3.972.0", | |
1440 | + "@aws-sdk/middleware-sdk-s3": "3.972.0", | |
1441 | + "@aws-sdk/middleware-ssec": "3.972.0", | |
1442 | + "@aws-sdk/middleware-user-agent": "3.972.0", | |
1443 | + "@aws-sdk/region-config-resolver": "3.972.0", | |
1444 | + "@aws-sdk/signature-v4-multi-region": "3.972.0", | |
1445 | + "@aws-sdk/types": "3.972.0", | |
1446 | + "@aws-sdk/util-endpoints": "3.972.0", | |
1447 | + "@aws-sdk/util-user-agent-browser": "3.972.0", | |
1448 | + "@aws-sdk/util-user-agent-node": "3.972.0", | |
1449 | + "@smithy/config-resolver": "^4.4.6", | |
1450 | + "@smithy/core": "^3.20.6", | |
1451 | + "@smithy/eventstream-serde-browser": "^4.2.8", | |
1452 | + "@smithy/eventstream-serde-config-resolver": "^4.3.8", | |
1453 | + "@smithy/eventstream-serde-node": "^4.2.8", | |
1454 | + "@smithy/fetch-http-handler": "^5.3.9", | |
1455 | + "@smithy/hash-blob-browser": "^4.2.9", | |
1456 | + "@smithy/hash-node": "^4.2.8", | |
1457 | + "@smithy/hash-stream-node": "^4.2.8", | |
1458 | + "@smithy/invalid-dependency": "^4.2.8", | |
1459 | + "@smithy/md5-js": "^4.2.8", | |
1460 | + "@smithy/middleware-content-length": "^4.2.8", | |
1461 | + "@smithy/middleware-endpoint": "^4.4.7", | |
1462 | + "@smithy/middleware-retry": "^4.4.23", | |
1463 | + "@smithy/middleware-serde": "^4.2.9", | |
1464 | + "@smithy/middleware-stack": "^4.2.8", | |
1465 | + "@smithy/node-config-provider": "^4.3.8", | |
1466 | + "@smithy/node-http-handler": "^4.4.8", | |
1467 | + "@smithy/protocol-http": "^5.3.8", | |
1468 | + "@smithy/smithy-client": "^4.10.8", | |
1469 | + "@smithy/types": "^4.12.0", | |
1470 | + "@smithy/url-parser": "^4.2.8", | |
1464 | 1471 | "@smithy/util-base64": "^4.3.0", |
1465 | 1472 | "@smithy/util-body-length-browser": "^4.2.0", |
1466 | 1473 | "@smithy/util-body-length-node": "^4.2.1", |
1467 | - "@smithy/util-defaults-mode-browser": "^4.3.13", | |
1468 | - "@smithy/util-defaults-mode-node": "^4.2.16", | |
1469 | - "@smithy/util-endpoints": "^3.2.5", | |
1470 | - "@smithy/util-middleware": "^4.2.5", | |
1471 | - "@smithy/util-retry": "^4.2.5", | |
1472 | - "@smithy/util-stream": "^4.5.6", | |
1474 | + "@smithy/util-defaults-mode-browser": "^4.3.22", | |
1475 | + "@smithy/util-defaults-mode-node": "^4.2.25", | |
1476 | + "@smithy/util-endpoints": "^3.2.8", | |
1477 | + "@smithy/util-middleware": "^4.2.8", | |
1478 | + "@smithy/util-retry": "^4.2.8", | |
1479 | + "@smithy/util-stream": "^4.5.10", | |
1473 | 1480 | "@smithy/util-utf8": "^4.2.0", |
1474 | - "@smithy/util-waiter": "^4.2.5", | |
1481 | + "@smithy/util-waiter": "^4.2.8", | |
1475 | 1482 | "tslib": "^2.6.2" |
1476 | 1483 | }, |
1477 | 1484 | "engines": { |
1478 | - "node": ">=18.0.0" | |
1485 | + "node": ">=20.0.0" | |
1486 | + } | |
1487 | + }, | |
1488 | + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/core": { | |
1489 | + "version": "3.972.0", | |
1490 | + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.972.0.tgz", | |
1491 | + "integrity": "sha512-nEeUW2M9F+xdIaD98F5MBcQ4ITtykj3yKbgFZ6J0JtL3bq+Z90szQ6Yy8H/BLPYXTs3V4n9ifnBo8cprRDiE6A==", | |
1492 | + "license": "Apache-2.0", | |
1493 | + "dependencies": { | |
1494 | + "@aws-sdk/types": "3.972.0", | |
1495 | + "@aws-sdk/xml-builder": "3.972.0", | |
1496 | + "@smithy/core": "^3.20.6", | |
1497 | + "@smithy/node-config-provider": "^4.3.8", | |
1498 | + "@smithy/property-provider": "^4.2.8", | |
1499 | + "@smithy/protocol-http": "^5.3.8", | |
1500 | + "@smithy/signature-v4": "^5.3.8", | |
1501 | + "@smithy/smithy-client": "^4.10.8", | |
1502 | + "@smithy/types": "^4.12.0", | |
1503 | + "@smithy/util-base64": "^4.3.0", | |
1504 | + "@smithy/util-middleware": "^4.2.8", | |
1505 | + "@smithy/util-utf8": "^4.2.0", | |
1506 | + "tslib": "^2.6.2" | |
1507 | + }, | |
1508 | + "engines": { | |
1509 | + "node": ">=20.0.0" | |
1510 | + } | |
1511 | + }, | |
1512 | + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-sdk-s3": { | |
1513 | + "version": "3.972.0", | |
1514 | + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.0.tgz", | |
1515 | + "integrity": "sha512-0bcKFXWx+NZ7tIlOo7KjQ+O2rydiHdIQahrq+fN6k9Osky29v17guy68urUKfhTobR6iY6KvxkroFWaFtTgS5w==", | |
1516 | + "license": "Apache-2.0", | |
1517 | + "dependencies": { | |
1518 | + "@aws-sdk/core": "3.972.0", | |
1519 | + "@aws-sdk/types": "3.972.0", | |
1520 | + "@aws-sdk/util-arn-parser": "3.972.0", | |
1521 | + "@smithy/core": "^3.20.6", | |
1522 | + "@smithy/node-config-provider": "^4.3.8", | |
1523 | + "@smithy/protocol-http": "^5.3.8", | |
1524 | + "@smithy/signature-v4": "^5.3.8", | |
1525 | + "@smithy/smithy-client": "^4.10.8", | |
1526 | + "@smithy/types": "^4.12.0", | |
1527 | + "@smithy/util-config-provider": "^4.2.0", | |
1528 | + "@smithy/util-middleware": "^4.2.8", | |
1529 | + "@smithy/util-stream": "^4.5.10", | |
1530 | + "@smithy/util-utf8": "^4.2.0", | |
1531 | + "tslib": "^2.6.2" | |
1532 | + }, | |
1533 | + "engines": { | |
1534 | + "node": ">=20.0.0" | |
1535 | + } | |
1536 | + }, | |
1537 | + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/signature-v4-multi-region": { | |
1538 | + "version": "3.972.0", | |
1539 | + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.972.0.tgz", | |
1540 | + "integrity": "sha512-2udiRijmjpN81Pvajje4TsjbXDZNP6K9bYUanBYH8hXa/tZG5qfGCySD+TyX0sgDxCQmEDMg3LaQdfjNHBDEgQ==", | |
1541 | + "license": "Apache-2.0", | |
1542 | + "dependencies": { | |
1543 | + "@aws-sdk/middleware-sdk-s3": "3.972.0", | |
1544 | + "@aws-sdk/types": "3.972.0", | |
1545 | + "@smithy/protocol-http": "^5.3.8", | |
1546 | + "@smithy/signature-v4": "^5.3.8", | |
1547 | + "@smithy/types": "^4.12.0", | |
1548 | + "tslib": "^2.6.2" | |
1549 | + }, | |
1550 | + "engines": { | |
1551 | + "node": ">=20.0.0" | |
1552 | + } | |
1553 | + }, | |
1554 | + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/types": { | |
1555 | + "version": "3.972.0", | |
1556 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
1557 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
1558 | + "license": "Apache-2.0", | |
1559 | + "dependencies": { | |
1560 | + "@smithy/types": "^4.12.0", | |
1561 | + "tslib": "^2.6.2" | |
1562 | + }, | |
1563 | + "engines": { | |
1564 | + "node": ">=20.0.0" | |
1565 | + } | |
1566 | + }, | |
1567 | + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/util-arn-parser": { | |
1568 | + "version": "3.972.0", | |
1569 | + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.972.0.tgz", | |
1570 | + "integrity": "sha512-RM5Mmo/KJ593iMSrALlHEOcc9YOIyOsDmS5x2NLOMdEmzv1o00fcpAkCQ02IGu1eFneBFT7uX0Mpag0HI+Cz2g==", | |
1571 | + "license": "Apache-2.0", | |
1572 | + "dependencies": { | |
1573 | + "tslib": "^2.6.2" | |
1574 | + }, | |
1575 | + "engines": { | |
1576 | + "node": ">=20.0.0" | |
1577 | + } | |
1578 | + }, | |
1579 | + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/xml-builder": { | |
1580 | + "version": "3.972.0", | |
1581 | + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.0.tgz", | |
1582 | + "integrity": "sha512-POaGMcXnozzqBUyJM3HLUZ9GR6OKJWPGJEmhtTnxZXt8B6JcJ/6K3xRJ5H/j8oovVLz8Wg6vFxAHv8lvuASxMg==", | |
1583 | + "license": "Apache-2.0", | |
1584 | + "dependencies": { | |
1585 | + "@smithy/types": "^4.12.0", | |
1586 | + "fast-xml-parser": "5.2.5", | |
1587 | + "tslib": "^2.6.2" | |
1588 | + }, | |
1589 | + "engines": { | |
1590 | + "node": ">=20.0.0" | |
1479 | 1591 | } |
1480 | 1592 | }, |
1481 | 1593 | "node_modules/@aws-sdk/client-sesv2": { |
| @@ -2040,50 +2152,103 @@ | ||
2040 | 2152 | } |
2041 | 2153 | }, |
2042 | 2154 | "node_modules/@aws-sdk/client-sso": { |
2043 | - "version": "3.948.0", | |
2155 | + "version": "3.972.0", | |
2156 | + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.972.0.tgz", | |
2157 | + "integrity": "sha512-5qw6qLiRE4SUiz0hWy878dSR13tSVhbTWhsvFT8mGHe37NRRiaobm5MA2sWD0deRAuO98djSiV+dhWXa1xIFNw==", | |
2044 | 2158 | "license": "Apache-2.0", |
2045 | 2159 | "dependencies": { |
2046 | 2160 | "@aws-crypto/sha256-browser": "5.2.0", |
2047 | 2161 | "@aws-crypto/sha256-js": "5.2.0", |
2048 | - "@aws-sdk/core": "3.947.0", | |
2049 | - "@aws-sdk/middleware-host-header": "3.936.0", | |
2050 | - "@aws-sdk/middleware-logger": "3.936.0", | |
2051 | - "@aws-sdk/middleware-recursion-detection": "3.948.0", | |
2052 | - "@aws-sdk/middleware-user-agent": "3.947.0", | |
2053 | - "@aws-sdk/region-config-resolver": "3.936.0", | |
2054 | - "@aws-sdk/types": "3.936.0", | |
2055 | - "@aws-sdk/util-endpoints": "3.936.0", | |
2056 | - "@aws-sdk/util-user-agent-browser": "3.936.0", | |
2057 | - "@aws-sdk/util-user-agent-node": "3.947.0", | |
2058 | - "@smithy/config-resolver": "^4.4.3", | |
2059 | - "@smithy/core": "^3.18.7", | |
2060 | - "@smithy/fetch-http-handler": "^5.3.6", | |
2061 | - "@smithy/hash-node": "^4.2.5", | |
2062 | - "@smithy/invalid-dependency": "^4.2.5", | |
2063 | - "@smithy/middleware-content-length": "^4.2.5", | |
2064 | - "@smithy/middleware-endpoint": "^4.3.14", | |
2065 | - "@smithy/middleware-retry": "^4.4.14", | |
2066 | - "@smithy/middleware-serde": "^4.2.6", | |
2067 | - "@smithy/middleware-stack": "^4.2.5", | |
2068 | - "@smithy/node-config-provider": "^4.3.5", | |
2069 | - "@smithy/node-http-handler": "^4.4.5", | |
2070 | - "@smithy/protocol-http": "^5.3.5", | |
2071 | - "@smithy/smithy-client": "^4.9.10", | |
2072 | - "@smithy/types": "^4.9.0", | |
2073 | - "@smithy/url-parser": "^4.2.5", | |
2162 | + "@aws-sdk/core": "3.972.0", | |
2163 | + "@aws-sdk/middleware-host-header": "3.972.0", | |
2164 | + "@aws-sdk/middleware-logger": "3.972.0", | |
2165 | + "@aws-sdk/middleware-recursion-detection": "3.972.0", | |
2166 | + "@aws-sdk/middleware-user-agent": "3.972.0", | |
2167 | + "@aws-sdk/region-config-resolver": "3.972.0", | |
2168 | + "@aws-sdk/types": "3.972.0", | |
2169 | + "@aws-sdk/util-endpoints": "3.972.0", | |
2170 | + "@aws-sdk/util-user-agent-browser": "3.972.0", | |
2171 | + "@aws-sdk/util-user-agent-node": "3.972.0", | |
2172 | + "@smithy/config-resolver": "^4.4.6", | |
2173 | + "@smithy/core": "^3.20.6", | |
2174 | + "@smithy/fetch-http-handler": "^5.3.9", | |
2175 | + "@smithy/hash-node": "^4.2.8", | |
2176 | + "@smithy/invalid-dependency": "^4.2.8", | |
2177 | + "@smithy/middleware-content-length": "^4.2.8", | |
2178 | + "@smithy/middleware-endpoint": "^4.4.7", | |
2179 | + "@smithy/middleware-retry": "^4.4.23", | |
2180 | + "@smithy/middleware-serde": "^4.2.9", | |
2181 | + "@smithy/middleware-stack": "^4.2.8", | |
2182 | + "@smithy/node-config-provider": "^4.3.8", | |
2183 | + "@smithy/node-http-handler": "^4.4.8", | |
2184 | + "@smithy/protocol-http": "^5.3.8", | |
2185 | + "@smithy/smithy-client": "^4.10.8", | |
2186 | + "@smithy/types": "^4.12.0", | |
2187 | + "@smithy/url-parser": "^4.2.8", | |
2074 | 2188 | "@smithy/util-base64": "^4.3.0", |
2075 | 2189 | "@smithy/util-body-length-browser": "^4.2.0", |
2076 | 2190 | "@smithy/util-body-length-node": "^4.2.1", |
2077 | - "@smithy/util-defaults-mode-browser": "^4.3.13", | |
2078 | - "@smithy/util-defaults-mode-node": "^4.2.16", | |
2079 | - "@smithy/util-endpoints": "^3.2.5", | |
2080 | - "@smithy/util-middleware": "^4.2.5", | |
2081 | - "@smithy/util-retry": "^4.2.5", | |
2191 | + "@smithy/util-defaults-mode-browser": "^4.3.22", | |
2192 | + "@smithy/util-defaults-mode-node": "^4.2.25", | |
2193 | + "@smithy/util-endpoints": "^3.2.8", | |
2194 | + "@smithy/util-middleware": "^4.2.8", | |
2195 | + "@smithy/util-retry": "^4.2.8", | |
2082 | 2196 | "@smithy/util-utf8": "^4.2.0", |
2083 | 2197 | "tslib": "^2.6.2" |
2084 | 2198 | }, |
2085 | 2199 | "engines": { |
2086 | - "node": ">=18.0.0" | |
2200 | + "node": ">=20.0.0" | |
2201 | + } | |
2202 | + }, | |
2203 | + "node_modules/@aws-sdk/client-sso/node_modules/@aws-sdk/core": { | |
2204 | + "version": "3.972.0", | |
2205 | + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.972.0.tgz", | |
2206 | + "integrity": "sha512-nEeUW2M9F+xdIaD98F5MBcQ4ITtykj3yKbgFZ6J0JtL3bq+Z90szQ6Yy8H/BLPYXTs3V4n9ifnBo8cprRDiE6A==", | |
2207 | + "license": "Apache-2.0", | |
2208 | + "dependencies": { | |
2209 | + "@aws-sdk/types": "3.972.0", | |
2210 | + "@aws-sdk/xml-builder": "3.972.0", | |
2211 | + "@smithy/core": "^3.20.6", | |
2212 | + "@smithy/node-config-provider": "^4.3.8", | |
2213 | + "@smithy/property-provider": "^4.2.8", | |
2214 | + "@smithy/protocol-http": "^5.3.8", | |
2215 | + "@smithy/signature-v4": "^5.3.8", | |
2216 | + "@smithy/smithy-client": "^4.10.8", | |
2217 | + "@smithy/types": "^4.12.0", | |
2218 | + "@smithy/util-base64": "^4.3.0", | |
2219 | + "@smithy/util-middleware": "^4.2.8", | |
2220 | + "@smithy/util-utf8": "^4.2.0", | |
2221 | + "tslib": "^2.6.2" | |
2222 | + }, | |
2223 | + "engines": { | |
2224 | + "node": ">=20.0.0" | |
2225 | + } | |
2226 | + }, | |
2227 | + "node_modules/@aws-sdk/client-sso/node_modules/@aws-sdk/types": { | |
2228 | + "version": "3.972.0", | |
2229 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
2230 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
2231 | + "license": "Apache-2.0", | |
2232 | + "dependencies": { | |
2233 | + "@smithy/types": "^4.12.0", | |
2234 | + "tslib": "^2.6.2" | |
2235 | + }, | |
2236 | + "engines": { | |
2237 | + "node": ">=20.0.0" | |
2238 | + } | |
2239 | + }, | |
2240 | + "node_modules/@aws-sdk/client-sso/node_modules/@aws-sdk/xml-builder": { | |
2241 | + "version": "3.972.0", | |
2242 | + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.0.tgz", | |
2243 | + "integrity": "sha512-POaGMcXnozzqBUyJM3HLUZ9GR6OKJWPGJEmhtTnxZXt8B6JcJ/6K3xRJ5H/j8oovVLz8Wg6vFxAHv8lvuASxMg==", | |
2244 | + "license": "Apache-2.0", | |
2245 | + "dependencies": { | |
2246 | + "@smithy/types": "^4.12.0", | |
2247 | + "fast-xml-parser": "5.2.5", | |
2248 | + "tslib": "^2.6.2" | |
2249 | + }, | |
2250 | + "engines": { | |
2251 | + "node": ">=20.0.0" | |
2087 | 2252 | } |
2088 | 2253 | }, |
2089 | 2254 | "node_modules/@aws-sdk/core": { |
| @@ -2108,255 +2273,841 @@ | ||
2108 | 2273 | "node": ">=18.0.0" |
2109 | 2274 | } |
2110 | 2275 | }, |
2111 | - "node_modules/@aws-sdk/credential-provider-env": { | |
2112 | - "version": "3.947.0", | |
2276 | + "node_modules/@aws-sdk/crc64-nvme": { | |
2277 | + "version": "3.972.0", | |
2278 | + "resolved": "https://registry.npmjs.org/@aws-sdk/crc64-nvme/-/crc64-nvme-3.972.0.tgz", | |
2279 | + "integrity": "sha512-ThlLhTqX68jvoIVv+pryOdb5coP1cX1/MaTbB9xkGDCbWbsqQcLqzPxuSoW1DCnAAIacmXCWpzUNOB9pv+xXQw==", | |
2113 | 2280 | "license": "Apache-2.0", |
2114 | 2281 | "dependencies": { |
2115 | - "@aws-sdk/core": "3.947.0", | |
2116 | - "@aws-sdk/types": "3.936.0", | |
2117 | - "@smithy/property-provider": "^4.2.5", | |
2118 | - "@smithy/types": "^4.9.0", | |
2282 | + "@smithy/types": "^4.12.0", | |
2119 | 2283 | "tslib": "^2.6.2" |
2120 | 2284 | }, |
2121 | 2285 | "engines": { |
2122 | - "node": ">=18.0.0" | |
2286 | + "node": ">=20.0.0" | |
2123 | 2287 | } |
2124 | 2288 | }, |
2125 | - "node_modules/@aws-sdk/credential-provider-http": { | |
2126 | - "version": "3.947.0", | |
2289 | + "node_modules/@aws-sdk/credential-provider-env": { | |
2290 | + "version": "3.972.0", | |
2291 | + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.0.tgz", | |
2292 | + "integrity": "sha512-kKHoNv+maHlPQOAhYamhap0PObd16SAb3jwaY0KYgNTiSbeXlbGUZPLioo9oA3wU10zItJzx83ClU7d7h40luA==", | |
2127 | 2293 | "license": "Apache-2.0", |
2128 | 2294 | "dependencies": { |
2129 | - "@aws-sdk/core": "3.947.0", | |
2130 | - "@aws-sdk/types": "3.936.0", | |
2131 | - "@smithy/fetch-http-handler": "^5.3.6", | |
2132 | - "@smithy/node-http-handler": "^4.4.5", | |
2133 | - "@smithy/property-provider": "^4.2.5", | |
2134 | - "@smithy/protocol-http": "^5.3.5", | |
2135 | - "@smithy/smithy-client": "^4.9.10", | |
2136 | - "@smithy/types": "^4.9.0", | |
2137 | - "@smithy/util-stream": "^4.5.6", | |
2295 | + "@aws-sdk/core": "3.972.0", | |
2296 | + "@aws-sdk/types": "3.972.0", | |
2297 | + "@smithy/property-provider": "^4.2.8", | |
2298 | + "@smithy/types": "^4.12.0", | |
2138 | 2299 | "tslib": "^2.6.2" |
2139 | 2300 | }, |
2140 | 2301 | "engines": { |
2141 | - "node": ">=18.0.0" | |
2302 | + "node": ">=20.0.0" | |
2142 | 2303 | } |
2143 | 2304 | }, |
2144 | - "node_modules/@aws-sdk/credential-provider-ini": { | |
2145 | - "version": "3.948.0", | |
2305 | + "node_modules/@aws-sdk/credential-provider-env/node_modules/@aws-sdk/core": { | |
2306 | + "version": "3.972.0", | |
2307 | + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.972.0.tgz", | |
2308 | + "integrity": "sha512-nEeUW2M9F+xdIaD98F5MBcQ4ITtykj3yKbgFZ6J0JtL3bq+Z90szQ6Yy8H/BLPYXTs3V4n9ifnBo8cprRDiE6A==", | |
2146 | 2309 | "license": "Apache-2.0", |
2147 | 2310 | "dependencies": { |
2148 | - "@aws-sdk/core": "3.947.0", | |
2149 | - "@aws-sdk/credential-provider-env": "3.947.0", | |
2150 | - "@aws-sdk/credential-provider-http": "3.947.0", | |
2151 | - "@aws-sdk/credential-provider-login": "3.948.0", | |
2152 | - "@aws-sdk/credential-provider-process": "3.947.0", | |
2153 | - "@aws-sdk/credential-provider-sso": "3.948.0", | |
2154 | - "@aws-sdk/credential-provider-web-identity": "3.948.0", | |
2155 | - "@aws-sdk/nested-clients": "3.948.0", | |
2156 | - "@aws-sdk/types": "3.936.0", | |
2157 | - "@smithy/credential-provider-imds": "^4.2.5", | |
2158 | - "@smithy/property-provider": "^4.2.5", | |
2159 | - "@smithy/shared-ini-file-loader": "^4.4.0", | |
2160 | - "@smithy/types": "^4.9.0", | |
2311 | + "@aws-sdk/types": "3.972.0", | |
2312 | + "@aws-sdk/xml-builder": "3.972.0", | |
2313 | + "@smithy/core": "^3.20.6", | |
2314 | + "@smithy/node-config-provider": "^4.3.8", | |
2315 | + "@smithy/property-provider": "^4.2.8", | |
2316 | + "@smithy/protocol-http": "^5.3.8", | |
2317 | + "@smithy/signature-v4": "^5.3.8", | |
2318 | + "@smithy/smithy-client": "^4.10.8", | |
2319 | + "@smithy/types": "^4.12.0", | |
2320 | + "@smithy/util-base64": "^4.3.0", | |
2321 | + "@smithy/util-middleware": "^4.2.8", | |
2322 | + "@smithy/util-utf8": "^4.2.0", | |
2161 | 2323 | "tslib": "^2.6.2" |
2162 | 2324 | }, |
2163 | 2325 | "engines": { |
2164 | - "node": ">=18.0.0" | |
2326 | + "node": ">=20.0.0" | |
2165 | 2327 | } |
2166 | 2328 | }, |
2167 | - "node_modules/@aws-sdk/credential-provider-login": { | |
2168 | - "version": "3.948.0", | |
2329 | + "node_modules/@aws-sdk/credential-provider-env/node_modules/@aws-sdk/types": { | |
2330 | + "version": "3.972.0", | |
2331 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
2332 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
2169 | 2333 | "license": "Apache-2.0", |
2170 | 2334 | "dependencies": { |
2171 | - "@aws-sdk/core": "3.947.0", | |
2172 | - "@aws-sdk/nested-clients": "3.948.0", | |
2173 | - "@aws-sdk/types": "3.936.0", | |
2174 | - "@smithy/property-provider": "^4.2.5", | |
2175 | - "@smithy/protocol-http": "^5.3.5", | |
2176 | - "@smithy/shared-ini-file-loader": "^4.4.0", | |
2177 | - "@smithy/types": "^4.9.0", | |
2335 | + "@smithy/types": "^4.12.0", | |
2178 | 2336 | "tslib": "^2.6.2" |
2179 | 2337 | }, |
2180 | 2338 | "engines": { |
2181 | - "node": ">=18.0.0" | |
2339 | + "node": ">=20.0.0" | |
2182 | 2340 | } |
2183 | 2341 | }, |
2184 | - "node_modules/@aws-sdk/credential-provider-node": { | |
2185 | - "version": "3.948.0", | |
2342 | + "node_modules/@aws-sdk/credential-provider-env/node_modules/@aws-sdk/xml-builder": { | |
2343 | + "version": "3.972.0", | |
2344 | + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.0.tgz", | |
2345 | + "integrity": "sha512-POaGMcXnozzqBUyJM3HLUZ9GR6OKJWPGJEmhtTnxZXt8B6JcJ/6K3xRJ5H/j8oovVLz8Wg6vFxAHv8lvuASxMg==", | |
2186 | 2346 | "license": "Apache-2.0", |
2187 | 2347 | "dependencies": { |
2188 | - "@aws-sdk/credential-provider-env": "3.947.0", | |
2189 | - "@aws-sdk/credential-provider-http": "3.947.0", | |
2190 | - "@aws-sdk/credential-provider-ini": "3.948.0", | |
2191 | - "@aws-sdk/credential-provider-process": "3.947.0", | |
2192 | - "@aws-sdk/credential-provider-sso": "3.948.0", | |
2193 | - "@aws-sdk/credential-provider-web-identity": "3.948.0", | |
2194 | - "@aws-sdk/types": "3.936.0", | |
2195 | - "@smithy/credential-provider-imds": "^4.2.5", | |
2196 | - "@smithy/property-provider": "^4.2.5", | |
2197 | - "@smithy/shared-ini-file-loader": "^4.4.0", | |
2198 | - "@smithy/types": "^4.9.0", | |
2348 | + "@smithy/types": "^4.12.0", | |
2349 | + "fast-xml-parser": "5.2.5", | |
2199 | 2350 | "tslib": "^2.6.2" |
2200 | 2351 | }, |
2201 | 2352 | "engines": { |
2202 | - "node": ">=18.0.0" | |
2353 | + "node": ">=20.0.0" | |
2203 | 2354 | } |
2204 | 2355 | }, |
2205 | - "node_modules/@aws-sdk/credential-provider-process": { | |
2206 | - "version": "3.947.0", | |
2207 | - "license": "Apache-2.0", | |
2208 | - "dependencies": { | |
2209 | - "@aws-sdk/core": "3.947.0", | |
2210 | - "@aws-sdk/types": "3.936.0", | |
2211 | - "@smithy/property-provider": "^4.2.5", | |
2212 | - "@smithy/shared-ini-file-loader": "^4.4.0", | |
2213 | - "@smithy/types": "^4.9.0", | |
2356 | + "node_modules/@aws-sdk/credential-provider-http": { | |
2357 | + "version": "3.972.0", | |
2358 | + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.0.tgz", | |
2359 | + "integrity": "sha512-xzEi81L7I5jGUbpmqEHCe7zZr54hCABdj4H+3LzktHYuovV/oqnvoDdvZpGFR0e/KAw1+PL38NbGrpG30j6qlA==", | |
2360 | + "license": "Apache-2.0", | |
2361 | + "dependencies": { | |
2362 | + "@aws-sdk/core": "3.972.0", | |
2363 | + "@aws-sdk/types": "3.972.0", | |
2364 | + "@smithy/fetch-http-handler": "^5.3.9", | |
2365 | + "@smithy/node-http-handler": "^4.4.8", | |
2366 | + "@smithy/property-provider": "^4.2.8", | |
2367 | + "@smithy/protocol-http": "^5.3.8", | |
2368 | + "@smithy/smithy-client": "^4.10.8", | |
2369 | + "@smithy/types": "^4.12.0", | |
2370 | + "@smithy/util-stream": "^4.5.10", | |
2214 | 2371 | "tslib": "^2.6.2" |
2215 | 2372 | }, |
2216 | 2373 | "engines": { |
2217 | - "node": ">=18.0.0" | |
2374 | + "node": ">=20.0.0" | |
2218 | 2375 | } |
2219 | 2376 | }, |
2220 | - "node_modules/@aws-sdk/credential-provider-sso": { | |
2221 | - "version": "3.948.0", | |
2377 | + "node_modules/@aws-sdk/credential-provider-http/node_modules/@aws-sdk/core": { | |
2378 | + "version": "3.972.0", | |
2379 | + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.972.0.tgz", | |
2380 | + "integrity": "sha512-nEeUW2M9F+xdIaD98F5MBcQ4ITtykj3yKbgFZ6J0JtL3bq+Z90szQ6Yy8H/BLPYXTs3V4n9ifnBo8cprRDiE6A==", | |
2222 | 2381 | "license": "Apache-2.0", |
2223 | 2382 | "dependencies": { |
2224 | - "@aws-sdk/client-sso": "3.948.0", | |
2225 | - "@aws-sdk/core": "3.947.0", | |
2226 | - "@aws-sdk/token-providers": "3.948.0", | |
2227 | - "@aws-sdk/types": "3.936.0", | |
2228 | - "@smithy/property-provider": "^4.2.5", | |
2229 | - "@smithy/shared-ini-file-loader": "^4.4.0", | |
2230 | - "@smithy/types": "^4.9.0", | |
2383 | + "@aws-sdk/types": "3.972.0", | |
2384 | + "@aws-sdk/xml-builder": "3.972.0", | |
2385 | + "@smithy/core": "^3.20.6", | |
2386 | + "@smithy/node-config-provider": "^4.3.8", | |
2387 | + "@smithy/property-provider": "^4.2.8", | |
2388 | + "@smithy/protocol-http": "^5.3.8", | |
2389 | + "@smithy/signature-v4": "^5.3.8", | |
2390 | + "@smithy/smithy-client": "^4.10.8", | |
2391 | + "@smithy/types": "^4.12.0", | |
2392 | + "@smithy/util-base64": "^4.3.0", | |
2393 | + "@smithy/util-middleware": "^4.2.8", | |
2394 | + "@smithy/util-utf8": "^4.2.0", | |
2231 | 2395 | "tslib": "^2.6.2" |
2232 | 2396 | }, |
2233 | 2397 | "engines": { |
2234 | - "node": ">=18.0.0" | |
2398 | + "node": ">=20.0.0" | |
2235 | 2399 | } |
2236 | 2400 | }, |
2237 | - "node_modules/@aws-sdk/credential-provider-web-identity": { | |
2238 | - "version": "3.948.0", | |
2401 | + "node_modules/@aws-sdk/credential-provider-http/node_modules/@aws-sdk/types": { | |
2402 | + "version": "3.972.0", | |
2403 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
2404 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
2239 | 2405 | "license": "Apache-2.0", |
2240 | 2406 | "dependencies": { |
2241 | - "@aws-sdk/core": "3.947.0", | |
2242 | - "@aws-sdk/nested-clients": "3.948.0", | |
2243 | - "@aws-sdk/types": "3.936.0", | |
2244 | - "@smithy/property-provider": "^4.2.5", | |
2245 | - "@smithy/shared-ini-file-loader": "^4.4.0", | |
2246 | - "@smithy/types": "^4.9.0", | |
2407 | + "@smithy/types": "^4.12.0", | |
2247 | 2408 | "tslib": "^2.6.2" |
2248 | 2409 | }, |
2249 | 2410 | "engines": { |
2250 | - "node": ">=18.0.0" | |
2411 | + "node": ">=20.0.0" | |
2251 | 2412 | } |
2252 | 2413 | }, |
2253 | - "node_modules/@aws-sdk/middleware-bucket-endpoint": { | |
2254 | - "version": "3.936.0", | |
2414 | + "node_modules/@aws-sdk/credential-provider-http/node_modules/@aws-sdk/xml-builder": { | |
2415 | + "version": "3.972.0", | |
2416 | + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.0.tgz", | |
2417 | + "integrity": "sha512-POaGMcXnozzqBUyJM3HLUZ9GR6OKJWPGJEmhtTnxZXt8B6JcJ/6K3xRJ5H/j8oovVLz8Wg6vFxAHv8lvuASxMg==", | |
2255 | 2418 | "license": "Apache-2.0", |
2256 | 2419 | "dependencies": { |
2257 | - "@aws-sdk/types": "3.936.0", | |
2258 | - "@aws-sdk/util-arn-parser": "3.893.0", | |
2259 | - "@smithy/node-config-provider": "^4.3.5", | |
2260 | - "@smithy/protocol-http": "^5.3.5", | |
2261 | - "@smithy/types": "^4.9.0", | |
2262 | - "@smithy/util-config-provider": "^4.2.0", | |
2420 | + "@smithy/types": "^4.12.0", | |
2421 | + "fast-xml-parser": "5.2.5", | |
2263 | 2422 | "tslib": "^2.6.2" |
2264 | 2423 | }, |
2265 | 2424 | "engines": { |
2266 | - "node": ">=18.0.0" | |
2425 | + "node": ">=20.0.0" | |
2267 | 2426 | } |
2268 | 2427 | }, |
2269 | - "node_modules/@aws-sdk/middleware-expect-continue": { | |
2270 | - "version": "3.936.0", | |
2271 | - "license": "Apache-2.0", | |
2272 | - "dependencies": { | |
2273 | - "@aws-sdk/types": "3.936.0", | |
2274 | - "@smithy/protocol-http": "^5.3.5", | |
2275 | - "@smithy/types": "^4.9.0", | |
2428 | + "node_modules/@aws-sdk/credential-provider-ini": { | |
2429 | + "version": "3.972.0", | |
2430 | + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.0.tgz", | |
2431 | + "integrity": "sha512-ruhAMceUIq2aknFd3jhWxmO0P0Efab5efjyIXOkI9i80g+zDY5VekeSxfqRKStEEJSKSCHDLQuOu0BnAn4Rzew==", | |
2432 | + "license": "Apache-2.0", | |
2433 | + "dependencies": { | |
2434 | + "@aws-sdk/core": "3.972.0", | |
2435 | + "@aws-sdk/credential-provider-env": "3.972.0", | |
2436 | + "@aws-sdk/credential-provider-http": "3.972.0", | |
2437 | + "@aws-sdk/credential-provider-login": "3.972.0", | |
2438 | + "@aws-sdk/credential-provider-process": "3.972.0", | |
2439 | + "@aws-sdk/credential-provider-sso": "3.972.0", | |
2440 | + "@aws-sdk/credential-provider-web-identity": "3.972.0", | |
2441 | + "@aws-sdk/nested-clients": "3.972.0", | |
2442 | + "@aws-sdk/types": "3.972.0", | |
2443 | + "@smithy/credential-provider-imds": "^4.2.8", | |
2444 | + "@smithy/property-provider": "^4.2.8", | |
2445 | + "@smithy/shared-ini-file-loader": "^4.4.3", | |
2446 | + "@smithy/types": "^4.12.0", | |
2276 | 2447 | "tslib": "^2.6.2" |
2277 | 2448 | }, |
2278 | 2449 | "engines": { |
2279 | - "node": ">=18.0.0" | |
2450 | + "node": ">=20.0.0" | |
2280 | 2451 | } |
2281 | 2452 | }, |
2282 | - "node_modules/@aws-sdk/middleware-flexible-checksums": { | |
2283 | - "version": "3.947.0", | |
2453 | + "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/core": { | |
2454 | + "version": "3.972.0", | |
2455 | + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.972.0.tgz", | |
2456 | + "integrity": "sha512-nEeUW2M9F+xdIaD98F5MBcQ4ITtykj3yKbgFZ6J0JtL3bq+Z90szQ6Yy8H/BLPYXTs3V4n9ifnBo8cprRDiE6A==", | |
2284 | 2457 | "license": "Apache-2.0", |
2285 | 2458 | "dependencies": { |
2286 | - "@aws-crypto/crc32": "5.2.0", | |
2287 | - "@aws-crypto/crc32c": "5.2.0", | |
2288 | - "@aws-crypto/util": "5.2.0", | |
2289 | - "@aws-sdk/core": "3.947.0", | |
2290 | - "@aws-sdk/types": "3.936.0", | |
2291 | - "@smithy/is-array-buffer": "^4.2.0", | |
2292 | - "@smithy/node-config-provider": "^4.3.5", | |
2293 | - "@smithy/protocol-http": "^5.3.5", | |
2294 | - "@smithy/types": "^4.9.0", | |
2295 | - "@smithy/util-middleware": "^4.2.5", | |
2296 | - "@smithy/util-stream": "^4.5.6", | |
2459 | + "@aws-sdk/types": "3.972.0", | |
2460 | + "@aws-sdk/xml-builder": "3.972.0", | |
2461 | + "@smithy/core": "^3.20.6", | |
2462 | + "@smithy/node-config-provider": "^4.3.8", | |
2463 | + "@smithy/property-provider": "^4.2.8", | |
2464 | + "@smithy/protocol-http": "^5.3.8", | |
2465 | + "@smithy/signature-v4": "^5.3.8", | |
2466 | + "@smithy/smithy-client": "^4.10.8", | |
2467 | + "@smithy/types": "^4.12.0", | |
2468 | + "@smithy/util-base64": "^4.3.0", | |
2469 | + "@smithy/util-middleware": "^4.2.8", | |
2297 | 2470 | "@smithy/util-utf8": "^4.2.0", |
2298 | 2471 | "tslib": "^2.6.2" |
2299 | 2472 | }, |
2300 | 2473 | "engines": { |
2301 | - "node": ">=18.0.0" | |
2474 | + "node": ">=20.0.0" | |
2302 | 2475 | } |
2303 | 2476 | }, |
2304 | - "node_modules/@aws-sdk/middleware-host-header": { | |
2305 | - "version": "3.936.0", | |
2477 | + "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/types": { | |
2478 | + "version": "3.972.0", | |
2479 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
2480 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
2306 | 2481 | "license": "Apache-2.0", |
2307 | 2482 | "dependencies": { |
2308 | - "@aws-sdk/types": "3.936.0", | |
2309 | - "@smithy/protocol-http": "^5.3.5", | |
2310 | - "@smithy/types": "^4.9.0", | |
2483 | + "@smithy/types": "^4.12.0", | |
2311 | 2484 | "tslib": "^2.6.2" |
2312 | 2485 | }, |
2313 | 2486 | "engines": { |
2314 | - "node": ">=18.0.0" | |
2487 | + "node": ">=20.0.0" | |
2315 | 2488 | } |
2316 | 2489 | }, |
2317 | - "node_modules/@aws-sdk/middleware-location-constraint": { | |
2318 | - "version": "3.936.0", | |
2490 | + "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/xml-builder": { | |
2491 | + "version": "3.972.0", | |
2492 | + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.0.tgz", | |
2493 | + "integrity": "sha512-POaGMcXnozzqBUyJM3HLUZ9GR6OKJWPGJEmhtTnxZXt8B6JcJ/6K3xRJ5H/j8oovVLz8Wg6vFxAHv8lvuASxMg==", | |
2319 | 2494 | "license": "Apache-2.0", |
2320 | 2495 | "dependencies": { |
2321 | - "@aws-sdk/types": "3.936.0", | |
2322 | - "@smithy/types": "^4.9.0", | |
2496 | + "@smithy/types": "^4.12.0", | |
2497 | + "fast-xml-parser": "5.2.5", | |
2323 | 2498 | "tslib": "^2.6.2" |
2324 | 2499 | }, |
2325 | 2500 | "engines": { |
2326 | - "node": ">=18.0.0" | |
2501 | + "node": ">=20.0.0" | |
2327 | 2502 | } |
2328 | 2503 | }, |
2329 | - "node_modules/@aws-sdk/middleware-logger": { | |
2330 | - "version": "3.936.0", | |
2331 | - "license": "Apache-2.0", | |
2332 | - "dependencies": { | |
2333 | - "@aws-sdk/types": "3.936.0", | |
2334 | - "@smithy/types": "^4.9.0", | |
2504 | + "node_modules/@aws-sdk/credential-provider-login": { | |
2505 | + "version": "3.972.0", | |
2506 | + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.0.tgz", | |
2507 | + "integrity": "sha512-SsrsFJsEYAJHO4N/r2P0aK6o8si6f1lprR+Ej8J731XJqTckSGs/HFHcbxOyW/iKt+LNUvZa59/VlJmjhF4bEQ==", | |
2508 | + "license": "Apache-2.0", | |
2509 | + "dependencies": { | |
2510 | + "@aws-sdk/core": "3.972.0", | |
2511 | + "@aws-sdk/nested-clients": "3.972.0", | |
2512 | + "@aws-sdk/types": "3.972.0", | |
2513 | + "@smithy/property-provider": "^4.2.8", | |
2514 | + "@smithy/protocol-http": "^5.3.8", | |
2515 | + "@smithy/shared-ini-file-loader": "^4.4.3", | |
2516 | + "@smithy/types": "^4.12.0", | |
2335 | 2517 | "tslib": "^2.6.2" |
2336 | 2518 | }, |
2337 | 2519 | "engines": { |
2338 | - "node": ">=18.0.0" | |
2520 | + "node": ">=20.0.0" | |
2339 | 2521 | } |
2340 | 2522 | }, |
2341 | - "node_modules/@aws-sdk/middleware-recursion-detection": { | |
2342 | - "version": "3.948.0", | |
2523 | + "node_modules/@aws-sdk/credential-provider-login/node_modules/@aws-sdk/core": { | |
2524 | + "version": "3.972.0", | |
2525 | + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.972.0.tgz", | |
2526 | + "integrity": "sha512-nEeUW2M9F+xdIaD98F5MBcQ4ITtykj3yKbgFZ6J0JtL3bq+Z90szQ6Yy8H/BLPYXTs3V4n9ifnBo8cprRDiE6A==", | |
2343 | 2527 | "license": "Apache-2.0", |
2344 | 2528 | "dependencies": { |
2345 | - "@aws-sdk/types": "3.936.0", | |
2346 | - "@aws/lambda-invoke-store": "^0.2.2", | |
2347 | - "@smithy/protocol-http": "^5.3.5", | |
2348 | - "@smithy/types": "^4.9.0", | |
2529 | + "@aws-sdk/types": "3.972.0", | |
2530 | + "@aws-sdk/xml-builder": "3.972.0", | |
2531 | + "@smithy/core": "^3.20.6", | |
2532 | + "@smithy/node-config-provider": "^4.3.8", | |
2533 | + "@smithy/property-provider": "^4.2.8", | |
2534 | + "@smithy/protocol-http": "^5.3.8", | |
2535 | + "@smithy/signature-v4": "^5.3.8", | |
2536 | + "@smithy/smithy-client": "^4.10.8", | |
2537 | + "@smithy/types": "^4.12.0", | |
2538 | + "@smithy/util-base64": "^4.3.0", | |
2539 | + "@smithy/util-middleware": "^4.2.8", | |
2540 | + "@smithy/util-utf8": "^4.2.0", | |
2349 | 2541 | "tslib": "^2.6.2" |
2350 | 2542 | }, |
2351 | 2543 | "engines": { |
2352 | - "node": ">=18.0.0" | |
2544 | + "node": ">=20.0.0" | |
2353 | 2545 | } |
2354 | 2546 | }, |
2355 | - "node_modules/@aws-sdk/middleware-sdk-s3": { | |
2356 | - "version": "3.947.0", | |
2547 | + "node_modules/@aws-sdk/credential-provider-login/node_modules/@aws-sdk/types": { | |
2548 | + "version": "3.972.0", | |
2549 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
2550 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
2357 | 2551 | "license": "Apache-2.0", |
2358 | 2552 | "dependencies": { |
2359 | - "@aws-sdk/core": "3.947.0", | |
2553 | + "@smithy/types": "^4.12.0", | |
2554 | + "tslib": "^2.6.2" | |
2555 | + }, | |
2556 | + "engines": { | |
2557 | + "node": ">=20.0.0" | |
2558 | + } | |
2559 | + }, | |
2560 | + "node_modules/@aws-sdk/credential-provider-login/node_modules/@aws-sdk/xml-builder": { | |
2561 | + "version": "3.972.0", | |
2562 | + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.0.tgz", | |
2563 | + "integrity": "sha512-POaGMcXnozzqBUyJM3HLUZ9GR6OKJWPGJEmhtTnxZXt8B6JcJ/6K3xRJ5H/j8oovVLz8Wg6vFxAHv8lvuASxMg==", | |
2564 | + "license": "Apache-2.0", | |
2565 | + "dependencies": { | |
2566 | + "@smithy/types": "^4.12.0", | |
2567 | + "fast-xml-parser": "5.2.5", | |
2568 | + "tslib": "^2.6.2" | |
2569 | + }, | |
2570 | + "engines": { | |
2571 | + "node": ">=20.0.0" | |
2572 | + } | |
2573 | + }, | |
2574 | + "node_modules/@aws-sdk/credential-provider-node": { | |
2575 | + "version": "3.972.0", | |
2576 | + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.0.tgz", | |
2577 | + "integrity": "sha512-wwJDpEGl6+sOygic8QKu0OHVB8SiodqF1fr5jvUlSFfS6tJss/E9vBc2aFjl7zI6KpAIYfIzIgM006lRrZtWCQ==", | |
2578 | + "license": "Apache-2.0", | |
2579 | + "dependencies": { | |
2580 | + "@aws-sdk/credential-provider-env": "3.972.0", | |
2581 | + "@aws-sdk/credential-provider-http": "3.972.0", | |
2582 | + "@aws-sdk/credential-provider-ini": "3.972.0", | |
2583 | + "@aws-sdk/credential-provider-process": "3.972.0", | |
2584 | + "@aws-sdk/credential-provider-sso": "3.972.0", | |
2585 | + "@aws-sdk/credential-provider-web-identity": "3.972.0", | |
2586 | + "@aws-sdk/types": "3.972.0", | |
2587 | + "@smithy/credential-provider-imds": "^4.2.8", | |
2588 | + "@smithy/property-provider": "^4.2.8", | |
2589 | + "@smithy/shared-ini-file-loader": "^4.4.3", | |
2590 | + "@smithy/types": "^4.12.0", | |
2591 | + "tslib": "^2.6.2" | |
2592 | + }, | |
2593 | + "engines": { | |
2594 | + "node": ">=20.0.0" | |
2595 | + } | |
2596 | + }, | |
2597 | + "node_modules/@aws-sdk/credential-provider-node/node_modules/@aws-sdk/types": { | |
2598 | + "version": "3.972.0", | |
2599 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
2600 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
2601 | + "license": "Apache-2.0", | |
2602 | + "dependencies": { | |
2603 | + "@smithy/types": "^4.12.0", | |
2604 | + "tslib": "^2.6.2" | |
2605 | + }, | |
2606 | + "engines": { | |
2607 | + "node": ">=20.0.0" | |
2608 | + } | |
2609 | + }, | |
2610 | + "node_modules/@aws-sdk/credential-provider-process": { | |
2611 | + "version": "3.972.0", | |
2612 | + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.0.tgz", | |
2613 | + "integrity": "sha512-nmzYhamLDJ8K+v3zWck79IaKMc350xZnWsf/GeaXO6E3MewSzd3lYkTiMi7lEp3/UwDm9NHfPguoPm+mhlSWQQ==", | |
2614 | + "license": "Apache-2.0", | |
2615 | + "dependencies": { | |
2616 | + "@aws-sdk/core": "3.972.0", | |
2617 | + "@aws-sdk/types": "3.972.0", | |
2618 | + "@smithy/property-provider": "^4.2.8", | |
2619 | + "@smithy/shared-ini-file-loader": "^4.4.3", | |
2620 | + "@smithy/types": "^4.12.0", | |
2621 | + "tslib": "^2.6.2" | |
2622 | + }, | |
2623 | + "engines": { | |
2624 | + "node": ">=20.0.0" | |
2625 | + } | |
2626 | + }, | |
2627 | + "node_modules/@aws-sdk/credential-provider-process/node_modules/@aws-sdk/core": { | |
2628 | + "version": "3.972.0", | |
2629 | + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.972.0.tgz", | |
2630 | + "integrity": "sha512-nEeUW2M9F+xdIaD98F5MBcQ4ITtykj3yKbgFZ6J0JtL3bq+Z90szQ6Yy8H/BLPYXTs3V4n9ifnBo8cprRDiE6A==", | |
2631 | + "license": "Apache-2.0", | |
2632 | + "dependencies": { | |
2633 | + "@aws-sdk/types": "3.972.0", | |
2634 | + "@aws-sdk/xml-builder": "3.972.0", | |
2635 | + "@smithy/core": "^3.20.6", | |
2636 | + "@smithy/node-config-provider": "^4.3.8", | |
2637 | + "@smithy/property-provider": "^4.2.8", | |
2638 | + "@smithy/protocol-http": "^5.3.8", | |
2639 | + "@smithy/signature-v4": "^5.3.8", | |
2640 | + "@smithy/smithy-client": "^4.10.8", | |
2641 | + "@smithy/types": "^4.12.0", | |
2642 | + "@smithy/util-base64": "^4.3.0", | |
2643 | + "@smithy/util-middleware": "^4.2.8", | |
2644 | + "@smithy/util-utf8": "^4.2.0", | |
2645 | + "tslib": "^2.6.2" | |
2646 | + }, | |
2647 | + "engines": { | |
2648 | + "node": ">=20.0.0" | |
2649 | + } | |
2650 | + }, | |
2651 | + "node_modules/@aws-sdk/credential-provider-process/node_modules/@aws-sdk/types": { | |
2652 | + "version": "3.972.0", | |
2653 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
2654 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
2655 | + "license": "Apache-2.0", | |
2656 | + "dependencies": { | |
2657 | + "@smithy/types": "^4.12.0", | |
2658 | + "tslib": "^2.6.2" | |
2659 | + }, | |
2660 | + "engines": { | |
2661 | + "node": ">=20.0.0" | |
2662 | + } | |
2663 | + }, | |
2664 | + "node_modules/@aws-sdk/credential-provider-process/node_modules/@aws-sdk/xml-builder": { | |
2665 | + "version": "3.972.0", | |
2666 | + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.0.tgz", | |
2667 | + "integrity": "sha512-POaGMcXnozzqBUyJM3HLUZ9GR6OKJWPGJEmhtTnxZXt8B6JcJ/6K3xRJ5H/j8oovVLz8Wg6vFxAHv8lvuASxMg==", | |
2668 | + "license": "Apache-2.0", | |
2669 | + "dependencies": { | |
2670 | + "@smithy/types": "^4.12.0", | |
2671 | + "fast-xml-parser": "5.2.5", | |
2672 | + "tslib": "^2.6.2" | |
2673 | + }, | |
2674 | + "engines": { | |
2675 | + "node": ">=20.0.0" | |
2676 | + } | |
2677 | + }, | |
2678 | + "node_modules/@aws-sdk/credential-provider-sso": { | |
2679 | + "version": "3.972.0", | |
2680 | + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.0.tgz", | |
2681 | + "integrity": "sha512-6mYyfk1SrMZ15cH9T53yAF4YSnvq4yU1Xlgm3nqV1gZVQzmF5kr4t/F3BU3ygbvzi4uSwWxG3I3TYYS5eMlAyg==", | |
2682 | + "license": "Apache-2.0", | |
2683 | + "dependencies": { | |
2684 | + "@aws-sdk/client-sso": "3.972.0", | |
2685 | + "@aws-sdk/core": "3.972.0", | |
2686 | + "@aws-sdk/token-providers": "3.972.0", | |
2687 | + "@aws-sdk/types": "3.972.0", | |
2688 | + "@smithy/property-provider": "^4.2.8", | |
2689 | + "@smithy/shared-ini-file-loader": "^4.4.3", | |
2690 | + "@smithy/types": "^4.12.0", | |
2691 | + "tslib": "^2.6.2" | |
2692 | + }, | |
2693 | + "engines": { | |
2694 | + "node": ">=20.0.0" | |
2695 | + } | |
2696 | + }, | |
2697 | + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/core": { | |
2698 | + "version": "3.972.0", | |
2699 | + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.972.0.tgz", | |
2700 | + "integrity": "sha512-nEeUW2M9F+xdIaD98F5MBcQ4ITtykj3yKbgFZ6J0JtL3bq+Z90szQ6Yy8H/BLPYXTs3V4n9ifnBo8cprRDiE6A==", | |
2701 | + "license": "Apache-2.0", | |
2702 | + "dependencies": { | |
2703 | + "@aws-sdk/types": "3.972.0", | |
2704 | + "@aws-sdk/xml-builder": "3.972.0", | |
2705 | + "@smithy/core": "^3.20.6", | |
2706 | + "@smithy/node-config-provider": "^4.3.8", | |
2707 | + "@smithy/property-provider": "^4.2.8", | |
2708 | + "@smithy/protocol-http": "^5.3.8", | |
2709 | + "@smithy/signature-v4": "^5.3.8", | |
2710 | + "@smithy/smithy-client": "^4.10.8", | |
2711 | + "@smithy/types": "^4.12.0", | |
2712 | + "@smithy/util-base64": "^4.3.0", | |
2713 | + "@smithy/util-middleware": "^4.2.8", | |
2714 | + "@smithy/util-utf8": "^4.2.0", | |
2715 | + "tslib": "^2.6.2" | |
2716 | + }, | |
2717 | + "engines": { | |
2718 | + "node": ">=20.0.0" | |
2719 | + } | |
2720 | + }, | |
2721 | + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/types": { | |
2722 | + "version": "3.972.0", | |
2723 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
2724 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
2725 | + "license": "Apache-2.0", | |
2726 | + "dependencies": { | |
2727 | + "@smithy/types": "^4.12.0", | |
2728 | + "tslib": "^2.6.2" | |
2729 | + }, | |
2730 | + "engines": { | |
2731 | + "node": ">=20.0.0" | |
2732 | + } | |
2733 | + }, | |
2734 | + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/xml-builder": { | |
2735 | + "version": "3.972.0", | |
2736 | + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.0.tgz", | |
2737 | + "integrity": "sha512-POaGMcXnozzqBUyJM3HLUZ9GR6OKJWPGJEmhtTnxZXt8B6JcJ/6K3xRJ5H/j8oovVLz8Wg6vFxAHv8lvuASxMg==", | |
2738 | + "license": "Apache-2.0", | |
2739 | + "dependencies": { | |
2740 | + "@smithy/types": "^4.12.0", | |
2741 | + "fast-xml-parser": "5.2.5", | |
2742 | + "tslib": "^2.6.2" | |
2743 | + }, | |
2744 | + "engines": { | |
2745 | + "node": ">=20.0.0" | |
2746 | + } | |
2747 | + }, | |
2748 | + "node_modules/@aws-sdk/credential-provider-web-identity": { | |
2749 | + "version": "3.972.0", | |
2750 | + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.0.tgz", | |
2751 | + "integrity": "sha512-vsJXBGL8H54kz4T6do3p5elATj5d1izVGUXMluRJntm9/I0be/zUYtdd4oDTM2kSUmd4Zhyw3fMQ9lw7CVhd4A==", | |
2752 | + "license": "Apache-2.0", | |
2753 | + "dependencies": { | |
2754 | + "@aws-sdk/core": "3.972.0", | |
2755 | + "@aws-sdk/nested-clients": "3.972.0", | |
2756 | + "@aws-sdk/types": "3.972.0", | |
2757 | + "@smithy/property-provider": "^4.2.8", | |
2758 | + "@smithy/shared-ini-file-loader": "^4.4.3", | |
2759 | + "@smithy/types": "^4.12.0", | |
2760 | + "tslib": "^2.6.2" | |
2761 | + }, | |
2762 | + "engines": { | |
2763 | + "node": ">=20.0.0" | |
2764 | + } | |
2765 | + }, | |
2766 | + "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@aws-sdk/core": { | |
2767 | + "version": "3.972.0", | |
2768 | + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.972.0.tgz", | |
2769 | + "integrity": "sha512-nEeUW2M9F+xdIaD98F5MBcQ4ITtykj3yKbgFZ6J0JtL3bq+Z90szQ6Yy8H/BLPYXTs3V4n9ifnBo8cprRDiE6A==", | |
2770 | + "license": "Apache-2.0", | |
2771 | + "dependencies": { | |
2772 | + "@aws-sdk/types": "3.972.0", | |
2773 | + "@aws-sdk/xml-builder": "3.972.0", | |
2774 | + "@smithy/core": "^3.20.6", | |
2775 | + "@smithy/node-config-provider": "^4.3.8", | |
2776 | + "@smithy/property-provider": "^4.2.8", | |
2777 | + "@smithy/protocol-http": "^5.3.8", | |
2778 | + "@smithy/signature-v4": "^5.3.8", | |
2779 | + "@smithy/smithy-client": "^4.10.8", | |
2780 | + "@smithy/types": "^4.12.0", | |
2781 | + "@smithy/util-base64": "^4.3.0", | |
2782 | + "@smithy/util-middleware": "^4.2.8", | |
2783 | + "@smithy/util-utf8": "^4.2.0", | |
2784 | + "tslib": "^2.6.2" | |
2785 | + }, | |
2786 | + "engines": { | |
2787 | + "node": ">=20.0.0" | |
2788 | + } | |
2789 | + }, | |
2790 | + "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@aws-sdk/types": { | |
2791 | + "version": "3.972.0", | |
2792 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
2793 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
2794 | + "license": "Apache-2.0", | |
2795 | + "dependencies": { | |
2796 | + "@smithy/types": "^4.12.0", | |
2797 | + "tslib": "^2.6.2" | |
2798 | + }, | |
2799 | + "engines": { | |
2800 | + "node": ">=20.0.0" | |
2801 | + } | |
2802 | + }, | |
2803 | + "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@aws-sdk/xml-builder": { | |
2804 | + "version": "3.972.0", | |
2805 | + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.0.tgz", | |
2806 | + "integrity": "sha512-POaGMcXnozzqBUyJM3HLUZ9GR6OKJWPGJEmhtTnxZXt8B6JcJ/6K3xRJ5H/j8oovVLz8Wg6vFxAHv8lvuASxMg==", | |
2807 | + "license": "Apache-2.0", | |
2808 | + "dependencies": { | |
2809 | + "@smithy/types": "^4.12.0", | |
2810 | + "fast-xml-parser": "5.2.5", | |
2811 | + "tslib": "^2.6.2" | |
2812 | + }, | |
2813 | + "engines": { | |
2814 | + "node": ">=20.0.0" | |
2815 | + } | |
2816 | + }, | |
2817 | + "node_modules/@aws-sdk/lib-storage": { | |
2818 | + "version": "3.972.0", | |
2819 | + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.972.0.tgz", | |
2820 | + "integrity": "sha512-4xNJ1B4zKzvwEedNuhJRoLmrNCfHorwBFvZjjR/bFSWxxCK0Mh5NSarB4sgeycVyZjCwOGFTFHxk4RtXi9JksA==", | |
2821 | + "license": "Apache-2.0", | |
2822 | + "dependencies": { | |
2823 | + "@smithy/abort-controller": "^4.2.8", | |
2824 | + "@smithy/middleware-endpoint": "^4.4.7", | |
2825 | + "@smithy/smithy-client": "^4.10.8", | |
2826 | + "buffer": "5.6.0", | |
2827 | + "events": "3.3.0", | |
2828 | + "stream-browserify": "3.0.0", | |
2829 | + "tslib": "^2.6.2" | |
2830 | + }, | |
2831 | + "engines": { | |
2832 | + "node": ">=20.0.0" | |
2833 | + }, | |
2834 | + "peerDependencies": { | |
2835 | + "@aws-sdk/client-s3": "3.972.0" | |
2836 | + } | |
2837 | + }, | |
2838 | + "node_modules/@aws-sdk/lib-storage/node_modules/buffer": { | |
2839 | + "version": "5.6.0", | |
2840 | + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", | |
2841 | + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", | |
2842 | + "license": "MIT", | |
2843 | + "dependencies": { | |
2844 | + "base64-js": "^1.0.2", | |
2845 | + "ieee754": "^1.1.4" | |
2846 | + } | |
2847 | + }, | |
2848 | + "node_modules/@aws-sdk/middleware-bucket-endpoint": { | |
2849 | + "version": "3.972.0", | |
2850 | + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.972.0.tgz", | |
2851 | + "integrity": "sha512-IrIjAehc3PrseAGfk2ldtAf+N0BAnNHR1DCZIDh9IAcFrTVWC3Fi9KJdtabrxcY3Onpt/8opOco4EIEAWgMz7A==", | |
2852 | + "license": "Apache-2.0", | |
2853 | + "dependencies": { | |
2854 | + "@aws-sdk/types": "3.972.0", | |
2855 | + "@aws-sdk/util-arn-parser": "3.972.0", | |
2856 | + "@smithy/node-config-provider": "^4.3.8", | |
2857 | + "@smithy/protocol-http": "^5.3.8", | |
2858 | + "@smithy/types": "^4.12.0", | |
2859 | + "@smithy/util-config-provider": "^4.2.0", | |
2860 | + "tslib": "^2.6.2" | |
2861 | + }, | |
2862 | + "engines": { | |
2863 | + "node": ">=20.0.0" | |
2864 | + } | |
2865 | + }, | |
2866 | + "node_modules/@aws-sdk/middleware-bucket-endpoint/node_modules/@aws-sdk/types": { | |
2867 | + "version": "3.972.0", | |
2868 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
2869 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
2870 | + "license": "Apache-2.0", | |
2871 | + "dependencies": { | |
2872 | + "@smithy/types": "^4.12.0", | |
2873 | + "tslib": "^2.6.2" | |
2874 | + }, | |
2875 | + "engines": { | |
2876 | + "node": ">=20.0.0" | |
2877 | + } | |
2878 | + }, | |
2879 | + "node_modules/@aws-sdk/middleware-bucket-endpoint/node_modules/@aws-sdk/util-arn-parser": { | |
2880 | + "version": "3.972.0", | |
2881 | + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.972.0.tgz", | |
2882 | + "integrity": "sha512-RM5Mmo/KJ593iMSrALlHEOcc9YOIyOsDmS5x2NLOMdEmzv1o00fcpAkCQ02IGu1eFneBFT7uX0Mpag0HI+Cz2g==", | |
2883 | + "license": "Apache-2.0", | |
2884 | + "dependencies": { | |
2885 | + "tslib": "^2.6.2" | |
2886 | + }, | |
2887 | + "engines": { | |
2888 | + "node": ">=20.0.0" | |
2889 | + } | |
2890 | + }, | |
2891 | + "node_modules/@aws-sdk/middleware-expect-continue": { | |
2892 | + "version": "3.972.0", | |
2893 | + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.972.0.tgz", | |
2894 | + "integrity": "sha512-xyhDoY0qse8MvQC4RZCpT5WoIQ4/kwqv71Dh1s3mdXjL789Z4a6L/khBTSXECR5+egSZ960AInj3aR+CrezDRQ==", | |
2895 | + "license": "Apache-2.0", | |
2896 | + "dependencies": { | |
2897 | + "@aws-sdk/types": "3.972.0", | |
2898 | + "@smithy/protocol-http": "^5.3.8", | |
2899 | + "@smithy/types": "^4.12.0", | |
2900 | + "tslib": "^2.6.2" | |
2901 | + }, | |
2902 | + "engines": { | |
2903 | + "node": ">=20.0.0" | |
2904 | + } | |
2905 | + }, | |
2906 | + "node_modules/@aws-sdk/middleware-expect-continue/node_modules/@aws-sdk/types": { | |
2907 | + "version": "3.972.0", | |
2908 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
2909 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
2910 | + "license": "Apache-2.0", | |
2911 | + "dependencies": { | |
2912 | + "@smithy/types": "^4.12.0", | |
2913 | + "tslib": "^2.6.2" | |
2914 | + }, | |
2915 | + "engines": { | |
2916 | + "node": ">=20.0.0" | |
2917 | + } | |
2918 | + }, | |
2919 | + "node_modules/@aws-sdk/middleware-flexible-checksums": { | |
2920 | + "version": "3.972.0", | |
2921 | + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.972.0.tgz", | |
2922 | + "integrity": "sha512-zxK0ezmT7fLEPJ650S8QBc4rGDq5+5rdsLnnuZ6hPaZE4/+QtUoTw+gSDETyiWodNcRuz2ZWnqi17K+7nKtSRg==", | |
2923 | + "license": "Apache-2.0", | |
2924 | + "dependencies": { | |
2925 | + "@aws-crypto/crc32": "5.2.0", | |
2926 | + "@aws-crypto/crc32c": "5.2.0", | |
2927 | + "@aws-crypto/util": "5.2.0", | |
2928 | + "@aws-sdk/core": "3.972.0", | |
2929 | + "@aws-sdk/crc64-nvme": "3.972.0", | |
2930 | + "@aws-sdk/types": "3.972.0", | |
2931 | + "@smithy/is-array-buffer": "^4.2.0", | |
2932 | + "@smithy/node-config-provider": "^4.3.8", | |
2933 | + "@smithy/protocol-http": "^5.3.8", | |
2934 | + "@smithy/types": "^4.12.0", | |
2935 | + "@smithy/util-middleware": "^4.2.8", | |
2936 | + "@smithy/util-stream": "^4.5.10", | |
2937 | + "@smithy/util-utf8": "^4.2.0", | |
2938 | + "tslib": "^2.6.2" | |
2939 | + }, | |
2940 | + "engines": { | |
2941 | + "node": ">=20.0.0" | |
2942 | + } | |
2943 | + }, | |
2944 | + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@aws-sdk/core": { | |
2945 | + "version": "3.972.0", | |
2946 | + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.972.0.tgz", | |
2947 | + "integrity": "sha512-nEeUW2M9F+xdIaD98F5MBcQ4ITtykj3yKbgFZ6J0JtL3bq+Z90szQ6Yy8H/BLPYXTs3V4n9ifnBo8cprRDiE6A==", | |
2948 | + "license": "Apache-2.0", | |
2949 | + "dependencies": { | |
2950 | + "@aws-sdk/types": "3.972.0", | |
2951 | + "@aws-sdk/xml-builder": "3.972.0", | |
2952 | + "@smithy/core": "^3.20.6", | |
2953 | + "@smithy/node-config-provider": "^4.3.8", | |
2954 | + "@smithy/property-provider": "^4.2.8", | |
2955 | + "@smithy/protocol-http": "^5.3.8", | |
2956 | + "@smithy/signature-v4": "^5.3.8", | |
2957 | + "@smithy/smithy-client": "^4.10.8", | |
2958 | + "@smithy/types": "^4.12.0", | |
2959 | + "@smithy/util-base64": "^4.3.0", | |
2960 | + "@smithy/util-middleware": "^4.2.8", | |
2961 | + "@smithy/util-utf8": "^4.2.0", | |
2962 | + "tslib": "^2.6.2" | |
2963 | + }, | |
2964 | + "engines": { | |
2965 | + "node": ">=20.0.0" | |
2966 | + } | |
2967 | + }, | |
2968 | + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@aws-sdk/types": { | |
2969 | + "version": "3.972.0", | |
2970 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
2971 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
2972 | + "license": "Apache-2.0", | |
2973 | + "dependencies": { | |
2974 | + "@smithy/types": "^4.12.0", | |
2975 | + "tslib": "^2.6.2" | |
2976 | + }, | |
2977 | + "engines": { | |
2978 | + "node": ">=20.0.0" | |
2979 | + } | |
2980 | + }, | |
2981 | + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@aws-sdk/xml-builder": { | |
2982 | + "version": "3.972.0", | |
2983 | + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.0.tgz", | |
2984 | + "integrity": "sha512-POaGMcXnozzqBUyJM3HLUZ9GR6OKJWPGJEmhtTnxZXt8B6JcJ/6K3xRJ5H/j8oovVLz8Wg6vFxAHv8lvuASxMg==", | |
2985 | + "license": "Apache-2.0", | |
2986 | + "dependencies": { | |
2987 | + "@smithy/types": "^4.12.0", | |
2988 | + "fast-xml-parser": "5.2.5", | |
2989 | + "tslib": "^2.6.2" | |
2990 | + }, | |
2991 | + "engines": { | |
2992 | + "node": ">=20.0.0" | |
2993 | + } | |
2994 | + }, | |
2995 | + "node_modules/@aws-sdk/middleware-host-header": { | |
2996 | + "version": "3.972.0", | |
2997 | + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.0.tgz", | |
2998 | + "integrity": "sha512-3eztFI6F9/eHtkIaWKN3nT+PM+eQ6p1MALDuNshFk323ixuCZzOOVT8oUqtZa30Z6dycNXJwhlIq7NhUVFfimw==", | |
2999 | + "license": "Apache-2.0", | |
3000 | + "dependencies": { | |
3001 | + "@aws-sdk/types": "3.972.0", | |
3002 | + "@smithy/protocol-http": "^5.3.8", | |
3003 | + "@smithy/types": "^4.12.0", | |
3004 | + "tslib": "^2.6.2" | |
3005 | + }, | |
3006 | + "engines": { | |
3007 | + "node": ">=20.0.0" | |
3008 | + } | |
3009 | + }, | |
3010 | + "node_modules/@aws-sdk/middleware-host-header/node_modules/@aws-sdk/types": { | |
3011 | + "version": "3.972.0", | |
3012 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
3013 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
3014 | + "license": "Apache-2.0", | |
3015 | + "dependencies": { | |
3016 | + "@smithy/types": "^4.12.0", | |
3017 | + "tslib": "^2.6.2" | |
3018 | + }, | |
3019 | + "engines": { | |
3020 | + "node": ">=20.0.0" | |
3021 | + } | |
3022 | + }, | |
3023 | + "node_modules/@aws-sdk/middleware-location-constraint": { | |
3024 | + "version": "3.972.0", | |
3025 | + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.972.0.tgz", | |
3026 | + "integrity": "sha512-WpsxoVPzbGPQGb/jupNYjpE0REcCPtjz7Q7zAt+dyo7fxsLBn4J+Rp6AYzSa04J9VrmrvCqCbVLu6B88PlSKSQ==", | |
3027 | + "license": "Apache-2.0", | |
3028 | + "dependencies": { | |
3029 | + "@aws-sdk/types": "3.972.0", | |
3030 | + "@smithy/types": "^4.12.0", | |
3031 | + "tslib": "^2.6.2" | |
3032 | + }, | |
3033 | + "engines": { | |
3034 | + "node": ">=20.0.0" | |
3035 | + } | |
3036 | + }, | |
3037 | + "node_modules/@aws-sdk/middleware-location-constraint/node_modules/@aws-sdk/types": { | |
3038 | + "version": "3.972.0", | |
3039 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
3040 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
3041 | + "license": "Apache-2.0", | |
3042 | + "dependencies": { | |
3043 | + "@smithy/types": "^4.12.0", | |
3044 | + "tslib": "^2.6.2" | |
3045 | + }, | |
3046 | + "engines": { | |
3047 | + "node": ">=20.0.0" | |
3048 | + } | |
3049 | + }, | |
3050 | + "node_modules/@aws-sdk/middleware-logger": { | |
3051 | + "version": "3.972.0", | |
3052 | + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.972.0.tgz", | |
3053 | + "integrity": "sha512-ZvdyVRwzK+ra31v1pQrgbqR/KsLD+wwJjHgko6JfoKUBIcEfAwJzQKO6HspHxdHWTVUz6MgvwskheR/TTYZl2g==", | |
3054 | + "license": "Apache-2.0", | |
3055 | + "dependencies": { | |
3056 | + "@aws-sdk/types": "3.972.0", | |
3057 | + "@smithy/types": "^4.12.0", | |
3058 | + "tslib": "^2.6.2" | |
3059 | + }, | |
3060 | + "engines": { | |
3061 | + "node": ">=20.0.0" | |
3062 | + } | |
3063 | + }, | |
3064 | + "node_modules/@aws-sdk/middleware-logger/node_modules/@aws-sdk/types": { | |
3065 | + "version": "3.972.0", | |
3066 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
3067 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
3068 | + "license": "Apache-2.0", | |
3069 | + "dependencies": { | |
3070 | + "@smithy/types": "^4.12.0", | |
3071 | + "tslib": "^2.6.2" | |
3072 | + }, | |
3073 | + "engines": { | |
3074 | + "node": ">=20.0.0" | |
3075 | + } | |
3076 | + }, | |
3077 | + "node_modules/@aws-sdk/middleware-recursion-detection": { | |
3078 | + "version": "3.972.0", | |
3079 | + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.0.tgz", | |
3080 | + "integrity": "sha512-F2SmUeO+S6l1h6dydNet3BQIk173uAkcfU1HDkw/bUdRLAnh15D3HP9vCZ7oCPBNcdEICbXYDmx0BR9rRUHGlQ==", | |
3081 | + "license": "Apache-2.0", | |
3082 | + "dependencies": { | |
3083 | + "@aws-sdk/types": "3.972.0", | |
3084 | + "@aws/lambda-invoke-store": "^0.2.2", | |
3085 | + "@smithy/protocol-http": "^5.3.8", | |
3086 | + "@smithy/types": "^4.12.0", | |
3087 | + "tslib": "^2.6.2" | |
3088 | + }, | |
3089 | + "engines": { | |
3090 | + "node": ">=20.0.0" | |
3091 | + } | |
3092 | + }, | |
3093 | + "node_modules/@aws-sdk/middleware-recursion-detection/node_modules/@aws-sdk/types": { | |
3094 | + "version": "3.972.0", | |
3095 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
3096 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
3097 | + "license": "Apache-2.0", | |
3098 | + "dependencies": { | |
3099 | + "@smithy/types": "^4.12.0", | |
3100 | + "tslib": "^2.6.2" | |
3101 | + }, | |
3102 | + "engines": { | |
3103 | + "node": ">=20.0.0" | |
3104 | + } | |
3105 | + }, | |
3106 | + "node_modules/@aws-sdk/middleware-sdk-s3": { | |
3107 | + "version": "3.947.0", | |
3108 | + "license": "Apache-2.0", | |
3109 | + "dependencies": { | |
3110 | + "@aws-sdk/core": "3.947.0", | |
2360 | 3111 | "@aws-sdk/types": "3.936.0", |
2361 | 3112 | "@aws-sdk/util-arn-parser": "3.893.0", |
2362 | 3113 | "@smithy/core": "^3.18.7", |
| @@ -2372,96 +3123,232 @@ | ||
2372 | 3123 | "tslib": "^2.6.2" |
2373 | 3124 | }, |
2374 | 3125 | "engines": { |
2375 | - "node": ">=18.0.0" | |
3126 | + "node": ">=18.0.0" | |
3127 | + } | |
3128 | + }, | |
3129 | + "node_modules/@aws-sdk/middleware-ssec": { | |
3130 | + "version": "3.972.0", | |
3131 | + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.972.0.tgz", | |
3132 | + "integrity": "sha512-cEr2HtK4R2fi8Y0P95cjbr4KJOjKBt8ms95mEJhabJN8KM4CpD4iS/J1lhvMj+qWir0KBTV6gKmxECXdfL9S6w==", | |
3133 | + "license": "Apache-2.0", | |
3134 | + "dependencies": { | |
3135 | + "@aws-sdk/types": "3.972.0", | |
3136 | + "@smithy/types": "^4.12.0", | |
3137 | + "tslib": "^2.6.2" | |
3138 | + }, | |
3139 | + "engines": { | |
3140 | + "node": ">=20.0.0" | |
3141 | + } | |
3142 | + }, | |
3143 | + "node_modules/@aws-sdk/middleware-ssec/node_modules/@aws-sdk/types": { | |
3144 | + "version": "3.972.0", | |
3145 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
3146 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
3147 | + "license": "Apache-2.0", | |
3148 | + "dependencies": { | |
3149 | + "@smithy/types": "^4.12.0", | |
3150 | + "tslib": "^2.6.2" | |
3151 | + }, | |
3152 | + "engines": { | |
3153 | + "node": ">=20.0.0" | |
3154 | + } | |
3155 | + }, | |
3156 | + "node_modules/@aws-sdk/middleware-user-agent": { | |
3157 | + "version": "3.972.0", | |
3158 | + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.0.tgz", | |
3159 | + "integrity": "sha512-kFHQm2OCBJCzGWRafgdWHGFjitUXY/OxXngymcX4l8CiyiNDZB27HDDBg2yLj3OUJc4z4fexLMmP8r9vgag19g==", | |
3160 | + "license": "Apache-2.0", | |
3161 | + "dependencies": { | |
3162 | + "@aws-sdk/core": "3.972.0", | |
3163 | + "@aws-sdk/types": "3.972.0", | |
3164 | + "@aws-sdk/util-endpoints": "3.972.0", | |
3165 | + "@smithy/core": "^3.20.6", | |
3166 | + "@smithy/protocol-http": "^5.3.8", | |
3167 | + "@smithy/types": "^4.12.0", | |
3168 | + "tslib": "^2.6.2" | |
3169 | + }, | |
3170 | + "engines": { | |
3171 | + "node": ">=20.0.0" | |
3172 | + } | |
3173 | + }, | |
3174 | + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@aws-sdk/core": { | |
3175 | + "version": "3.972.0", | |
3176 | + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.972.0.tgz", | |
3177 | + "integrity": "sha512-nEeUW2M9F+xdIaD98F5MBcQ4ITtykj3yKbgFZ6J0JtL3bq+Z90szQ6Yy8H/BLPYXTs3V4n9ifnBo8cprRDiE6A==", | |
3178 | + "license": "Apache-2.0", | |
3179 | + "dependencies": { | |
3180 | + "@aws-sdk/types": "3.972.0", | |
3181 | + "@aws-sdk/xml-builder": "3.972.0", | |
3182 | + "@smithy/core": "^3.20.6", | |
3183 | + "@smithy/node-config-provider": "^4.3.8", | |
3184 | + "@smithy/property-provider": "^4.2.8", | |
3185 | + "@smithy/protocol-http": "^5.3.8", | |
3186 | + "@smithy/signature-v4": "^5.3.8", | |
3187 | + "@smithy/smithy-client": "^4.10.8", | |
3188 | + "@smithy/types": "^4.12.0", | |
3189 | + "@smithy/util-base64": "^4.3.0", | |
3190 | + "@smithy/util-middleware": "^4.2.8", | |
3191 | + "@smithy/util-utf8": "^4.2.0", | |
3192 | + "tslib": "^2.6.2" | |
3193 | + }, | |
3194 | + "engines": { | |
3195 | + "node": ">=20.0.0" | |
3196 | + } | |
3197 | + }, | |
3198 | + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@aws-sdk/types": { | |
3199 | + "version": "3.972.0", | |
3200 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
3201 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
3202 | + "license": "Apache-2.0", | |
3203 | + "dependencies": { | |
3204 | + "@smithy/types": "^4.12.0", | |
3205 | + "tslib": "^2.6.2" | |
3206 | + }, | |
3207 | + "engines": { | |
3208 | + "node": ">=20.0.0" | |
3209 | + } | |
3210 | + }, | |
3211 | + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@aws-sdk/xml-builder": { | |
3212 | + "version": "3.972.0", | |
3213 | + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.0.tgz", | |
3214 | + "integrity": "sha512-POaGMcXnozzqBUyJM3HLUZ9GR6OKJWPGJEmhtTnxZXt8B6JcJ/6K3xRJ5H/j8oovVLz8Wg6vFxAHv8lvuASxMg==", | |
3215 | + "license": "Apache-2.0", | |
3216 | + "dependencies": { | |
3217 | + "@smithy/types": "^4.12.0", | |
3218 | + "fast-xml-parser": "5.2.5", | |
3219 | + "tslib": "^2.6.2" | |
3220 | + }, | |
3221 | + "engines": { | |
3222 | + "node": ">=20.0.0" | |
3223 | + } | |
3224 | + }, | |
3225 | + "node_modules/@aws-sdk/nested-clients": { | |
3226 | + "version": "3.972.0", | |
3227 | + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.972.0.tgz", | |
3228 | + "integrity": "sha512-QGlbnuGzSQJVG6bR9Qw6G0Blh6abFR4VxNa61ttMbzy9jt28xmk2iGtrYLrQPlCCPhY6enHqjTWm3n3LOb0wAw==", | |
3229 | + "license": "Apache-2.0", | |
3230 | + "dependencies": { | |
3231 | + "@aws-crypto/sha256-browser": "5.2.0", | |
3232 | + "@aws-crypto/sha256-js": "5.2.0", | |
3233 | + "@aws-sdk/core": "3.972.0", | |
3234 | + "@aws-sdk/middleware-host-header": "3.972.0", | |
3235 | + "@aws-sdk/middleware-logger": "3.972.0", | |
3236 | + "@aws-sdk/middleware-recursion-detection": "3.972.0", | |
3237 | + "@aws-sdk/middleware-user-agent": "3.972.0", | |
3238 | + "@aws-sdk/region-config-resolver": "3.972.0", | |
3239 | + "@aws-sdk/types": "3.972.0", | |
3240 | + "@aws-sdk/util-endpoints": "3.972.0", | |
3241 | + "@aws-sdk/util-user-agent-browser": "3.972.0", | |
3242 | + "@aws-sdk/util-user-agent-node": "3.972.0", | |
3243 | + "@smithy/config-resolver": "^4.4.6", | |
3244 | + "@smithy/core": "^3.20.6", | |
3245 | + "@smithy/fetch-http-handler": "^5.3.9", | |
3246 | + "@smithy/hash-node": "^4.2.8", | |
3247 | + "@smithy/invalid-dependency": "^4.2.8", | |
3248 | + "@smithy/middleware-content-length": "^4.2.8", | |
3249 | + "@smithy/middleware-endpoint": "^4.4.7", | |
3250 | + "@smithy/middleware-retry": "^4.4.23", | |
3251 | + "@smithy/middleware-serde": "^4.2.9", | |
3252 | + "@smithy/middleware-stack": "^4.2.8", | |
3253 | + "@smithy/node-config-provider": "^4.3.8", | |
3254 | + "@smithy/node-http-handler": "^4.4.8", | |
3255 | + "@smithy/protocol-http": "^5.3.8", | |
3256 | + "@smithy/smithy-client": "^4.10.8", | |
3257 | + "@smithy/types": "^4.12.0", | |
3258 | + "@smithy/url-parser": "^4.2.8", | |
3259 | + "@smithy/util-base64": "^4.3.0", | |
3260 | + "@smithy/util-body-length-browser": "^4.2.0", | |
3261 | + "@smithy/util-body-length-node": "^4.2.1", | |
3262 | + "@smithy/util-defaults-mode-browser": "^4.3.22", | |
3263 | + "@smithy/util-defaults-mode-node": "^4.2.25", | |
3264 | + "@smithy/util-endpoints": "^3.2.8", | |
3265 | + "@smithy/util-middleware": "^4.2.8", | |
3266 | + "@smithy/util-retry": "^4.2.8", | |
3267 | + "@smithy/util-utf8": "^4.2.0", | |
3268 | + "tslib": "^2.6.2" | |
3269 | + }, | |
3270 | + "engines": { | |
3271 | + "node": ">=20.0.0" | |
2376 | 3272 | } |
2377 | 3273 | }, |
2378 | - "node_modules/@aws-sdk/middleware-ssec": { | |
2379 | - "version": "3.936.0", | |
3274 | + "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/core": { | |
3275 | + "version": "3.972.0", | |
3276 | + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.972.0.tgz", | |
3277 | + "integrity": "sha512-nEeUW2M9F+xdIaD98F5MBcQ4ITtykj3yKbgFZ6J0JtL3bq+Z90szQ6Yy8H/BLPYXTs3V4n9ifnBo8cprRDiE6A==", | |
2380 | 3278 | "license": "Apache-2.0", |
2381 | 3279 | "dependencies": { |
2382 | - "@aws-sdk/types": "3.936.0", | |
2383 | - "@smithy/types": "^4.9.0", | |
3280 | + "@aws-sdk/types": "3.972.0", | |
3281 | + "@aws-sdk/xml-builder": "3.972.0", | |
3282 | + "@smithy/core": "^3.20.6", | |
3283 | + "@smithy/node-config-provider": "^4.3.8", | |
3284 | + "@smithy/property-provider": "^4.2.8", | |
3285 | + "@smithy/protocol-http": "^5.3.8", | |
3286 | + "@smithy/signature-v4": "^5.3.8", | |
3287 | + "@smithy/smithy-client": "^4.10.8", | |
3288 | + "@smithy/types": "^4.12.0", | |
3289 | + "@smithy/util-base64": "^4.3.0", | |
3290 | + "@smithy/util-middleware": "^4.2.8", | |
3291 | + "@smithy/util-utf8": "^4.2.0", | |
2384 | 3292 | "tslib": "^2.6.2" |
2385 | 3293 | }, |
2386 | 3294 | "engines": { |
2387 | - "node": ">=18.0.0" | |
3295 | + "node": ">=20.0.0" | |
2388 | 3296 | } |
2389 | 3297 | }, |
2390 | - "node_modules/@aws-sdk/middleware-user-agent": { | |
2391 | - "version": "3.947.0", | |
3298 | + "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/types": { | |
3299 | + "version": "3.972.0", | |
3300 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
3301 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
2392 | 3302 | "license": "Apache-2.0", |
2393 | 3303 | "dependencies": { |
2394 | - "@aws-sdk/core": "3.947.0", | |
2395 | - "@aws-sdk/types": "3.936.0", | |
2396 | - "@aws-sdk/util-endpoints": "3.936.0", | |
2397 | - "@smithy/core": "^3.18.7", | |
2398 | - "@smithy/protocol-http": "^5.3.5", | |
2399 | - "@smithy/types": "^4.9.0", | |
3304 | + "@smithy/types": "^4.12.0", | |
2400 | 3305 | "tslib": "^2.6.2" |
2401 | 3306 | }, |
2402 | 3307 | "engines": { |
2403 | - "node": ">=18.0.0" | |
3308 | + "node": ">=20.0.0" | |
2404 | 3309 | } |
2405 | 3310 | }, |
2406 | - "node_modules/@aws-sdk/nested-clients": { | |
2407 | - "version": "3.948.0", | |
3311 | + "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/xml-builder": { | |
3312 | + "version": "3.972.0", | |
3313 | + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.0.tgz", | |
3314 | + "integrity": "sha512-POaGMcXnozzqBUyJM3HLUZ9GR6OKJWPGJEmhtTnxZXt8B6JcJ/6K3xRJ5H/j8oovVLz8Wg6vFxAHv8lvuASxMg==", | |
2408 | 3315 | "license": "Apache-2.0", |
2409 | 3316 | "dependencies": { |
2410 | - "@aws-crypto/sha256-browser": "5.2.0", | |
2411 | - "@aws-crypto/sha256-js": "5.2.0", | |
2412 | - "@aws-sdk/core": "3.947.0", | |
2413 | - "@aws-sdk/middleware-host-header": "3.936.0", | |
2414 | - "@aws-sdk/middleware-logger": "3.936.0", | |
2415 | - "@aws-sdk/middleware-recursion-detection": "3.948.0", | |
2416 | - "@aws-sdk/middleware-user-agent": "3.947.0", | |
2417 | - "@aws-sdk/region-config-resolver": "3.936.0", | |
2418 | - "@aws-sdk/types": "3.936.0", | |
2419 | - "@aws-sdk/util-endpoints": "3.936.0", | |
2420 | - "@aws-sdk/util-user-agent-browser": "3.936.0", | |
2421 | - "@aws-sdk/util-user-agent-node": "3.947.0", | |
2422 | - "@smithy/config-resolver": "^4.4.3", | |
2423 | - "@smithy/core": "^3.18.7", | |
2424 | - "@smithy/fetch-http-handler": "^5.3.6", | |
2425 | - "@smithy/hash-node": "^4.2.5", | |
2426 | - "@smithy/invalid-dependency": "^4.2.5", | |
2427 | - "@smithy/middleware-content-length": "^4.2.5", | |
2428 | - "@smithy/middleware-endpoint": "^4.3.14", | |
2429 | - "@smithy/middleware-retry": "^4.4.14", | |
2430 | - "@smithy/middleware-serde": "^4.2.6", | |
2431 | - "@smithy/middleware-stack": "^4.2.5", | |
2432 | - "@smithy/node-config-provider": "^4.3.5", | |
2433 | - "@smithy/node-http-handler": "^4.4.5", | |
2434 | - "@smithy/protocol-http": "^5.3.5", | |
2435 | - "@smithy/smithy-client": "^4.9.10", | |
2436 | - "@smithy/types": "^4.9.0", | |
2437 | - "@smithy/url-parser": "^4.2.5", | |
2438 | - "@smithy/util-base64": "^4.3.0", | |
2439 | - "@smithy/util-body-length-browser": "^4.2.0", | |
2440 | - "@smithy/util-body-length-node": "^4.2.1", | |
2441 | - "@smithy/util-defaults-mode-browser": "^4.3.13", | |
2442 | - "@smithy/util-defaults-mode-node": "^4.2.16", | |
2443 | - "@smithy/util-endpoints": "^3.2.5", | |
2444 | - "@smithy/util-middleware": "^4.2.5", | |
2445 | - "@smithy/util-retry": "^4.2.5", | |
2446 | - "@smithy/util-utf8": "^4.2.0", | |
3317 | + "@smithy/types": "^4.12.0", | |
3318 | + "fast-xml-parser": "5.2.5", | |
2447 | 3319 | "tslib": "^2.6.2" |
2448 | 3320 | }, |
2449 | 3321 | "engines": { |
2450 | - "node": ">=18.0.0" | |
3322 | + "node": ">=20.0.0" | |
2451 | 3323 | } |
2452 | 3324 | }, |
2453 | 3325 | "node_modules/@aws-sdk/region-config-resolver": { |
2454 | - "version": "3.936.0", | |
3326 | + "version": "3.972.0", | |
3327 | + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.0.tgz", | |
3328 | + "integrity": "sha512-JyOf+R/6vJW8OEVFCAyzEOn2reri/Q+L0z9zx4JQSKWvTmJ1qeFO25sOm8VIfB8URKhfGRTQF30pfYaH2zxt/A==", | |
2455 | 3329 | "license": "Apache-2.0", |
2456 | 3330 | "dependencies": { |
2457 | - "@aws-sdk/types": "3.936.0", | |
2458 | - "@smithy/config-resolver": "^4.4.3", | |
2459 | - "@smithy/node-config-provider": "^4.3.5", | |
2460 | - "@smithy/types": "^4.9.0", | |
3331 | + "@aws-sdk/types": "3.972.0", | |
3332 | + "@smithy/config-resolver": "^4.4.6", | |
3333 | + "@smithy/node-config-provider": "^4.3.8", | |
3334 | + "@smithy/types": "^4.12.0", | |
2461 | 3335 | "tslib": "^2.6.2" |
2462 | 3336 | }, |
2463 | 3337 | "engines": { |
2464 | - "node": ">=18.0.0" | |
3338 | + "node": ">=20.0.0" | |
3339 | + } | |
3340 | + }, | |
3341 | + "node_modules/@aws-sdk/region-config-resolver/node_modules/@aws-sdk/types": { | |
3342 | + "version": "3.972.0", | |
3343 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
3344 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
3345 | + "license": "Apache-2.0", | |
3346 | + "dependencies": { | |
3347 | + "@smithy/types": "^4.12.0", | |
3348 | + "tslib": "^2.6.2" | |
3349 | + }, | |
3350 | + "engines": { | |
3351 | + "node": ">=20.0.0" | |
2465 | 3352 | } |
2466 | 3353 | }, |
2467 | 3354 | "node_modules/@aws-sdk/s3-request-presigner": { |
| @@ -2497,19 +3384,72 @@ | ||
2497 | 3384 | } |
2498 | 3385 | }, |
2499 | 3386 | "node_modules/@aws-sdk/token-providers": { |
2500 | - "version": "3.948.0", | |
3387 | + "version": "3.972.0", | |
3388 | + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.972.0.tgz", | |
3389 | + "integrity": "sha512-kWlXG+y5nZhgXGEtb72Je+EvqepBPs8E3vZse//1PYLWs2speFqbGE/ywCXmzEJgHgVqSB/u/lqBvs5WlYmSqQ==", | |
2501 | 3390 | "license": "Apache-2.0", |
2502 | 3391 | "dependencies": { |
2503 | - "@aws-sdk/core": "3.947.0", | |
2504 | - "@aws-sdk/nested-clients": "3.948.0", | |
2505 | - "@aws-sdk/types": "3.936.0", | |
2506 | - "@smithy/property-provider": "^4.2.5", | |
2507 | - "@smithy/shared-ini-file-loader": "^4.4.0", | |
2508 | - "@smithy/types": "^4.9.0", | |
3392 | + "@aws-sdk/core": "3.972.0", | |
3393 | + "@aws-sdk/nested-clients": "3.972.0", | |
3394 | + "@aws-sdk/types": "3.972.0", | |
3395 | + "@smithy/property-provider": "^4.2.8", | |
3396 | + "@smithy/shared-ini-file-loader": "^4.4.3", | |
3397 | + "@smithy/types": "^4.12.0", | |
2509 | 3398 | "tslib": "^2.6.2" |
2510 | 3399 | }, |
2511 | 3400 | "engines": { |
2512 | - "node": ">=18.0.0" | |
3401 | + "node": ">=20.0.0" | |
3402 | + } | |
3403 | + }, | |
3404 | + "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/core": { | |
3405 | + "version": "3.972.0", | |
3406 | + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.972.0.tgz", | |
3407 | + "integrity": "sha512-nEeUW2M9F+xdIaD98F5MBcQ4ITtykj3yKbgFZ6J0JtL3bq+Z90szQ6Yy8H/BLPYXTs3V4n9ifnBo8cprRDiE6A==", | |
3408 | + "license": "Apache-2.0", | |
3409 | + "dependencies": { | |
3410 | + "@aws-sdk/types": "3.972.0", | |
3411 | + "@aws-sdk/xml-builder": "3.972.0", | |
3412 | + "@smithy/core": "^3.20.6", | |
3413 | + "@smithy/node-config-provider": "^4.3.8", | |
3414 | + "@smithy/property-provider": "^4.2.8", | |
3415 | + "@smithy/protocol-http": "^5.3.8", | |
3416 | + "@smithy/signature-v4": "^5.3.8", | |
3417 | + "@smithy/smithy-client": "^4.10.8", | |
3418 | + "@smithy/types": "^4.12.0", | |
3419 | + "@smithy/util-base64": "^4.3.0", | |
3420 | + "@smithy/util-middleware": "^4.2.8", | |
3421 | + "@smithy/util-utf8": "^4.2.0", | |
3422 | + "tslib": "^2.6.2" | |
3423 | + }, | |
3424 | + "engines": { | |
3425 | + "node": ">=20.0.0" | |
3426 | + } | |
3427 | + }, | |
3428 | + "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/types": { | |
3429 | + "version": "3.972.0", | |
3430 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
3431 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
3432 | + "license": "Apache-2.0", | |
3433 | + "dependencies": { | |
3434 | + "@smithy/types": "^4.12.0", | |
3435 | + "tslib": "^2.6.2" | |
3436 | + }, | |
3437 | + "engines": { | |
3438 | + "node": ">=20.0.0" | |
3439 | + } | |
3440 | + }, | |
3441 | + "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/xml-builder": { | |
3442 | + "version": "3.972.0", | |
3443 | + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.0.tgz", | |
3444 | + "integrity": "sha512-POaGMcXnozzqBUyJM3HLUZ9GR6OKJWPGJEmhtTnxZXt8B6JcJ/6K3xRJ5H/j8oovVLz8Wg6vFxAHv8lvuASxMg==", | |
3445 | + "license": "Apache-2.0", | |
3446 | + "dependencies": { | |
3447 | + "@smithy/types": "^4.12.0", | |
3448 | + "fast-xml-parser": "5.2.5", | |
3449 | + "tslib": "^2.6.2" | |
3450 | + }, | |
3451 | + "engines": { | |
3452 | + "node": ">=20.0.0" | |
2513 | 3453 | } |
2514 | 3454 | }, |
2515 | 3455 | "node_modules/@aws-sdk/types": { |
| @@ -2534,17 +3474,32 @@ | ||
2534 | 3474 | } |
2535 | 3475 | }, |
2536 | 3476 | "node_modules/@aws-sdk/util-endpoints": { |
2537 | - "version": "3.936.0", | |
3477 | + "version": "3.972.0", | |
3478 | + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.972.0.tgz", | |
3479 | + "integrity": "sha512-6JHsl1V/a1ZW8D8AFfd4R52fwZPnZ5H4U6DS8m/bWT8qad72NvbOFAC7U2cDtFs2TShqUO3TEiX/EJibtY3ijg==", | |
2538 | 3480 | "license": "Apache-2.0", |
2539 | 3481 | "dependencies": { |
2540 | - "@aws-sdk/types": "3.936.0", | |
2541 | - "@smithy/types": "^4.9.0", | |
2542 | - "@smithy/url-parser": "^4.2.5", | |
2543 | - "@smithy/util-endpoints": "^3.2.5", | |
3482 | + "@aws-sdk/types": "3.972.0", | |
3483 | + "@smithy/types": "^4.12.0", | |
3484 | + "@smithy/url-parser": "^4.2.8", | |
3485 | + "@smithy/util-endpoints": "^3.2.8", | |
2544 | 3486 | "tslib": "^2.6.2" |
2545 | 3487 | }, |
2546 | 3488 | "engines": { |
2547 | - "node": ">=18.0.0" | |
3489 | + "node": ">=20.0.0" | |
3490 | + } | |
3491 | + }, | |
3492 | + "node_modules/@aws-sdk/util-endpoints/node_modules/@aws-sdk/types": { | |
3493 | + "version": "3.972.0", | |
3494 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
3495 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
3496 | + "license": "Apache-2.0", | |
3497 | + "dependencies": { | |
3498 | + "@smithy/types": "^4.12.0", | |
3499 | + "tslib": "^2.6.2" | |
3500 | + }, | |
3501 | + "engines": { | |
3502 | + "node": ">=20.0.0" | |
2548 | 3503 | } |
2549 | 3504 | }, |
2550 | 3505 | "node_modules/@aws-sdk/util-format-url": { |
| @@ -2571,27 +3526,44 @@ | ||
2571 | 3526 | } |
2572 | 3527 | }, |
2573 | 3528 | "node_modules/@aws-sdk/util-user-agent-browser": { |
2574 | - "version": "3.936.0", | |
3529 | + "version": "3.972.0", | |
3530 | + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.0.tgz", | |
3531 | + "integrity": "sha512-eOLdkQyoRbDgioTS3Orr7iVsVEutJyMZxvyZ6WAF95IrF0kfWx5Rd/KXnfbnG/VKa2CvjZiitWfouLzfVEyvJA==", | |
2575 | 3532 | "license": "Apache-2.0", |
2576 | 3533 | "dependencies": { |
2577 | - "@aws-sdk/types": "3.936.0", | |
2578 | - "@smithy/types": "^4.9.0", | |
3534 | + "@aws-sdk/types": "3.972.0", | |
3535 | + "@smithy/types": "^4.12.0", | |
2579 | 3536 | "bowser": "^2.11.0", |
2580 | 3537 | "tslib": "^2.6.2" |
2581 | 3538 | } |
2582 | 3539 | }, |
3540 | + "node_modules/@aws-sdk/util-user-agent-browser/node_modules/@aws-sdk/types": { | |
3541 | + "version": "3.972.0", | |
3542 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
3543 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
3544 | + "license": "Apache-2.0", | |
3545 | + "dependencies": { | |
3546 | + "@smithy/types": "^4.12.0", | |
3547 | + "tslib": "^2.6.2" | |
3548 | + }, | |
3549 | + "engines": { | |
3550 | + "node": ">=20.0.0" | |
3551 | + } | |
3552 | + }, | |
2583 | 3553 | "node_modules/@aws-sdk/util-user-agent-node": { |
2584 | - "version": "3.947.0", | |
3554 | + "version": "3.972.0", | |
3555 | + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.972.0.tgz", | |
3556 | + "integrity": "sha512-GOy+AiSrE9kGiojiwlZvVVSXwylu4+fmP0MJfvras/MwP09RB/YtQuOVR1E0fKQc6OMwaTNBjgAbOEhxuWFbAw==", | |
2585 | 3557 | "license": "Apache-2.0", |
2586 | 3558 | "dependencies": { |
2587 | - "@aws-sdk/middleware-user-agent": "3.947.0", | |
2588 | - "@aws-sdk/types": "3.936.0", | |
2589 | - "@smithy/node-config-provider": "^4.3.5", | |
2590 | - "@smithy/types": "^4.9.0", | |
3559 | + "@aws-sdk/middleware-user-agent": "3.972.0", | |
3560 | + "@aws-sdk/types": "3.972.0", | |
3561 | + "@smithy/node-config-provider": "^4.3.8", | |
3562 | + "@smithy/types": "^4.12.0", | |
2591 | 3563 | "tslib": "^2.6.2" |
2592 | 3564 | }, |
2593 | 3565 | "engines": { |
2594 | - "node": ">=18.0.0" | |
3566 | + "node": ">=20.0.0" | |
2595 | 3567 | }, |
2596 | 3568 | "peerDependencies": { |
2597 | 3569 | "aws-crt": ">=1.0.0" |
| @@ -2602,6 +3574,19 @@ | ||
2602 | 3574 | } |
2603 | 3575 | } |
2604 | 3576 | }, |
3577 | + "node_modules/@aws-sdk/util-user-agent-node/node_modules/@aws-sdk/types": { | |
3578 | + "version": "3.972.0", | |
3579 | + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", | |
3580 | + "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", | |
3581 | + "license": "Apache-2.0", | |
3582 | + "dependencies": { | |
3583 | + "@smithy/types": "^4.12.0", | |
3584 | + "tslib": "^2.6.2" | |
3585 | + }, | |
3586 | + "engines": { | |
3587 | + "node": ">=20.0.0" | |
3588 | + } | |
3589 | + }, | |
2605 | 3590 | "node_modules/@aws-sdk/xml-builder": { |
2606 | 3591 | "version": "3.930.0", |
2607 | 3592 | "license": "Apache-2.0", |
| @@ -7888,12 +8873,12 @@ | ||
7888 | 8873 | } |
7889 | 8874 | }, |
7890 | 8875 | "node_modules/@smithy/abort-controller": { |
7891 | - "version": "4.2.7", | |
7892 | - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.7.tgz", | |
7893 | - "integrity": "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw==", | |
8876 | + "version": "4.2.8", | |
8877 | + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.8.tgz", | |
8878 | + "integrity": "sha512-peuVfkYHAmS5ybKxWcfraK7WBBP0J+rkfUcbHJJKQ4ir3UAUNQI+Y4Vt/PqSzGqgloJ5O1dk7+WzNL8wcCSXbw==", | |
7894 | 8879 | "license": "Apache-2.0", |
7895 | 8880 | "dependencies": { |
7896 | - "@smithy/types": "^4.11.0", | |
8881 | + "@smithy/types": "^4.12.0", | |
7897 | 8882 | "tslib": "^2.6.2" |
7898 | 8883 | }, |
7899 | 8884 | "engines": { |
| @@ -7902,6 +8887,8 @@ | ||
7902 | 8887 | }, |
7903 | 8888 | "node_modules/@smithy/chunked-blob-reader": { |
7904 | 8889 | "version": "5.2.0", |
8890 | + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-5.2.0.tgz", | |
8891 | + "integrity": "sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA==", | |
7905 | 8892 | "license": "Apache-2.0", |
7906 | 8893 | "dependencies": { |
7907 | 8894 | "tslib": "^2.6.2" |
| @@ -7912,6 +8899,8 @@ | ||
7912 | 8899 | }, |
7913 | 8900 | "node_modules/@smithy/chunked-blob-reader-native": { |
7914 | 8901 | "version": "4.2.1", |
8902 | + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-4.2.1.tgz", | |
8903 | + "integrity": "sha512-lX9Ay+6LisTfpLid2zZtIhSEjHMZoAR5hHCR4H7tBz/Zkfr5ea8RcQ7Tk4mi0P76p4cN+Btz16Ffno7YHpKXnQ==", | |
7915 | 8904 | "license": "Apache-2.0", |
7916 | 8905 | "dependencies": { |
7917 | 8906 | "@smithy/util-base64": "^4.3.0", |
| @@ -7922,16 +8911,16 @@ | ||
7922 | 8911 | } |
7923 | 8912 | }, |
7924 | 8913 | "node_modules/@smithy/config-resolver": { |
7925 | - "version": "4.4.5", | |
7926 | - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.5.tgz", | |
7927 | - "integrity": "sha512-HAGoUAFYsUkoSckuKbCPayECeMim8pOu+yLy1zOxt1sifzEbrsRpYa+mKcMdiHKMeiqOibyPG0sFJnmaV/OGEg==", | |
8914 | + "version": "4.4.6", | |
8915 | + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.6.tgz", | |
8916 | + "integrity": "sha512-qJpzYC64kaj3S0fueiu3kXm8xPrR3PcXDPEgnaNMRn0EjNSZFoFjvbUp0YUDsRhN1CB90EnHJtbxWKevnH99UQ==", | |
7928 | 8917 | "license": "Apache-2.0", |
7929 | 8918 | "dependencies": { |
7930 | - "@smithy/node-config-provider": "^4.3.7", | |
7931 | - "@smithy/types": "^4.11.0", | |
8919 | + "@smithy/node-config-provider": "^4.3.8", | |
8920 | + "@smithy/types": "^4.12.0", | |
7932 | 8921 | "@smithy/util-config-provider": "^4.2.0", |
7933 | - "@smithy/util-endpoints": "^3.2.7", | |
7934 | - "@smithy/util-middleware": "^4.2.7", | |
8922 | + "@smithy/util-endpoints": "^3.2.8", | |
8923 | + "@smithy/util-middleware": "^4.2.8", | |
7935 | 8924 | "tslib": "^2.6.2" |
7936 | 8925 | }, |
7937 | 8926 | "engines": { |
| @@ -7939,18 +8928,18 @@ | ||
7939 | 8928 | } |
7940 | 8929 | }, |
7941 | 8930 | "node_modules/@smithy/core": { |
7942 | - "version": "3.20.0", | |
7943 | - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.20.0.tgz", | |
7944 | - "integrity": "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ==", | |
8931 | + "version": "3.21.0", | |
8932 | + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.21.0.tgz", | |
8933 | + "integrity": "sha512-bg2TfzgsERyETAxc/Ims/eJX8eAnIeTi4r4LHpMpfF/2NyO6RsWis0rjKcCPaGksljmOb23BZRiCeT/3NvwkXw==", | |
7945 | 8934 | "license": "Apache-2.0", |
7946 | 8935 | "dependencies": { |
7947 | - "@smithy/middleware-serde": "^4.2.8", | |
7948 | - "@smithy/protocol-http": "^5.3.7", | |
7949 | - "@smithy/types": "^4.11.0", | |
8936 | + "@smithy/middleware-serde": "^4.2.9", | |
8937 | + "@smithy/protocol-http": "^5.3.8", | |
8938 | + "@smithy/types": "^4.12.0", | |
7950 | 8939 | "@smithy/util-base64": "^4.3.0", |
7951 | 8940 | "@smithy/util-body-length-browser": "^4.2.0", |
7952 | - "@smithy/util-middleware": "^4.2.7", | |
7953 | - "@smithy/util-stream": "^4.5.8", | |
8941 | + "@smithy/util-middleware": "^4.2.8", | |
8942 | + "@smithy/util-stream": "^4.5.10", | |
7954 | 8943 | "@smithy/util-utf8": "^4.2.0", |
7955 | 8944 | "@smithy/uuid": "^1.1.0", |
7956 | 8945 | "tslib": "^2.6.2" |
| @@ -7960,15 +8949,15 @@ | ||
7960 | 8949 | } |
7961 | 8950 | }, |
7962 | 8951 | "node_modules/@smithy/credential-provider-imds": { |
7963 | - "version": "4.2.7", | |
7964 | - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.7.tgz", | |
7965 | - "integrity": "sha512-CmduWdCiILCRNbQWFR0OcZlUPVtyE49Sr8yYL0rZQ4D/wKxiNzBNS/YHemvnbkIWj623fplgkexUd/c9CAKdoA==", | |
8952 | + "version": "4.2.8", | |
8953 | + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.8.tgz", | |
8954 | + "integrity": "sha512-FNT0xHS1c/CPN8upqbMFP83+ul5YgdisfCfkZ86Jh2NSmnqw/AJ6x5pEogVCTVvSm7j9MopRU89bmDelxuDMYw==", | |
7966 | 8955 | "license": "Apache-2.0", |
7967 | 8956 | "dependencies": { |
7968 | - "@smithy/node-config-provider": "^4.3.7", | |
7969 | - "@smithy/property-provider": "^4.2.7", | |
7970 | - "@smithy/types": "^4.11.0", | |
7971 | - "@smithy/url-parser": "^4.2.7", | |
8957 | + "@smithy/node-config-provider": "^4.3.8", | |
8958 | + "@smithy/property-provider": "^4.2.8", | |
8959 | + "@smithy/types": "^4.12.0", | |
8960 | + "@smithy/url-parser": "^4.2.8", | |
7972 | 8961 | "tslib": "^2.6.2" |
7973 | 8962 | }, |
7974 | 8963 | "engines": { |
| @@ -7976,11 +8965,13 @@ | ||
7976 | 8965 | } |
7977 | 8966 | }, |
7978 | 8967 | "node_modules/@smithy/eventstream-codec": { |
7979 | - "version": "4.2.5", | |
8968 | + "version": "4.2.8", | |
8969 | + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.2.8.tgz", | |
8970 | + "integrity": "sha512-jS/O5Q14UsufqoGhov7dHLOPCzkYJl9QDzusI2Psh4wyYx/izhzvX9P4D69aTxcdfVhEPhjK+wYyn/PzLjKbbw==", | |
7980 | 8971 | "license": "Apache-2.0", |
7981 | 8972 | "dependencies": { |
7982 | 8973 | "@aws-crypto/crc32": "5.2.0", |
7983 | - "@smithy/types": "^4.9.0", | |
8974 | + "@smithy/types": "^4.12.0", | |
7984 | 8975 | "@smithy/util-hex-encoding": "^4.2.0", |
7985 | 8976 | "tslib": "^2.6.2" |
7986 | 8977 | }, |
| @@ -7989,11 +8980,13 @@ | ||
7989 | 8980 | } |
7990 | 8981 | }, |
7991 | 8982 | "node_modules/@smithy/eventstream-serde-browser": { |
7992 | - "version": "4.2.5", | |
8983 | + "version": "4.2.8", | |
8984 | + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.8.tgz", | |
8985 | + "integrity": "sha512-MTfQT/CRQz5g24ayXdjg53V0mhucZth4PESoA5IhvaWVDTOQLfo8qI9vzqHcPsdd2v6sqfTYqF5L/l+pea5Uyw==", | |
7993 | 8986 | "license": "Apache-2.0", |
7994 | 8987 | "dependencies": { |
7995 | - "@smithy/eventstream-serde-universal": "^4.2.5", | |
7996 | - "@smithy/types": "^4.9.0", | |
8988 | + "@smithy/eventstream-serde-universal": "^4.2.8", | |
8989 | + "@smithy/types": "^4.12.0", | |
7997 | 8990 | "tslib": "^2.6.2" |
7998 | 8991 | }, |
7999 | 8992 | "engines": { |
| @@ -8001,10 +8994,12 @@ | ||
8001 | 8994 | } |
8002 | 8995 | }, |
8003 | 8996 | "node_modules/@smithy/eventstream-serde-config-resolver": { |
8004 | - "version": "4.3.5", | |
8997 | + "version": "4.3.8", | |
8998 | + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.8.tgz", | |
8999 | + "integrity": "sha512-ah12+luBiDGzBruhu3efNy1IlbwSEdNiw8fOZksoKoWW1ZHvO/04MQsdnws/9Aj+5b0YXSSN2JXKy/ClIsW8MQ==", | |
8005 | 9000 | "license": "Apache-2.0", |
8006 | 9001 | "dependencies": { |
8007 | - "@smithy/types": "^4.9.0", | |
9002 | + "@smithy/types": "^4.12.0", | |
8008 | 9003 | "tslib": "^2.6.2" |
8009 | 9004 | }, |
8010 | 9005 | "engines": { |
| @@ -8012,11 +9007,13 @@ | ||
8012 | 9007 | } |
8013 | 9008 | }, |
8014 | 9009 | "node_modules/@smithy/eventstream-serde-node": { |
8015 | - "version": "4.2.5", | |
9010 | + "version": "4.2.8", | |
9011 | + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.8.tgz", | |
9012 | + "integrity": "sha512-cYpCpp29z6EJHa5T9WL0KAlq3SOKUQkcgSoeRfRVwjGgSFl7Uh32eYGt7IDYCX20skiEdRffyDpvF2efEZPC0A==", | |
8016 | 9013 | "license": "Apache-2.0", |
8017 | 9014 | "dependencies": { |
8018 | - "@smithy/eventstream-serde-universal": "^4.2.5", | |
8019 | - "@smithy/types": "^4.9.0", | |
9015 | + "@smithy/eventstream-serde-universal": "^4.2.8", | |
9016 | + "@smithy/types": "^4.12.0", | |
8020 | 9017 | "tslib": "^2.6.2" |
8021 | 9018 | }, |
8022 | 9019 | "engines": { |
| @@ -8024,11 +9021,13 @@ | ||
8024 | 9021 | } |
8025 | 9022 | }, |
8026 | 9023 | "node_modules/@smithy/eventstream-serde-universal": { |
8027 | - "version": "4.2.5", | |
9024 | + "version": "4.2.8", | |
9025 | + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.2.8.tgz", | |
9026 | + "integrity": "sha512-iJ6YNJd0bntJYnX6s52NC4WFYcZeKrPUr1Kmmr5AwZcwCSzVpS7oavAmxMR7pMq7V+D1G4s9F5NJK0xwOsKAlQ==", | |
8028 | 9027 | "license": "Apache-2.0", |
8029 | 9028 | "dependencies": { |
8030 | - "@smithy/eventstream-codec": "^4.2.5", | |
8031 | - "@smithy/types": "^4.9.0", | |
9029 | + "@smithy/eventstream-codec": "^4.2.8", | |
9030 | + "@smithy/types": "^4.12.0", | |
8032 | 9031 | "tslib": "^2.6.2" |
8033 | 9032 | }, |
8034 | 9033 | "engines": { |
| @@ -8036,14 +9035,14 @@ | ||
8036 | 9035 | } |
8037 | 9036 | }, |
8038 | 9037 | "node_modules/@smithy/fetch-http-handler": { |
8039 | - "version": "5.3.8", | |
8040 | - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.8.tgz", | |
8041 | - "integrity": "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg==", | |
9038 | + "version": "5.3.9", | |
9039 | + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.9.tgz", | |
9040 | + "integrity": "sha512-I4UhmcTYXBrct03rwzQX1Y/iqQlzVQaPxWjCjula++5EmWq9YGBrx6bbGqluGc1f0XEfhSkiY4jhLgbsJUMKRA==", | |
8042 | 9041 | "license": "Apache-2.0", |
8043 | 9042 | "dependencies": { |
8044 | - "@smithy/protocol-http": "^5.3.7", | |
8045 | - "@smithy/querystring-builder": "^4.2.7", | |
8046 | - "@smithy/types": "^4.11.0", | |
9043 | + "@smithy/protocol-http": "^5.3.8", | |
9044 | + "@smithy/querystring-builder": "^4.2.8", | |
9045 | + "@smithy/types": "^4.12.0", | |
8047 | 9046 | "@smithy/util-base64": "^4.3.0", |
8048 | 9047 | "tslib": "^2.6.2" |
8049 | 9048 | }, |
| @@ -8052,12 +9051,14 @@ | ||
8052 | 9051 | } |
8053 | 9052 | }, |
8054 | 9053 | "node_modules/@smithy/hash-blob-browser": { |
8055 | - "version": "4.2.6", | |
9054 | + "version": "4.2.9", | |
9055 | + "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.9.tgz", | |
9056 | + "integrity": "sha512-m80d/iicI7DlBDxyQP6Th7BW/ejDGiF0bgI754+tiwK0lgMkcaIBgvwwVc7OFbY4eUzpGtnig52MhPAEJ7iNYg==", | |
8056 | 9057 | "license": "Apache-2.0", |
8057 | 9058 | "dependencies": { |
8058 | 9059 | "@smithy/chunked-blob-reader": "^5.2.0", |
8059 | 9060 | "@smithy/chunked-blob-reader-native": "^4.2.1", |
8060 | - "@smithy/types": "^4.9.0", | |
9061 | + "@smithy/types": "^4.12.0", | |
8061 | 9062 | "tslib": "^2.6.2" |
8062 | 9063 | }, |
8063 | 9064 | "engines": { |
| @@ -8065,12 +9066,12 @@ | ||
8065 | 9066 | } |
8066 | 9067 | }, |
8067 | 9068 | "node_modules/@smithy/hash-node": { |
8068 | - "version": "4.2.7", | |
8069 | - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.7.tgz", | |
8070 | - "integrity": "sha512-PU/JWLTBCV1c8FtB8tEFnY4eV1tSfBc7bDBADHfn1K+uRbPgSJ9jnJp0hyjiFN2PMdPzxsf1Fdu0eo9fJ760Xw==", | |
9069 | + "version": "4.2.8", | |
9070 | + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.8.tgz", | |
9071 | + "integrity": "sha512-7ZIlPbmaDGxVoxErDZnuFG18WekhbA/g2/i97wGj+wUBeS6pcUeAym8u4BXh/75RXWhgIJhyC11hBzig6MljwA==", | |
8071 | 9072 | "license": "Apache-2.0", |
8072 | 9073 | "dependencies": { |
8073 | - "@smithy/types": "^4.11.0", | |
9074 | + "@smithy/types": "^4.12.0", | |
8074 | 9075 | "@smithy/util-buffer-from": "^4.2.0", |
8075 | 9076 | "@smithy/util-utf8": "^4.2.0", |
8076 | 9077 | "tslib": "^2.6.2" |
| @@ -8080,10 +9081,12 @@ | ||
8080 | 9081 | } |
8081 | 9082 | }, |
8082 | 9083 | "node_modules/@smithy/hash-stream-node": { |
8083 | - "version": "4.2.5", | |
9084 | + "version": "4.2.8", | |
9085 | + "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.2.8.tgz", | |
9086 | + "integrity": "sha512-v0FLTXgHrTeheYZFGhR+ehX5qUm4IQsjAiL9qehad2cyjMWcN2QG6/4mSwbSgEQzI7jwfoXj7z4fxZUx/Mhj2w==", | |
8084 | 9087 | "license": "Apache-2.0", |
8085 | 9088 | "dependencies": { |
8086 | - "@smithy/types": "^4.9.0", | |
9089 | + "@smithy/types": "^4.12.0", | |
8087 | 9090 | "@smithy/util-utf8": "^4.2.0", |
8088 | 9091 | "tslib": "^2.6.2" |
8089 | 9092 | }, |
| @@ -8092,12 +9095,12 @@ | ||
8092 | 9095 | } |
8093 | 9096 | }, |
8094 | 9097 | "node_modules/@smithy/invalid-dependency": { |
8095 | - "version": "4.2.7", | |
8096 | - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.7.tgz", | |
8097 | - "integrity": "sha512-ncvgCr9a15nPlkhIUx3CU4d7E7WEuVJOV7fS7nnK2hLtPK9tYRBkMHQbhXU1VvvKeBm/O0x26OEoBq+ngFpOEQ==", | |
9098 | + "version": "4.2.8", | |
9099 | + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.8.tgz", | |
9100 | + "integrity": "sha512-N9iozRybwAQ2dn9Fot9kI6/w9vos2oTXLhtK7ovGqwZjlOcxu6XhPlpLpC+INsxktqHinn5gS2DXDjDF2kG5sQ==", | |
8098 | 9101 | "license": "Apache-2.0", |
8099 | 9102 | "dependencies": { |
8100 | - "@smithy/types": "^4.11.0", | |
9103 | + "@smithy/types": "^4.12.0", | |
8101 | 9104 | "tslib": "^2.6.2" |
8102 | 9105 | }, |
8103 | 9106 | "engines": { |
| @@ -8115,10 +9118,12 @@ | ||
8115 | 9118 | } |
8116 | 9119 | }, |
8117 | 9120 | "node_modules/@smithy/md5-js": { |
8118 | - "version": "4.2.5", | |
9121 | + "version": "4.2.8", | |
9122 | + "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.2.8.tgz", | |
9123 | + "integrity": "sha512-oGMaLj4tVZzLi3itBa9TCswgMBr7k9b+qKYowQ6x1rTyTuO1IU2YHdHUa+891OsOH+wCsH7aTPRsTJO3RMQmjQ==", | |
8119 | 9124 | "license": "Apache-2.0", |
8120 | 9125 | "dependencies": { |
8121 | - "@smithy/types": "^4.9.0", | |
9126 | + "@smithy/types": "^4.12.0", | |
8122 | 9127 | "@smithy/util-utf8": "^4.2.0", |
8123 | 9128 | "tslib": "^2.6.2" |
8124 | 9129 | }, |
| @@ -8127,13 +9132,13 @@ | ||
8127 | 9132 | } |
8128 | 9133 | }, |
8129 | 9134 | "node_modules/@smithy/middleware-content-length": { |
8130 | - "version": "4.2.7", | |
8131 | - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.7.tgz", | |
8132 | - "integrity": "sha512-GszfBfCcvt7kIbJ41LuNa5f0wvQCHhnGx/aDaZJCCT05Ld6x6U2s0xsc/0mBFONBZjQJp2U/0uSJ178OXOwbhg==", | |
9135 | + "version": "4.2.8", | |
9136 | + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.8.tgz", | |
9137 | + "integrity": "sha512-RO0jeoaYAB1qBRhfVyq0pMgBoUK34YEJxVxyjOWYZiOKOq2yMZ4MnVXMZCUDenpozHue207+9P5ilTV1zeda0A==", | |
8133 | 9138 | "license": "Apache-2.0", |
8134 | 9139 | "dependencies": { |
8135 | - "@smithy/protocol-http": "^5.3.7", | |
8136 | - "@smithy/types": "^4.11.0", | |
9140 | + "@smithy/protocol-http": "^5.3.8", | |
9141 | + "@smithy/types": "^4.12.0", | |
8137 | 9142 | "tslib": "^2.6.2" |
8138 | 9143 | }, |
8139 | 9144 | "engines": { |
| @@ -8141,18 +9146,18 @@ | ||
8141 | 9146 | } |
8142 | 9147 | }, |
8143 | 9148 | "node_modules/@smithy/middleware-endpoint": { |
8144 | - "version": "4.4.1", | |
8145 | - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.1.tgz", | |
8146 | - "integrity": "sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg==", | |
8147 | - "license": "Apache-2.0", | |
8148 | - "dependencies": { | |
8149 | - "@smithy/core": "^3.20.0", | |
8150 | - "@smithy/middleware-serde": "^4.2.8", | |
8151 | - "@smithy/node-config-provider": "^4.3.7", | |
8152 | - "@smithy/shared-ini-file-loader": "^4.4.2", | |
8153 | - "@smithy/types": "^4.11.0", | |
8154 | - "@smithy/url-parser": "^4.2.7", | |
8155 | - "@smithy/util-middleware": "^4.2.7", | |
9149 | + "version": "4.4.10", | |
9150 | + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.10.tgz", | |
9151 | + "integrity": "sha512-kwWpNltpxrvPabnjEFvwSmA+66l6s2ReCvgVSzW/z92LU4T28fTdgZ18IdYRYOrisu2NMQ0jUndRScbO65A/zg==", | |
9152 | + "license": "Apache-2.0", | |
9153 | + "dependencies": { | |
9154 | + "@smithy/core": "^3.21.0", | |
9155 | + "@smithy/middleware-serde": "^4.2.9", | |
9156 | + "@smithy/node-config-provider": "^4.3.8", | |
9157 | + "@smithy/shared-ini-file-loader": "^4.4.3", | |
9158 | + "@smithy/types": "^4.12.0", | |
9159 | + "@smithy/url-parser": "^4.2.8", | |
9160 | + "@smithy/util-middleware": "^4.2.8", | |
8156 | 9161 | "tslib": "^2.6.2" |
8157 | 9162 | }, |
8158 | 9163 | "engines": { |
| @@ -8160,18 +9165,18 @@ | ||
8160 | 9165 | } |
8161 | 9166 | }, |
8162 | 9167 | "node_modules/@smithy/middleware-retry": { |
8163 | - "version": "4.4.17", | |
8164 | - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.17.tgz", | |
8165 | - "integrity": "sha512-MqbXK6Y9uq17h+4r0ogu/sBT6V/rdV+5NvYL7ZV444BKfQygYe8wAhDrVXagVebN6w2RE0Fm245l69mOsPGZzg==", | |
8166 | - "license": "Apache-2.0", | |
8167 | - "dependencies": { | |
8168 | - "@smithy/node-config-provider": "^4.3.7", | |
8169 | - "@smithy/protocol-http": "^5.3.7", | |
8170 | - "@smithy/service-error-classification": "^4.2.7", | |
8171 | - "@smithy/smithy-client": "^4.10.2", | |
8172 | - "@smithy/types": "^4.11.0", | |
8173 | - "@smithy/util-middleware": "^4.2.7", | |
8174 | - "@smithy/util-retry": "^4.2.7", | |
9168 | + "version": "4.4.26", | |
9169 | + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.26.tgz", | |
9170 | + "integrity": "sha512-ozZMoTAr+B2aVYfLYfkssFvc8ZV3p/vLpVQ7/k277xxUOA9ykSPe5obL2j6yHfbdrM/SZV7qj0uk/hSqavHrLw==", | |
9171 | + "license": "Apache-2.0", | |
9172 | + "dependencies": { | |
9173 | + "@smithy/node-config-provider": "^4.3.8", | |
9174 | + "@smithy/protocol-http": "^5.3.8", | |
9175 | + "@smithy/service-error-classification": "^4.2.8", | |
9176 | + "@smithy/smithy-client": "^4.10.11", | |
9177 | + "@smithy/types": "^4.12.0", | |
9178 | + "@smithy/util-middleware": "^4.2.8", | |
9179 | + "@smithy/util-retry": "^4.2.8", | |
8175 | 9180 | "@smithy/uuid": "^1.1.0", |
8176 | 9181 | "tslib": "^2.6.2" |
8177 | 9182 | }, |
| @@ -8180,13 +9185,13 @@ | ||
8180 | 9185 | } |
8181 | 9186 | }, |
8182 | 9187 | "node_modules/@smithy/middleware-serde": { |
8183 | - "version": "4.2.8", | |
8184 | - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.8.tgz", | |
8185 | - "integrity": "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w==", | |
9188 | + "version": "4.2.9", | |
9189 | + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.9.tgz", | |
9190 | + "integrity": "sha512-eMNiej0u/snzDvlqRGSN3Vl0ESn3838+nKyVfF2FKNXFbi4SERYT6PR392D39iczngbqqGG0Jl1DlCnp7tBbXQ==", | |
8186 | 9191 | "license": "Apache-2.0", |
8187 | 9192 | "dependencies": { |
8188 | - "@smithy/protocol-http": "^5.3.7", | |
8189 | - "@smithy/types": "^4.11.0", | |
9193 | + "@smithy/protocol-http": "^5.3.8", | |
9194 | + "@smithy/types": "^4.12.0", | |
8190 | 9195 | "tslib": "^2.6.2" |
8191 | 9196 | }, |
8192 | 9197 | "engines": { |
| @@ -8194,12 +9199,12 @@ | ||
8194 | 9199 | } |
8195 | 9200 | }, |
8196 | 9201 | "node_modules/@smithy/middleware-stack": { |
8197 | - "version": "4.2.7", | |
8198 | - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.7.tgz", | |
8199 | - "integrity": "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw==", | |
9202 | + "version": "4.2.8", | |
9203 | + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.8.tgz", | |
9204 | + "integrity": "sha512-w6LCfOviTYQjBctOKSwy6A8FIkQy7ICvglrZFl6Bw4FmcQ1Z420fUtIhxaUZZshRe0VCq4kvDiPiXrPZAe8oRA==", | |
8200 | 9205 | "license": "Apache-2.0", |
8201 | 9206 | "dependencies": { |
8202 | - "@smithy/types": "^4.11.0", | |
9207 | + "@smithy/types": "^4.12.0", | |
8203 | 9208 | "tslib": "^2.6.2" |
8204 | 9209 | }, |
8205 | 9210 | "engines": { |
| @@ -8207,14 +9212,14 @@ | ||
8207 | 9212 | } |
8208 | 9213 | }, |
8209 | 9214 | "node_modules/@smithy/node-config-provider": { |
8210 | - "version": "4.3.7", | |
8211 | - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.7.tgz", | |
8212 | - "integrity": "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw==", | |
9215 | + "version": "4.3.8", | |
9216 | + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.8.tgz", | |
9217 | + "integrity": "sha512-aFP1ai4lrbVlWjfpAfRSL8KFcnJQYfTl5QxLJXY32vghJrDuFyPZ6LtUL+JEGYiFRG1PfPLHLoxj107ulncLIg==", | |
8213 | 9218 | "license": "Apache-2.0", |
8214 | 9219 | "dependencies": { |
8215 | - "@smithy/property-provider": "^4.2.7", | |
8216 | - "@smithy/shared-ini-file-loader": "^4.4.2", | |
8217 | - "@smithy/types": "^4.11.0", | |
9220 | + "@smithy/property-provider": "^4.2.8", | |
9221 | + "@smithy/shared-ini-file-loader": "^4.4.3", | |
9222 | + "@smithy/types": "^4.12.0", | |
8218 | 9223 | "tslib": "^2.6.2" |
8219 | 9224 | }, |
8220 | 9225 | "engines": { |
| @@ -8222,15 +9227,15 @@ | ||
8222 | 9227 | } |
8223 | 9228 | }, |
8224 | 9229 | "node_modules/@smithy/node-http-handler": { |
8225 | - "version": "4.4.7", | |
8226 | - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.4.7.tgz", | |
8227 | - "integrity": "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ==", | |
9230 | + "version": "4.4.8", | |
9231 | + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.4.8.tgz", | |
9232 | + "integrity": "sha512-q9u+MSbJVIJ1QmJ4+1u+cERXkrhuILCBDsJUBAW1MPE6sFonbCNaegFuwW9ll8kh5UdyY3jOkoOGlc7BesoLpg==", | |
8228 | 9233 | "license": "Apache-2.0", |
8229 | 9234 | "dependencies": { |
8230 | - "@smithy/abort-controller": "^4.2.7", | |
8231 | - "@smithy/protocol-http": "^5.3.7", | |
8232 | - "@smithy/querystring-builder": "^4.2.7", | |
8233 | - "@smithy/types": "^4.11.0", | |
9235 | + "@smithy/abort-controller": "^4.2.8", | |
9236 | + "@smithy/protocol-http": "^5.3.8", | |
9237 | + "@smithy/querystring-builder": "^4.2.8", | |
9238 | + "@smithy/types": "^4.12.0", | |
8234 | 9239 | "tslib": "^2.6.2" |
8235 | 9240 | }, |
8236 | 9241 | "engines": { |
| @@ -8238,12 +9243,12 @@ | ||
8238 | 9243 | } |
8239 | 9244 | }, |
8240 | 9245 | "node_modules/@smithy/property-provider": { |
8241 | - "version": "4.2.7", | |
8242 | - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.7.tgz", | |
8243 | - "integrity": "sha512-jmNYKe9MGGPoSl/D7JDDs1C8b3dC8f/w78LbaVfoTtWy4xAd5dfjaFG9c9PWPihY4ggMQNQSMtzU77CNgAJwmA==", | |
9246 | + "version": "4.2.8", | |
9247 | + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.8.tgz", | |
9248 | + "integrity": "sha512-EtCTbyIveCKeOXDSWSdze3k612yCPq1YbXsbqX3UHhkOSW8zKsM9NOJG5gTIya0vbY2DIaieG8pKo1rITHYL0w==", | |
8244 | 9249 | "license": "Apache-2.0", |
8245 | 9250 | "dependencies": { |
8246 | - "@smithy/types": "^4.11.0", | |
9251 | + "@smithy/types": "^4.12.0", | |
8247 | 9252 | "tslib": "^2.6.2" |
8248 | 9253 | }, |
8249 | 9254 | "engines": { |
| @@ -8251,12 +9256,12 @@ | ||
8251 | 9256 | } |
8252 | 9257 | }, |
8253 | 9258 | "node_modules/@smithy/protocol-http": { |
8254 | - "version": "5.3.7", | |
8255 | - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.7.tgz", | |
8256 | - "integrity": "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA==", | |
9259 | + "version": "5.3.8", | |
9260 | + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.8.tgz", | |
9261 | + "integrity": "sha512-QNINVDhxpZ5QnP3aviNHQFlRogQZDfYlCkQT+7tJnErPQbDhysondEjhikuANxgMsZrkGeiAxXy4jguEGsDrWQ==", | |
8257 | 9262 | "license": "Apache-2.0", |
8258 | 9263 | "dependencies": { |
8259 | - "@smithy/types": "^4.11.0", | |
9264 | + "@smithy/types": "^4.12.0", | |
8260 | 9265 | "tslib": "^2.6.2" |
8261 | 9266 | }, |
8262 | 9267 | "engines": { |
| @@ -8264,12 +9269,12 @@ | ||
8264 | 9269 | } |
8265 | 9270 | }, |
8266 | 9271 | "node_modules/@smithy/querystring-builder": { |
8267 | - "version": "4.2.7", | |
8268 | - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.7.tgz", | |
8269 | - "integrity": "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg==", | |
9272 | + "version": "4.2.8", | |
9273 | + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.8.tgz", | |
9274 | + "integrity": "sha512-Xr83r31+DrE8CP3MqPgMJl+pQlLLmOfiEUnoyAlGzzJIrEsbKsPy1hqH0qySaQm4oWrCBlUqRt+idEgunKB+iw==", | |
8270 | 9275 | "license": "Apache-2.0", |
8271 | 9276 | "dependencies": { |
8272 | - "@smithy/types": "^4.11.0", | |
9277 | + "@smithy/types": "^4.12.0", | |
8273 | 9278 | "@smithy/util-uri-escape": "^4.2.0", |
8274 | 9279 | "tslib": "^2.6.2" |
8275 | 9280 | }, |
| @@ -8278,12 +9283,12 @@ | ||
8278 | 9283 | } |
8279 | 9284 | }, |
8280 | 9285 | "node_modules/@smithy/querystring-parser": { |
8281 | - "version": "4.2.7", | |
8282 | - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.7.tgz", | |
8283 | - "integrity": "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w==", | |
9286 | + "version": "4.2.8", | |
9287 | + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.8.tgz", | |
9288 | + "integrity": "sha512-vUurovluVy50CUlazOiXkPq40KGvGWSdmusa3130MwrR1UNnNgKAlj58wlOe61XSHRpUfIIh6cE0zZ8mzKaDPA==", | |
8284 | 9289 | "license": "Apache-2.0", |
8285 | 9290 | "dependencies": { |
8286 | - "@smithy/types": "^4.11.0", | |
9291 | + "@smithy/types": "^4.12.0", | |
8287 | 9292 | "tslib": "^2.6.2" |
8288 | 9293 | }, |
8289 | 9294 | "engines": { |
| @@ -8291,24 +9296,24 @@ | ||
8291 | 9296 | } |
8292 | 9297 | }, |
8293 | 9298 | "node_modules/@smithy/service-error-classification": { |
8294 | - "version": "4.2.7", | |
8295 | - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.7.tgz", | |
8296 | - "integrity": "sha512-YB7oCbukqEb2Dlh3340/8g8vNGbs/QsNNRms+gv3N2AtZz9/1vSBx6/6tpwQpZMEJFs7Uq8h4mmOn48ZZ72MkA==", | |
9299 | + "version": "4.2.8", | |
9300 | + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.8.tgz", | |
9301 | + "integrity": "sha512-mZ5xddodpJhEt3RkCjbmUQuXUOaPNTkbMGR0bcS8FE0bJDLMZlhmpgrvPNCYglVw5rsYTpSnv19womw9WWXKQQ==", | |
8297 | 9302 | "license": "Apache-2.0", |
8298 | 9303 | "dependencies": { |
8299 | - "@smithy/types": "^4.11.0" | |
9304 | + "@smithy/types": "^4.12.0" | |
8300 | 9305 | }, |
8301 | 9306 | "engines": { |
8302 | 9307 | "node": ">=18.0.0" |
8303 | 9308 | } |
8304 | 9309 | }, |
8305 | 9310 | "node_modules/@smithy/shared-ini-file-loader": { |
8306 | - "version": "4.4.2", | |
8307 | - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.2.tgz", | |
8308 | - "integrity": "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg==", | |
9311 | + "version": "4.4.3", | |
9312 | + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.3.tgz", | |
9313 | + "integrity": "sha512-DfQjxXQnzC5UbCUPeC3Ie8u+rIWZTvuDPAGU/BxzrOGhRvgUanaP68kDZA+jaT3ZI+djOf+4dERGlm9mWfFDrg==", | |
8309 | 9314 | "license": "Apache-2.0", |
8310 | 9315 | "dependencies": { |
8311 | - "@smithy/types": "^4.11.0", | |
9316 | + "@smithy/types": "^4.12.0", | |
8312 | 9317 | "tslib": "^2.6.2" |
8313 | 9318 | }, |
8314 | 9319 | "engines": { |
| @@ -8316,16 +9321,16 @@ | ||
8316 | 9321 | } |
8317 | 9322 | }, |
8318 | 9323 | "node_modules/@smithy/signature-v4": { |
8319 | - "version": "5.3.7", | |
8320 | - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.7.tgz", | |
8321 | - "integrity": "sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg==", | |
9324 | + "version": "5.3.8", | |
9325 | + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.8.tgz", | |
9326 | + "integrity": "sha512-6A4vdGj7qKNRF16UIcO8HhHjKW27thsxYci+5r/uVRkdcBEkOEiY8OMPuydLX4QHSrJqGHPJzPRwwVTqbLZJhg==", | |
8322 | 9327 | "license": "Apache-2.0", |
8323 | 9328 | "dependencies": { |
8324 | 9329 | "@smithy/is-array-buffer": "^4.2.0", |
8325 | - "@smithy/protocol-http": "^5.3.7", | |
8326 | - "@smithy/types": "^4.11.0", | |
9330 | + "@smithy/protocol-http": "^5.3.8", | |
9331 | + "@smithy/types": "^4.12.0", | |
8327 | 9332 | "@smithy/util-hex-encoding": "^4.2.0", |
8328 | - "@smithy/util-middleware": "^4.2.7", | |
9333 | + "@smithy/util-middleware": "^4.2.8", | |
8329 | 9334 | "@smithy/util-uri-escape": "^4.2.0", |
8330 | 9335 | "@smithy/util-utf8": "^4.2.0", |
8331 | 9336 | "tslib": "^2.6.2" |
| @@ -8335,17 +9340,17 @@ | ||
8335 | 9340 | } |
8336 | 9341 | }, |
8337 | 9342 | "node_modules/@smithy/smithy-client": { |
8338 | - "version": "4.10.2", | |
8339 | - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.10.2.tgz", | |
8340 | - "integrity": "sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g==", | |
9343 | + "version": "4.10.11", | |
9344 | + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.10.11.tgz", | |
9345 | + "integrity": "sha512-6o804SCyHGMXAb5mFJ+iTy9kVKv7F91a9szN0J+9X6p8A0NrdpUxdaC57aye2ipQkP2C4IAqETEpGZ0Zj77Haw==", | |
8341 | 9346 | "license": "Apache-2.0", |
8342 | 9347 | "dependencies": { |
8343 | - "@smithy/core": "^3.20.0", | |
8344 | - "@smithy/middleware-endpoint": "^4.4.1", | |
8345 | - "@smithy/middleware-stack": "^4.2.7", | |
8346 | - "@smithy/protocol-http": "^5.3.7", | |
8347 | - "@smithy/types": "^4.11.0", | |
8348 | - "@smithy/util-stream": "^4.5.8", | |
9348 | + "@smithy/core": "^3.21.0", | |
9349 | + "@smithy/middleware-endpoint": "^4.4.10", | |
9350 | + "@smithy/middleware-stack": "^4.2.8", | |
9351 | + "@smithy/protocol-http": "^5.3.8", | |
9352 | + "@smithy/types": "^4.12.0", | |
9353 | + "@smithy/util-stream": "^4.5.10", | |
8349 | 9354 | "tslib": "^2.6.2" |
8350 | 9355 | }, |
8351 | 9356 | "engines": { |
| @@ -8353,9 +9358,9 @@ | ||
8353 | 9358 | } |
8354 | 9359 | }, |
8355 | 9360 | "node_modules/@smithy/types": { |
8356 | - "version": "4.11.0", | |
8357 | - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.11.0.tgz", | |
8358 | - "integrity": "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA==", | |
9361 | + "version": "4.12.0", | |
9362 | + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.12.0.tgz", | |
9363 | + "integrity": "sha512-9YcuJVTOBDjg9LWo23Qp0lTQ3D7fQsQtwle0jVfpbUHy9qBwCEgKuVH4FqFB3VYu0nwdHKiEMA+oXz7oV8X1kw==", | |
8359 | 9364 | "license": "Apache-2.0", |
8360 | 9365 | "dependencies": { |
8361 | 9366 | "tslib": "^2.6.2" |
| @@ -8365,13 +9370,13 @@ | ||
8365 | 9370 | } |
8366 | 9371 | }, |
8367 | 9372 | "node_modules/@smithy/url-parser": { |
8368 | - "version": "4.2.7", | |
8369 | - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.7.tgz", | |
8370 | - "integrity": "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg==", | |
9373 | + "version": "4.2.8", | |
9374 | + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.8.tgz", | |
9375 | + "integrity": "sha512-NQho9U68TGMEU639YkXnVMV3GEFFULmmaWdlu1E9qzyIePOHsoSnagTGSDv1Zi8DCNN6btxOSdgmy5E/hsZwhA==", | |
8371 | 9376 | "license": "Apache-2.0", |
8372 | 9377 | "dependencies": { |
8373 | - "@smithy/querystring-parser": "^4.2.7", | |
8374 | - "@smithy/types": "^4.11.0", | |
9378 | + "@smithy/querystring-parser": "^4.2.8", | |
9379 | + "@smithy/types": "^4.12.0", | |
8375 | 9380 | "tslib": "^2.6.2" |
8376 | 9381 | }, |
8377 | 9382 | "engines": { |
| @@ -8432,14 +9437,14 @@ | ||
8432 | 9437 | } |
8433 | 9438 | }, |
8434 | 9439 | "node_modules/@smithy/util-defaults-mode-browser": { |
8435 | - "version": "4.3.16", | |
8436 | - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.16.tgz", | |
8437 | - "integrity": "sha512-/eiSP3mzY3TsvUOYMeL4EqUX6fgUOj2eUOU4rMMgVbq67TiRLyxT7Xsjxq0bW3OwuzK009qOwF0L2OgJqperAQ==", | |
9440 | + "version": "4.3.25", | |
9441 | + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.25.tgz", | |
9442 | + "integrity": "sha512-8ugoNMtss2dJHsXnqsibGPqoaafvWJPACmYKxJ4E6QWaDrixsAemmiMMAVbvwYadjR0H9G2+AlzsInSzRi8PSw==", | |
8438 | 9443 | "license": "Apache-2.0", |
8439 | 9444 | "dependencies": { |
8440 | - "@smithy/property-provider": "^4.2.7", | |
8441 | - "@smithy/smithy-client": "^4.10.2", | |
8442 | - "@smithy/types": "^4.11.0", | |
9445 | + "@smithy/property-provider": "^4.2.8", | |
9446 | + "@smithy/smithy-client": "^4.10.11", | |
9447 | + "@smithy/types": "^4.12.0", | |
8443 | 9448 | "tslib": "^2.6.2" |
8444 | 9449 | }, |
8445 | 9450 | "engines": { |
| @@ -8447,17 +9452,17 @@ | ||
8447 | 9452 | } |
8448 | 9453 | }, |
8449 | 9454 | "node_modules/@smithy/util-defaults-mode-node": { |
8450 | - "version": "4.2.19", | |
8451 | - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.19.tgz", | |
8452 | - "integrity": "sha512-3a4+4mhf6VycEJyHIQLypRbiwG6aJvbQAeRAVXydMmfweEPnLLabRbdyo/Pjw8Rew9vjsh5WCdhmDaHkQnhhhA==", | |
9455 | + "version": "4.2.28", | |
9456 | + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.28.tgz", | |
9457 | + "integrity": "sha512-mjUdcP8h3E0K/XvNMi9oBXRV3DMCzeRiYIieZ1LQ7jq5tu6GH/GTWym7a1xIIE0pKSoLcpGsaImuQhGPSIJzAA==", | |
8453 | 9458 | "license": "Apache-2.0", |
8454 | 9459 | "dependencies": { |
8455 | - "@smithy/config-resolver": "^4.4.5", | |
8456 | - "@smithy/credential-provider-imds": "^4.2.7", | |
8457 | - "@smithy/node-config-provider": "^4.3.7", | |
8458 | - "@smithy/property-provider": "^4.2.7", | |
8459 | - "@smithy/smithy-client": "^4.10.2", | |
8460 | - "@smithy/types": "^4.11.0", | |
9460 | + "@smithy/config-resolver": "^4.4.6", | |
9461 | + "@smithy/credential-provider-imds": "^4.2.8", | |
9462 | + "@smithy/node-config-provider": "^4.3.8", | |
9463 | + "@smithy/property-provider": "^4.2.8", | |
9464 | + "@smithy/smithy-client": "^4.10.11", | |
9465 | + "@smithy/types": "^4.12.0", | |
8461 | 9466 | "tslib": "^2.6.2" |
8462 | 9467 | }, |
8463 | 9468 | "engines": { |
| @@ -8465,13 +9470,13 @@ | ||
8465 | 9470 | } |
8466 | 9471 | }, |
8467 | 9472 | "node_modules/@smithy/util-endpoints": { |
8468 | - "version": "3.2.7", | |
8469 | - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.2.7.tgz", | |
8470 | - "integrity": "sha512-s4ILhyAvVqhMDYREeTS68R43B1V5aenV5q/V1QpRQJkCXib5BPRo4s7uNdzGtIKxaPHCfU/8YkvPAEvTpxgspg==", | |
9473 | + "version": "3.2.8", | |
9474 | + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.2.8.tgz", | |
9475 | + "integrity": "sha512-8JaVTn3pBDkhZgHQ8R0epwWt+BqPSLCjdjXXusK1onwJlRuN69fbvSK66aIKKO7SwVFM6x2J2ox5X8pOaWcUEw==", | |
8471 | 9476 | "license": "Apache-2.0", |
8472 | 9477 | "dependencies": { |
8473 | - "@smithy/node-config-provider": "^4.3.7", | |
8474 | - "@smithy/types": "^4.11.0", | |
9478 | + "@smithy/node-config-provider": "^4.3.8", | |
9479 | + "@smithy/types": "^4.12.0", | |
8475 | 9480 | "tslib": "^2.6.2" |
8476 | 9481 | }, |
8477 | 9482 | "engines": { |
| @@ -8489,12 +9494,12 @@ | ||
8489 | 9494 | } |
8490 | 9495 | }, |
8491 | 9496 | "node_modules/@smithy/util-middleware": { |
8492 | - "version": "4.2.7", | |
8493 | - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.7.tgz", | |
8494 | - "integrity": "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w==", | |
9497 | + "version": "4.2.8", | |
9498 | + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.8.tgz", | |
9499 | + "integrity": "sha512-PMqfeJxLcNPMDgvPbbLl/2Vpin+luxqTGPpW3NAQVLbRrFRzTa4rNAASYeIGjRV9Ytuhzny39SpyU04EQreF+A==", | |
8495 | 9500 | "license": "Apache-2.0", |
8496 | 9501 | "dependencies": { |
8497 | - "@smithy/types": "^4.11.0", | |
9502 | + "@smithy/types": "^4.12.0", | |
8498 | 9503 | "tslib": "^2.6.2" |
8499 | 9504 | }, |
8500 | 9505 | "engines": { |
| @@ -8502,13 +9507,13 @@ | ||
8502 | 9507 | } |
8503 | 9508 | }, |
8504 | 9509 | "node_modules/@smithy/util-retry": { |
8505 | - "version": "4.2.7", | |
8506 | - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.7.tgz", | |
8507 | - "integrity": "sha512-SvDdsQyF5CIASa4EYVT02LukPHVzAgUA4kMAuZ97QJc2BpAqZfA4PINB8/KOoCXEw9tsuv/jQjMeaHFvxdLNGg==", | |
9510 | + "version": "4.2.8", | |
9511 | + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.8.tgz", | |
9512 | + "integrity": "sha512-CfJqwvoRY0kTGe5AkQokpURNCT1u/MkRzMTASWMPPo2hNSnKtF1D45dQl3DE2LKLr4m+PW9mCeBMJr5mCAVThg==", | |
8508 | 9513 | "license": "Apache-2.0", |
8509 | 9514 | "dependencies": { |
8510 | - "@smithy/service-error-classification": "^4.2.7", | |
8511 | - "@smithy/types": "^4.11.0", | |
9515 | + "@smithy/service-error-classification": "^4.2.8", | |
9516 | + "@smithy/types": "^4.12.0", | |
8512 | 9517 | "tslib": "^2.6.2" |
8513 | 9518 | }, |
8514 | 9519 | "engines": { |
| @@ -8516,14 +9521,14 @@ | ||
8516 | 9521 | } |
8517 | 9522 | }, |
8518 | 9523 | "node_modules/@smithy/util-stream": { |
8519 | - "version": "4.5.8", | |
8520 | - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.8.tgz", | |
8521 | - "integrity": "sha512-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w==", | |
9524 | + "version": "4.5.10", | |
9525 | + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.10.tgz", | |
9526 | + "integrity": "sha512-jbqemy51UFSZSp2y0ZmRfckmrzuKww95zT9BYMmuJ8v3altGcqjwoV1tzpOwuHaKrwQrCjIzOib499ymr2f98g==", | |
8522 | 9527 | "license": "Apache-2.0", |
8523 | 9528 | "dependencies": { |
8524 | - "@smithy/fetch-http-handler": "^5.3.8", | |
8525 | - "@smithy/node-http-handler": "^4.4.7", | |
8526 | - "@smithy/types": "^4.11.0", | |
9529 | + "@smithy/fetch-http-handler": "^5.3.9", | |
9530 | + "@smithy/node-http-handler": "^4.4.8", | |
9531 | + "@smithy/types": "^4.12.0", | |
8527 | 9532 | "@smithy/util-base64": "^4.3.0", |
8528 | 9533 | "@smithy/util-buffer-from": "^4.2.0", |
8529 | 9534 | "@smithy/util-hex-encoding": "^4.2.0", |
| @@ -8556,11 +9561,13 @@ | ||
8556 | 9561 | } |
8557 | 9562 | }, |
8558 | 9563 | "node_modules/@smithy/util-waiter": { |
8559 | - "version": "4.2.5", | |
9564 | + "version": "4.2.8", | |
9565 | + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.2.8.tgz", | |
9566 | + "integrity": "sha512-n+lahlMWk+aejGuax7DPWtqav8HYnWxQwR+LCG2BgCUmaGcTe9qZCFsmw8TMg9iG75HOwhrJCX9TCJRLH+Yzqg==", | |
8560 | 9567 | "license": "Apache-2.0", |
8561 | 9568 | "dependencies": { |
8562 | - "@smithy/abort-controller": "^4.2.5", | |
8563 | - "@smithy/types": "^4.9.0", | |
9569 | + "@smithy/abort-controller": "^4.2.8", | |
9570 | + "@smithy/types": "^4.12.0", | |
8564 | 9571 | "tslib": "^2.6.2" |
8565 | 9572 | }, |
8566 | 9573 | "engines": { |
| @@ -17231,6 +18238,30 @@ | ||
17231 | 18238 | "url": "https://github.com/sponsors/sindresorhus" |
17232 | 18239 | } |
17233 | 18240 | }, |
18241 | + "node_modules/stream-browserify": { | |
18242 | + "version": "3.0.0", | |
18243 | + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", | |
18244 | + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", | |
18245 | + "license": "MIT", | |
18246 | + "dependencies": { | |
18247 | + "inherits": "~2.0.4", | |
18248 | + "readable-stream": "^3.5.0" | |
18249 | + } | |
18250 | + }, | |
18251 | + "node_modules/stream-browserify/node_modules/readable-stream": { | |
18252 | + "version": "3.6.2", | |
18253 | + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", | |
18254 | + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", | |
18255 | + "license": "MIT", | |
18256 | + "dependencies": { | |
18257 | + "inherits": "^2.0.3", | |
18258 | + "string_decoder": "^1.1.1", | |
18259 | + "util-deprecate": "^1.0.1" | |
18260 | + }, | |
18261 | + "engines": { | |
18262 | + "node": ">= 6" | |
18263 | + } | |
18264 | + }, | |
17234 | 18265 | "node_modules/streamx": { |
17235 | 18266 | "version": "2.23.0", |
17236 | 18267 | "license": "MIT", |
17237 | 18268 | |
▼package.json
+1-0
| @@ -36,6 +36,7 @@ | ||
36 | 36 | "@astrojs/tailwind": "^5.1.0", |
37 | 37 | "@astrojs/vercel": "^7.7.0", |
38 | 38 | "@aws-sdk/client-s3": "^3.948.0", |
39 | + "@aws-sdk/lib-storage": "^3.972.0", | |
39 | 40 | "@aws-sdk/s3-request-presigner": "^3.948.0", |
40 | 41 | "@libsql/client": "^0.15.15", |
41 | 42 | "@monaco-editor/react": "^4.6.0", |
42 | 43 | |
▼scripts/ssh-server.ts
+9-0
| @@ -4,6 +4,7 @@ import { canReadRepo, canWriteRepo } from "@/lib/permissions"; | ||
4 | 4 | import { startSSHServer } from "@/lib/ssh"; |
5 | 5 | import { and, eq } from "drizzle-orm"; |
6 | 6 | import { join } from "path"; |
7 | +import { uploadRepoToStorage, getStorageRepoPath, isCloudStorage } from "@/lib/git-storage"; | |
7 | 8 | |
8 | 9 | const DATA_DIR = join(process.cwd(), "data"); |
9 | 10 | const REPOS_DIR = join(DATA_DIR, "repos"); |
| @@ -111,6 +112,14 @@ async function main() { | ||
111 | 112 | } |
112 | 113 | }); |
113 | 114 | }); |
115 | + // 3. Sync to Cloud Storage (if enabled) | |
116 | + if (await isCloudStorage()) { | |
117 | + console.log(`[SSH] Syncing ${repoPath} to storage...`); | |
118 | + const storagePath = getStorageRepoPath(owner.username, repo.name); | |
119 | + const localRepoPath = join(REPOS_DIR, owner.username, `${repo.name}.git`); | |
120 | + await uploadRepoToStorage(localRepoPath, storagePath); | |
121 | + console.log(`[SSH] Sync complete.`); | |
122 | + } | |
114 | 123 | } |
115 | 124 | } |
116 | 125 | }); |
117 | 126 | |
▼src/components/dashboard/StackCard.astro
+92-0
| @@ -0,0 +1,92 @@ | ||
1 | +--- | |
2 | +interface Props { | |
3 | + stack: { | |
4 | + id: string; | |
5 | + name: string; | |
6 | + repoName: string; | |
7 | + repoOwner: string; | |
8 | + status: string; | |
9 | + updatedAt: string; | |
10 | + prs: { | |
11 | + id: string; | |
12 | + number: number; | |
13 | + title: string; | |
14 | + status: string; | |
15 | + url: string; | |
16 | + position: number; | |
17 | + isMerged: boolean; | |
18 | + isClosed: boolean; | |
19 | + }[]; | |
20 | + }; | |
21 | +} | |
22 | + | |
23 | +const { stack } = Astro.props; | |
24 | + | |
25 | +// Determine stack status color | |
26 | +const isFullyMerged = stack.prs.every(pr => pr.isMerged); | |
27 | +const hasFailures = false; // TODO: Check CI status if available | |
28 | + | |
29 | +const statusColor = isFullyMerged ? "text-green-400" : hasFailures ? "text-red-400" : "text-blue-400"; | |
30 | +const statusBorder = isFullyMerged ? "border-green-500/30" : hasFailures ? "border-red-500/30" : "border-blue-500/30"; | |
31 | +const statusBg = isFullyMerged ? "bg-green-500/10" : hasFailures ? "bg-red-500/10" : "bg-blue-500/10"; | |
32 | +--- | |
33 | + | |
34 | +<div class="relative group"> | |
35 | + <div class="absolute -inset-[1px] bg-gradient-to-r from-blue-500/20 via-cyan-500/20 to-purple-500/20 rounded-xl opacity-0 group-hover:opacity-100 transition-opacity" /> | |
36 | + <div class="relative rounded-xl border border-white/10 bg-[#0d1117]/80 backdrop-blur-sm p-5 hover:bg-white/[0.02] transition-colors"> | |
37 | + | |
38 | + <!-- Header --> | |
39 | + <div class="flex items-center justify-between mb-4"> | |
40 | + <div> | |
41 | + <div class="flex items-center gap-2"> | |
42 | + <span class={`text-sm font-semibold ${statusColor}`}>{stack.name}</span> | |
43 | + <span class="text-xs text-gray-500">in {stack.repoOwner}/{stack.repoName}</span> | |
44 | + </div> | |
45 | + <div class="text-xs text-gray-600 mt-0.5"> | |
46 | + Updated {new Date(stack.updatedAt).toLocaleDateString()} | |
47 | + </div> | |
48 | + </div> | |
49 | + <div class={`text-xs px-2 py-0.5 rounded-full border ${statusBorder} ${statusColor} ${statusBg}`}> | |
50 | + {isFullyMerged ? "Merged" : "Active"} | |
51 | + </div> | |
52 | + </div> | |
53 | + | |
54 | + <!-- Stack Visualization (Subway Map) --> | |
55 | + <div class="relative pl-2 space-y-0"> | |
56 | + {stack.prs.map((pr, index) => ( | |
57 | + <div class="relative flex items-start gap-3 pb-4 last:pb-0"> | |
58 | + <!-- Connecting Line --> | |
59 | + {index !== stack.prs.length - 1 && ( | |
60 | + <div class="absolute left-[5px] top-2.5 bottom-0 w-0.5 bg-gray-800" /> | |
61 | + )} | |
62 | + | |
63 | + <!-- Dot --> | |
64 | + <div class={`relative z-10 w-3 h-3 rounded-full mt-1.5 border-2 ${ | |
65 | + pr.isMerged | |
66 | + ? "bg-green-500 border-green-500" | |
67 | + : pr.isClosed | |
68 | + ? "bg-red-500 border-red-500" | |
69 | + : "bg-[#0d1117] border-blue-500" | |
70 | + }`} /> | |
71 | + | |
72 | + <!-- Content --> | |
73 | + <div class="flex-1 min-w-0 -mt-0.5"> | |
74 | + <a href={pr.url} class="block hover:underline truncate text-sm font-medium text-gray-300 hover:text-blue-400 decoration-blue-400/50"> | |
75 | + {pr.title} | |
76 | + </a> | |
77 | + <div class="flex items-center gap-2 text-xs text-gray-500"> | |
78 | + <span class="font-mono">#{pr.number}</span> | |
79 | + <span>•</span> | |
80 | + <span class={ | |
81 | + pr.isMerged ? "text-green-500" : pr.isClosed ? "text-red-500" : "text-blue-500" | |
82 | + }> | |
83 | + {pr.status.charAt(0).toUpperCase() + pr.status.slice(1)} | |
84 | + </span> | |
85 | + </div> | |
86 | + </div> | |
87 | + </div> | |
88 | + ))} | |
89 | + </div> | |
90 | + | |
91 | + </div> | |
92 | +</div> | |
0 | 93 | |
▼src/components/dashboard/UserAvatar.tsx
+21-0
| @@ -0,0 +1,21 @@ | ||
1 | +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; | |
2 | + | |
3 | +interface UserAvatarProps { | |
4 | + user: { | |
5 | + username: string; | |
6 | + displayName?: string | null; | |
7 | + avatarUrl?: string | null; | |
8 | + }; | |
9 | + className?: string; | |
10 | +} | |
11 | + | |
12 | +export function UserAvatar({ user, className }: UserAvatarProps) { | |
13 | + return ( | |
14 | + <Avatar className={className}> | |
15 | + <AvatarImage src={user.avatarUrl || undefined} alt={user.username} /> | |
16 | + <AvatarFallback className="bg-gradient-to-br from-cyan-500 to-blue-600 text-white text-xl"> | |
17 | + {user.username[0].toUpperCase()} | |
18 | + </AvatarFallback> | |
19 | + </Avatar> | |
20 | + ); | |
21 | +} | |
0 | 22 | |
▼src/db/schema/merge-queue.ts
+16-47
| @@ -1,17 +1,9 @@ | ||
1 | -/** | |
2 | - * Merge Queue Schema | |
3 | - * Stack-aware merge queue with CI optimization | |
4 | - */ | |
5 | - | |
6 | 1 | import { relations } from "drizzle-orm"; |
7 | -import { boolean, integer, pgTable, text, timestamp } from "drizzle-orm/pg-core"; | |
2 | +import { integer, pgTable, text, timestamp } from "drizzle-orm/pg-core"; | |
8 | 3 | import { pullRequests } from "./pull-requests"; |
9 | 4 | import { repositories } from "./repositories"; |
10 | -import { users } from "./users"; | |
11 | -import { prStacks } from "./stacked-prs"; | |
12 | 5 | |
13 | -// Merge queue entries | |
14 | -export const mergeQueue = pgTable("merge_queue", { | |
6 | +export const mergeQueueItems = pgTable("merge_queue_items", { | |
15 | 7 | id: text("id").primaryKey(), |
16 | 8 | repositoryId: text("repository_id") |
17 | 9 | .notNull() |
| @@ -19,55 +11,32 @@ export const mergeQueue = pgTable("merge_queue", { | ||
19 | 11 | pullRequestId: text("pull_request_id") |
20 | 12 | .notNull() |
21 | 13 | .references(() => pullRequests.id, { onDelete: "cascade" }), |
22 | - stackId: text("stack_id").references(() => prStacks.id), // Stack-aware | |
23 | 14 | |
24 | - // Queue status | |
25 | - status: text("status").notNull().default("pending"), // pending, testing, ready, merging, merged, failed | |
26 | - priority: integer("priority").notNull().default(0), // Higher = merge first | |
27 | - position: integer("position"), // Current position in queue | |
15 | + // Status tracking | |
16 | + status: text("status").notNull().default("queued"), // queued, running, failed, merged | |
28 | 17 | |
29 | - // CI integration | |
30 | - ciStatus: text("ci_status").default("pending"), // pending, running, passed, failed | |
31 | - ciRunId: text("ci_run_id"), | |
18 | + // Execution details | |
19 | + attemptCount: integer("attempt_count").default(0), | |
20 | + lastAttemptAt: timestamp("last_attempt_at"), | |
21 | + executionBranch: text("execution_branch"), // mq/pr-123-attempt-1 | |
22 | + position: integer("position").default(0), | |
32 | 23 | |
33 | - // Timing | |
34 | - addedById: text("added_by_id") | |
35 | - .notNull() | |
36 | - .references(() => users.id), | |
37 | - addedAt: timestamp("added_at").notNull().defaultNow(), | |
38 | - estimatedMergeAt: timestamp("estimated_merge_at"), | |
24 | + // Timestamps | |
25 | + queuedAt: timestamp("queued_at").notNull().defaultNow(), | |
39 | 26 | startedAt: timestamp("started_at"), |
40 | 27 | completedAt: timestamp("completed_at"), |
41 | - | |
42 | - // Error handling | |
43 | - failureReason: text("failure_reason"), | |
44 | - retryCount: integer("retry_count").default(0), | |
45 | - | |
46 | - // Merge options | |
47 | - mergeMethod: text("merge_method").default("merge"), // merge, squash, rebase | |
48 | - deleteOnMerge: boolean("delete_on_merge").default(true), | |
49 | 28 | }); |
50 | 29 | |
51 | -// Relations | |
52 | -export const mergeQueueRelations = relations(mergeQueue, ({ one }) => ({ | |
30 | +export const mergeQueueItemsRelations = relations(mergeQueueItems, ({ one }) => ({ | |
53 | 31 | repository: one(repositories, { |
54 | - fields: [mergeQueue.repositoryId], | |
32 | + fields: [mergeQueueItems.repositoryId], | |
55 | 33 | references: [repositories.id], |
56 | 34 | }), |
57 | 35 | pullRequest: one(pullRequests, { |
58 | - fields: [mergeQueue.pullRequestId], | |
36 | + fields: [mergeQueueItems.pullRequestId], | |
59 | 37 | references: [pullRequests.id], |
60 | 38 | }), |
61 | - stack: one(prStacks, { | |
62 | - fields: [mergeQueue.stackId], | |
63 | - references: [prStacks.id], | |
64 | - }), | |
65 | - addedBy: one(users, { | |
66 | - fields: [mergeQueue.addedById], | |
67 | - references: [users.id], | |
68 | - }), | |
69 | 39 | })); |
70 | 40 | |
71 | -// Types | |
72 | -export type MergeQueueEntry = typeof mergeQueue.$inferSelect; | |
73 | -export type NewMergeQueueEntry = typeof mergeQueue.$inferInsert; | |
41 | +export type MergeQueueItem = typeof mergeQueueItems.$inferSelect; | |
42 | +export type NewMergeQueueItem = typeof mergeQueueItems.$inferInsert; | |
74 | 43 | |
▼src/lib/analysis.ts
+13-3
| @@ -3,6 +3,7 @@ import { getDatabase, schema } from "@/db"; | ||
3 | 3 | import type { NodePgDatabase } from "drizzle-orm/node-postgres"; |
4 | 4 | import { logger } from "@/lib/logger"; |
5 | 5 | import { getCommits, getRepoSize, listFiles, getCommitDiff } from "./git"; |
6 | +import { resolveRepoPath } from "./git-storage"; | |
6 | 7 | import { eq } from "drizzle-orm"; |
7 | 8 | import { extname } from "path"; |
8 | 9 | |
| @@ -46,9 +47,18 @@ export async function analyzeRepository(repoId: string, userId: string | null = | ||
46 | 47 | logger.info({ repo: repo.name }, "Analyzing repository"); |
47 | 48 | |
48 | 49 | try { |
50 | + // Resolve disk path for cloud storage | |
51 | + let repoPath: string; | |
52 | + try { | |
53 | + repoPath = await resolveRepoPath(repo.diskPath); | |
54 | + } catch (err) { | |
55 | + logger.warn({ repo: repo.name, err }, "Could not resolve repo path for analysis, skipping"); | |
56 | + return; | |
57 | + } | |
58 | + | |
49 | 59 | // 2. Sync Commits (Last 20 to update recent history) |
50 | 60 | // In a full system we'd diff 'refs/heads/main' vs DB, but here we just fetch recent |
51 | - const commits = await getCommits(repo.diskPath, { limit: 20 }); | |
61 | + const commits = await getCommits(repoPath, { limit: 20 }); | |
52 | 62 | let newCommitsCount = 0; |
53 | 63 | |
54 | 64 | for (const c of commits) { |
| @@ -59,7 +69,7 @@ export async function analyzeRepository(repoId: string, userId: string | null = | ||
59 | 69 | |
60 | 70 | if (!exists) { |
61 | 71 | // Get diff stats |
62 | - const diffs = await getCommitDiff(repo.diskPath, c.sha); | |
72 | + const diffs = await getCommitDiff(repoPath, c.sha); | |
63 | 73 | const additions = diffs.reduce((sum, d) => sum + d.additions, 0); |
64 | 74 | const deletions = diffs.reduce((sum, d) => sum + d.deletions, 0); |
65 | 75 | |
| @@ -88,7 +98,7 @@ export async function analyzeRepository(repoId: string, userId: string | null = | ||
88 | 98 | |
89 | 99 | // 3. Analyze Languages |
90 | 100 | // Scan HEAD files |
91 | - const files = await listFiles(repo.diskPath, "HEAD"); | |
101 | + const files = await listFiles(repoPath, "HEAD"); | |
92 | 102 | const langCounts: Record<string, number> = {}; |
93 | 103 | |
94 | 104 | for (const file of files) { |
95 | 105 | |
▼src/lib/auth-basic.ts
+26-15
| @@ -19,23 +19,34 @@ export async function validateBasicAuth( | ||
19 | 19 | where: eq(schema.users.username, username), |
20 | 20 | }); |
21 | 21 | |
22 | - if (!user || !user.passwordHash) return null; | |
22 | + if (!user) return null; | |
23 | + | |
24 | + // Check if password looks like a Personal Access Token (och_xxx format) | |
25 | + if (password.startsWith("och_")) { | |
26 | + const pat = await db.query.personalAccessTokens.findFirst({ | |
27 | + where: (tokens, { and, eq }) => | |
28 | + and(eq(tokens.userId, user.id), eq(tokens.token, password)), | |
29 | + }); | |
30 | + | |
31 | + if (pat) { | |
32 | + // Update last used at | |
33 | + await db | |
34 | + .update(schema.personalAccessTokens) | |
35 | + .set({ lastUsedAt: new Date() }) | |
36 | + .where(eq(schema.personalAccessTokens.id, pat.id)); | |
37 | + console.log(`[validateBasicAuth] Authenticated ${username} via PAT`); | |
38 | + return user.id; | |
39 | + } | |
40 | + // Token format but not valid | |
41 | + return null; | |
42 | + } | |
23 | 43 | |
24 | - const isValid = await bcrypt.compare(password, user.passwordHash); | |
25 | - if (isValid) return user.id; | |
44 | + // Fall back to password check | |
45 | + if (!user.passwordHash) return null; | |
26 | 46 | |
27 | - // Check Personal Access Token | |
28 | - const pat = await db.query.personalAccessTokens.findFirst({ | |
29 | - where: (tokens, { and, eq }) => | |
30 | - and(eq(tokens.userId, user.id), eq(tokens.token, password)), | |
31 | - }); | |
32 | - | |
33 | - if (pat) { | |
34 | - // Update last used at | |
35 | - await db | |
36 | - .update(schema.personalAccessTokens) | |
37 | - .set({ lastUsedAt: new Date() }) | |
38 | - .where(eq(schema.personalAccessTokens.id, pat.id)); | |
47 | + const isValid = await bcrypt.compare(password, user.passwordHash); | |
48 | + if (isValid) { | |
49 | + console.log(`[validateBasicAuth] Authenticated ${username} via password`); | |
39 | 50 | return user.id; |
40 | 51 | } |
41 | 52 | |
42 | 53 | |
▼src/lib/env-validation.ts
+40-0
| @@ -63,6 +63,33 @@ const envVars: EnvConfig[] = [ | ||
63 | 63 | required: false, |
64 | 64 | defaultValue: "./data/storage", |
65 | 65 | }, |
66 | + // S3 Storage (Required if STORAGE_TYPE=s3) | |
67 | + { | |
68 | + name: "STORAGE_BUCKET", | |
69 | + required: false, | |
70 | + }, | |
71 | + { | |
72 | + name: "STORAGE_ENDPOINT", | |
73 | + required: false, | |
74 | + }, | |
75 | + { | |
76 | + name: "STORAGE_ACCESS_KEY_ID", | |
77 | + required: false, | |
78 | + }, | |
79 | + { | |
80 | + name: "STORAGE_SECRET_ACCESS_KEY", | |
81 | + required: false, | |
82 | + }, | |
83 | + { | |
84 | + name: "STORAGE_REGION", | |
85 | + required: false, | |
86 | + defaultValue: "us-east-1", | |
87 | + }, | |
88 | + // Rclone Storage (Required if STORAGE_TYPE=rclone) | |
89 | + { | |
90 | + name: "STORAGE_RCLONE_REMOTE", | |
91 | + required: false, | |
92 | + }, | |
66 | 93 | |
67 | 94 | // Google Drive |
68 | 95 | { |
| @@ -177,6 +204,19 @@ export function validateEnvironment(exitOnError: boolean = true): boolean { | ||
177 | 204 | if (!process.env.GOOGLE_FOLDER_ID) errors.push("❌ GOOGLE_FOLDER_ID is required when STORAGE_TYPE is 'gdrive'"); |
178 | 205 | } |
179 | 206 | |
207 | + // S3 Validation | |
208 | + if (process.env.STORAGE_TYPE === "s3") { | |
209 | + if (!process.env.STORAGE_BUCKET) errors.push("❌ STORAGE_BUCKET is required when STORAGE_TYPE is 's3'"); | |
210 | + if (!process.env.STORAGE_ACCESS_KEY_ID) errors.push("❌ STORAGE_ACCESS_KEY_ID is required when STORAGE_TYPE is 's3'"); | |
211 | + if (!process.env.STORAGE_SECRET_ACCESS_KEY) errors.push("❌ STORAGE_SECRET_ACCESS_KEY is required when STORAGE_TYPE is 's3'"); | |
212 | + // Endpoint might be optional for AWS S3 but usually required for others. | |
213 | + } | |
214 | + | |
215 | + // Rclone Validation | |
216 | + if (process.env.STORAGE_TYPE === "rclone") { | |
217 | + if (!process.env.STORAGE_RCLONE_REMOTE) errors.push("❌ STORAGE_RCLONE_REMOTE is required when STORAGE_TYPE is 'rclone'"); | |
218 | + } | |
219 | + | |
180 | 220 | // Print results |
181 | 221 | if (warnings.length > 0) { |
182 | 222 | console.log("\n⚠️ Warnings:"); |
183 | 223 | |
▼src/lib/git-server.ts
+387-0
| @@ -0,0 +1,387 @@ | ||
1 | + | |
2 | +import { spawn, ChildProcess } from "child_process"; | |
3 | +import { randomBytes } from "crypto"; | |
4 | +import { createReadStream, createWriteStream } from "fs"; | |
5 | +import * as fs from "fs/promises"; | |
6 | +import { join, dirname } from "path"; | |
7 | +import { PassThrough, Readable, Transform, Writable } from "stream"; | |
8 | +import { pipeline } from "stream/promises"; | |
9 | +import { getStorage } from "./storage"; | |
10 | +import { logger } from "./logger"; | |
11 | + | |
12 | +// Packet Line Utilities | |
13 | +export function pktLine(str: string): string { | |
14 | + const len = Buffer.byteLength(str, "utf8") + 4; | |
15 | + const hex = len.toString(16).padStart(4, "0"); | |
16 | + return `${hex}${str}`; | |
17 | +} | |
18 | + | |
19 | +export function flushPkt(): string { | |
20 | + return "0000"; | |
21 | +} | |
22 | + | |
23 | +// Git Service Types | |
24 | +type GitService = "git-upload-pack" | "git-receive-pack"; | |
25 | + | |
26 | +interface ServiceOptions { | |
27 | + repoPath: string; // Absolute path to bare repo | |
28 | + service: GitService; | |
29 | +} | |
30 | + | |
31 | +/** | |
32 | + * Handles the info/refs request (Step 1 of push/pull) | |
33 | + */ | |
34 | +export async function getAdvertisedRefs(options: ServiceOptions): Promise<Buffer> { | |
35 | + const { repoPath, service } = options; | |
36 | + const serviceHeader = `# service=${service}\n`; | |
37 | + const header = pktLine(serviceHeader) + flushPkt(); | |
38 | + const args = ["--stateless-rpc", "--advertise-refs", repoPath]; | |
39 | + const cmd = service === "git-upload-pack" ? "upload-pack" : "receive-pack"; | |
40 | + | |
41 | + return new Promise((resolve, reject) => { | |
42 | + const child = spawn("git", [cmd, ...args]); | |
43 | + const chunks: Buffer[] = []; | |
44 | + chunks.push(Buffer.from(header, "utf8")); | |
45 | + child.stdout.on("data", (chunk) => chunks.push(chunk)); | |
46 | + child.on("close", (code) => { | |
47 | + if (code === 0) resolve(Buffer.concat(chunks)); | |
48 | + else reject(new Error(`Git ${cmd} exited with code ${code}`)); | |
49 | + }); | |
50 | + child.on("error", reject); | |
51 | + }); | |
52 | +} | |
53 | + | |
54 | +/** | |
55 | + * Handles git-upload-pack (Clone/Fetch) | |
56 | + */ | |
57 | +export async function handleUploadPack( | |
58 | + repoPath: string, | |
59 | + reqBody: Readable | ReadableStream | |
60 | +): Promise<Readable> { | |
61 | + const nodeStream = isReadable(reqBody) ? reqBody : Readable.fromWeb(reqBody as any); | |
62 | + const child = spawn("git", ["upload-pack", "--stateless-rpc", repoPath], { | |
63 | + stdio: ["pipe", "pipe", "pipe"], | |
64 | + }); | |
65 | + nodeStream.pipe(child.stdin); | |
66 | + return child.stdout; | |
67 | +} | |
68 | + | |
69 | +class PackStreamProcessor extends Writable { | |
70 | + private initialized = false; | |
71 | + private storagePass?: PassThrough; | |
72 | + private indexPass?: PassThrough; | |
73 | + private uploadPromise?: Promise<void>; | |
74 | + private indexPack?: ChildProcess; | |
75 | + private indexPackPromise?: Promise<void>; | |
76 | + public packHash = ""; | |
77 | + | |
78 | + private tempIdxPath: string; | |
79 | + private storageTempKey: string; | |
80 | + | |
81 | + constructor( | |
82 | + private repoPath: string, | |
83 | + private dbRepoPath: string, | |
84 | + private storage: any | |
85 | + ) { | |
86 | + super(); | |
87 | + const tempId = randomBytes(8).toString('hex'); | |
88 | + const tempPackName = `incoming-${tempId}.pack`; | |
89 | + this.storageTempKey = `${dbRepoPath}/objects/pack/${tempPackName}`; | |
90 | + this.tempIdxPath = join(process.cwd(), ".tmp", `incoming-${tempId}.idx`); | |
91 | + } | |
92 | + | |
93 | + async cleanup() { | |
94 | + // Logic moved to handleReceivePack to avoid premature deletion | |
95 | + } | |
96 | + | |
97 | + getFinalPaths(hash: string) { | |
98 | + return { | |
99 | + packKey: `${this.dbRepoPath}/objects/pack/pack-${hash}.pack`, | |
100 | + idxKey: `${this.dbRepoPath}/objects/pack/pack-${hash}.idx`, | |
101 | + idxPath: this.tempIdxPath, | |
102 | + tempKey: this.storageTempKey | |
103 | + }; | |
104 | + } | |
105 | + | |
106 | + _write(chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void): void { | |
107 | + if (!this.initialized) { | |
108 | + this.initialized = true; | |
109 | + this.init(chunk).then(() => callback()).catch(callback); | |
110 | + } else { | |
111 | + this.storagePass?.write(chunk); | |
112 | + this.indexPass?.write(chunk); | |
113 | + callback(); | |
114 | + } | |
115 | + } | |
116 | + | |
117 | + private async init(firstChunk: any) { | |
118 | + await fs.mkdir(join(process.cwd(), ".tmp"), { recursive: true }); | |
119 | + | |
120 | + this.storagePass = new PassThrough(); | |
121 | + this.indexPass = new PassThrough(); | |
122 | + | |
123 | + // Start Storage Upload | |
124 | + this.uploadPromise = this.storage.writeStream(this.storageTempKey, this.storagePass); | |
125 | + | |
126 | + // Start Index Pack | |
127 | + // Note: --keep might cause packfile to be written to repo objects/pack directly if cwd is repoPath | |
128 | + this.indexPack = spawn("git", ["index-pack", "--stdin", "-v", "--fix-thin", "--keep", `--index-version=2`, `-o`, this.tempIdxPath], { | |
129 | + cwd: this.repoPath, | |
130 | + stdio: ['pipe', 'pipe', 'pipe'] | |
131 | + }); | |
132 | + | |
133 | + this.indexPackPromise = new Promise<void>((resolve, reject) => { | |
134 | + let out = ""; | |
135 | + this.indexPack!.stdout!.on('data', (d: any) => out += d.toString()); | |
136 | + this.indexPack!.on('close', (code: number) => { | |
137 | + const match = out.trim().match(/([0-9a-f]{40})/); | |
138 | + if (code === 0 && match) { | |
139 | + this.packHash = match[1]; | |
140 | + resolve(); | |
141 | + } else { | |
142 | + reject(new Error(`index-pack failed code=${code} out=${out}`)); | |
143 | + } | |
144 | + }); | |
145 | + this.indexPack!.stderr!.on('data', (d: any) => logger.debug(`[index-pack] ${d}`)); | |
146 | + this.indexPack!.on('error', reject); | |
147 | + }); | |
148 | + | |
149 | + // Pipe PassThroughs | |
150 | + this.storagePass.write(firstChunk); | |
151 | + this.indexPass.pipe(this.indexPack!.stdin!); | |
152 | + this.indexPass.write(firstChunk); | |
153 | + } | |
154 | + | |
155 | + _final(callback: (error?: Error | null) => void): void { | |
156 | + if (this.initialized) { | |
157 | + this.storagePass?.end(); | |
158 | + this.indexPass?.end(); | |
159 | + Promise.all([this.uploadPromise, this.indexPackPromise]) | |
160 | + .then(() => callback()) | |
161 | + .catch((err) => callback(err as Error)); | |
162 | + } else { | |
163 | + callback(); | |
164 | + } | |
165 | + } | |
166 | +} | |
167 | + | |
168 | +/** | |
169 | + * Handles git-receive-pack (Push) | |
170 | + */ | |
171 | +export async function handleReceivePack( | |
172 | + repoPath: string, | |
173 | + reqBody: Readable | ReadableStream, | |
174 | + dbRepoPath: string | |
175 | +): Promise<Readable> { | |
176 | + const storage = await getStorage(); | |
177 | + const inputStream = isReadable(reqBody) ? reqBody : Readable.fromWeb(reqBody as any); | |
178 | + | |
179 | + const { commands, packs } = splitReceivePackStream(inputStream); | |
180 | + | |
181 | + const commandLines: string[] = []; | |
182 | + const commandPromise = new Promise<void>((resolve, reject) => { | |
183 | + commands.on('data', (chunk) => commandLines.push(chunk.toString())); | |
184 | + commands.on('end', resolve); | |
185 | + commands.on('error', reject); | |
186 | + }); | |
187 | + | |
188 | + const packProcessor = new PackStreamProcessor(repoPath, dbRepoPath, storage); | |
189 | + | |
190 | + await new Promise<void>((resolve, reject) => { | |
191 | + pipeline(packs, packProcessor).then(resolve).catch(reject); | |
192 | + }); | |
193 | + | |
194 | + await commandPromise; | |
195 | + | |
196 | + if (packProcessor.packHash) { | |
197 | + const hash = packProcessor.packHash; | |
198 | + const { tempKey, packKey, idxKey, idxPath } = packProcessor.getFinalPaths(hash); | |
199 | + | |
200 | + logger.info(`[ReceivePack] Pack hash: ${hash}`); | |
201 | + | |
202 | + await storage.move(tempKey, packKey); | |
203 | + await storage.put(idxKey, await fs.readFile(idxPath)); | |
204 | + | |
205 | + // Local Object Availability Logic | |
206 | + const localPackDir = join(repoPath, "objects", "pack"); | |
207 | + await fs.mkdir(localPackDir, { recursive: true }); | |
208 | + | |
209 | + const targetIdx = join(localPackDir, `pack-${hash}.idx`); | |
210 | + const targetPack = join(localPackDir, `pack-${hash}.pack`); | |
211 | + const sourcePack = idxPath.replace(".idx", ".pack"); | |
212 | + | |
213 | + // Packfile might already be at destination due to index-pack behavior | |
214 | + try { | |
215 | + await fs.access(targetPack); | |
216 | + } catch { | |
217 | + try { await fs.copyFile(sourcePack, targetPack); } catch { } | |
218 | + } | |
219 | + | |
220 | + // Index file is definitely in .tmp | |
221 | + try { await fs.copyFile(idxPath, targetIdx); } catch { } | |
222 | + | |
223 | + // Cleanup | |
224 | + try { await fs.unlink(idxPath); } catch { } | |
225 | + try { await fs.unlink(sourcePack); } catch { } | |
226 | + | |
227 | + await updateRefs(repoPath, commandLines); | |
228 | + } else if (commandLines.length > 0) { | |
229 | + logger.info(`[ReceivePack] No pack, updating refs only.`); | |
230 | + await updateRefs(repoPath, commandLines); | |
231 | + } | |
232 | + | |
233 | + return reportStatus(commandLines); | |
234 | +} | |
235 | + | |
236 | +// Stateful PktLine Parser | |
237 | +class PktLineDemuxer extends Transform { | |
238 | + private buffer: Buffer = Buffer.alloc(0); | |
239 | + private state: 'LENGTH' | 'DATA' | 'PACK' = 'LENGTH'; | |
240 | + private remainingData: number = 0; | |
241 | + | |
242 | + constructor(private options: { onCommand: (data: Buffer) => void, onPack: (data: Buffer) => void }) { | |
243 | + super(); | |
244 | + } | |
245 | + | |
246 | + _transform(chunk: Buffer, encoding: string, callback: () => void) { | |
247 | + if (this.state === 'PACK') { | |
248 | + this.options.onPack(chunk); | |
249 | + return callback(); | |
250 | + } | |
251 | + | |
252 | + this.buffer = Buffer.concat([this.buffer, chunk]); | |
253 | + | |
254 | + while (true) { | |
255 | + if (this.state === 'LENGTH') { | |
256 | + if (this.buffer.length < 4) break; | |
257 | + | |
258 | + const lenStr = this.buffer.slice(0, 4).toString('utf8'); | |
259 | + | |
260 | + if (lenStr === '0000') { | |
261 | + const rest = this.buffer.slice(4); | |
262 | + if (rest.length > 0) { | |
263 | + this.options.onPack(rest); | |
264 | + } | |
265 | + this.state = 'PACK'; | |
266 | + this.buffer = Buffer.alloc(0); | |
267 | + return callback(); | |
268 | + } | |
269 | + | |
270 | + const len = parseInt(lenStr, 16); | |
271 | + if (isNaN(len)) { | |
272 | + return callback(); | |
273 | + } | |
274 | + | |
275 | + this.remainingData = len - 4; | |
276 | + this.buffer = this.buffer.slice(4); | |
277 | + | |
278 | + if (this.remainingData === 0) { | |
279 | + this.state = 'LENGTH'; | |
280 | + continue; | |
281 | + } | |
282 | + | |
283 | + this.state = 'DATA'; | |
284 | + } | |
285 | + | |
286 | + if (this.state === 'DATA') { | |
287 | + if (this.buffer.length < this.remainingData) break; | |
288 | + | |
289 | + const payload = this.buffer.slice(0, this.remainingData); | |
290 | + this.options.onCommand(payload); | |
291 | + | |
292 | + this.buffer = this.buffer.slice(this.remainingData); | |
293 | + this.state = 'LENGTH'; | |
294 | + } | |
295 | + } | |
296 | + callback(); | |
297 | + } | |
298 | +} | |
299 | + | |
300 | +function splitReceivePackStream(stream: Readable): { commands: Readable; packs: Readable } { | |
301 | + const commands = new PassThrough(); | |
302 | + const packs = new PassThrough(); | |
303 | + const demux = new PktLineDemuxer({ | |
304 | + onCommand: (d) => commands.write(d), | |
305 | + onPack: (d) => packs.write(d) | |
306 | + }); | |
307 | + | |
308 | + stream.pipe(demux); | |
309 | + | |
310 | + demux.on('finish', () => { | |
311 | + commands.end(); | |
312 | + packs.end(); | |
313 | + }); | |
314 | + | |
315 | + demux.on('error', (err) => { | |
316 | + commands.destroy(err); | |
317 | + packs.destroy(err); | |
318 | + }); | |
319 | + | |
320 | + return { commands, packs }; | |
321 | +} | |
322 | + | |
323 | +async function updateRefs(repoPath: string, commandLines: string[]) { | |
324 | + for (const line of commandLines) { | |
325 | + const parts = line.trim().split(' '); | |
326 | + if (parts.length < 3) continue; | |
327 | + | |
328 | + const [oldSha, newSha, refName] = parts; | |
329 | + const cleanRefName = refName.split('\0')[0]; | |
330 | + | |
331 | + if (newSha === "0000000000000000000000000000000000000000") { | |
332 | + await runGit(repoPath, ["update-ref", "-d", cleanRefName, oldSha]); | |
333 | + } else if (oldSha === "0000000000000000000000000000000000000000") { | |
334 | + await runGit(repoPath, ["update-ref", cleanRefName, newSha]); | |
335 | + } else { | |
336 | + await runGit(repoPath, ["update-ref", cleanRefName, newSha, oldSha]); | |
337 | + } | |
338 | + } | |
339 | +} | |
340 | + | |
341 | +function reportStatus(commandBuffs: string[], error?: string): Readable { | |
342 | + const s = new Readable(); | |
343 | + s._read = () => { }; | |
344 | + | |
345 | + // Git receive-pack uses sideband protocol (band 2 for status messages) | |
346 | + const sidebandMsg = (msg: string): Buffer => { | |
347 | + const band = Buffer.from([0x02]); // Band 2 for progress/status | |
348 | + const text = Buffer.from(msg, 'utf8'); | |
349 | + const data = Buffer.concat([band, text]); | |
350 | + const len = data.length + 4; | |
351 | + const hex = len.toString(16).padStart(4, '0'); | |
352 | + return Buffer.concat([Buffer.from(hex, 'utf8'), data]); | |
353 | + }; | |
354 | + | |
355 | + s.push(sidebandMsg(error ? `unpack ${error}\n` : "unpack ok\n")); | |
356 | + | |
357 | + const seen = new Set<string>(); | |
358 | + | |
359 | + for (const line of commandBuffs) { | |
360 | + const parts = line.trim().split(' '); | |
361 | + if (parts.length >= 3) { | |
362 | + const refName = parts[2].split('\0')[0]; | |
363 | + if (!seen.has(refName)) { | |
364 | + s.push(sidebandMsg(error ? `ng ${refName} ${error}\n` : `ok ${refName}\n`)); | |
365 | + seen.add(refName); | |
366 | + } | |
367 | + } | |
368 | + } | |
369 | + s.push(flushPkt()); | |
370 | + s.push(null); | |
371 | + return s; | |
372 | +} | |
373 | + | |
374 | +async function runGit(cwd: string, args: string[]): Promise<void> { | |
375 | + return new Promise((resolve, reject) => { | |
376 | + const child = spawn("git", args, { cwd }); | |
377 | + child.on('close', (code) => { | |
378 | + if (code === 0) resolve(); | |
379 | + else reject(new Error(`git ${args[0]} failed with code ${code}`)); | |
380 | + }); | |
381 | + child.on('error', reject); | |
382 | + }); | |
383 | +} | |
384 | + | |
385 | +function isReadable(stream: any): stream is Readable { | |
386 | + return stream instanceof Readable || (stream && typeof stream.on === 'function'); | |
387 | +} | |
0 | 388 | |
▼src/lib/git-storage.ts
+162-7
| @@ -13,6 +13,8 @@ import * as path from "path"; | ||
13 | 13 | import { join, relative } from "path"; |
14 | 14 | import { Readable } from "stream"; |
15 | 15 | import { getStorage, type StorageAdapter } from "./storage"; |
16 | +import { initRepository } from "./git"; | |
17 | +import { logger } from "./logger"; | |
16 | 18 | |
17 | 19 | // Cache for warm Vercel functions |
18 | 20 | const repoCache = new Map<string, { localPath: string; lastUsed: Date; modified: boolean }>(); |
| @@ -72,6 +74,13 @@ export async function downloadRepoFromStorage( | ||
72 | 74 | // List all files in the storage path |
73 | 75 | const result = await storage.list({ prefix: storagePath }); |
74 | 76 | |
77 | + // If no objects found, repo might not be initialized yet (lazy init) | |
78 | + // This is OK - just return with empty directory | |
79 | + if (!result.objects || result.objects.length === 0) { | |
80 | + console.log(`[downloadRepoFromStorage] No files found at ${storagePath} - repo may not be initialized yet`); | |
81 | + return; | |
82 | + } | |
83 | + | |
75 | 84 | // Download each file |
76 | 85 | for (const obj of result.objects) { |
77 | 86 | const relativePath = obj.key.replace(storagePath, "").replace(/^\//, ""); |
| @@ -112,9 +121,25 @@ export async function uploadRepoToStorage( | ||
112 | 121 | const storage = await getStorage(); |
113 | 122 | console.log(`[uploadRepoToStorage] Starting upload from ${localPath} to ${storagePath}`); |
114 | 123 | |
124 | + // Check if directory exists | |
125 | + if (!existsSync(localPath)) { | |
126 | + console.error(`[uploadRepoToStorage] ERROR: Directory does not exist: ${localPath}`); | |
127 | + return; | |
128 | + } | |
129 | + | |
130 | + // Check what's in the directory | |
131 | + const topLevelEntries = readdirSync(localPath, { withFileTypes: true }); | |
132 | + console.log(`[uploadRepoToStorage] Found ${topLevelEntries.length} top-level entries: ${topLevelEntries.map(e => e.name).join(', ')}`); | |
133 | + | |
115 | 134 | let fileCount = 0; |
116 | 135 | async function uploadDir(dirPath: string): Promise<void> { |
117 | - const entries = readdirSync(dirPath, { withFileTypes: true }); | |
136 | + let entries; | |
137 | + try { | |
138 | + entries = readdirSync(dirPath, { withFileTypes: true }); | |
139 | + } catch (err) { | |
140 | + console.error(`[uploadRepoToStorage] Failed to read directory ${dirPath}:`, err); | |
141 | + return; | |
142 | + } | |
118 | 143 | |
119 | 144 | for (const entry of entries) { |
120 | 145 | const fullPath = join(dirPath, entry.name); |
| @@ -124,10 +149,14 @@ export async function uploadRepoToStorage( | ||
124 | 149 | if (entry.isDirectory()) { |
125 | 150 | await uploadDir(fullPath); |
126 | 151 | } else { |
127 | - const content = await fs.readFile(fullPath); | |
128 | - console.log(`[uploadRepoToStorage] Uploading: ${storageKey} (${content.length} bytes)`); | |
129 | - await storage.put(storageKey, content); | |
130 | - fileCount++; | |
152 | + try { | |
153 | + const content = await fs.readFile(fullPath); | |
154 | + console.log(`[uploadRepoToStorage] Uploading: ${storageKey} (${content.length} bytes)`); | |
155 | + await storage.put(storageKey, content); | |
156 | + fileCount++; | |
157 | + } catch (err) { | |
158 | + console.error(`[uploadRepoToStorage] Failed to upload ${fullPath}:`, err); | |
159 | + } | |
131 | 160 | } |
132 | 161 | } |
133 | 162 | } |
| @@ -191,12 +220,63 @@ export async function acquireRepo(owner: string, repoName: string): Promise<stri | ||
191 | 220 | // Download from storage |
192 | 221 | const localPath = getLocalTempPath(owner, repoName); |
193 | 222 | |
194 | - // Clean up any existing temp files | |
223 | + // Check if local directory already has a valid git repo | |
224 | + // This handles: | |
225 | + // 1. Race condition where upload is in progress but page loads | |
226 | + // 2. Recently created repos where async S3 upload hasn't finished | |
227 | + const headPath = join(localPath, 'HEAD'); | |
228 | + if (existsSync(localPath) && existsSync(headPath)) { | |
229 | + console.log(`[acquireRepo] Local repo exists and has HEAD file, using existing: ${localPath}`); | |
230 | + // Add to cache so subsequent requests use it | |
231 | + repoCache.set(cacheKey, { | |
232 | + localPath, | |
233 | + lastUsed: new Date(), | |
234 | + modified: false, | |
235 | + }); | |
236 | + return localPath; | |
237 | + } | |
238 | + | |
239 | + // Clean up any existing temp files (only if not a valid git repo) | |
195 | 240 | if (existsSync(localPath)) { |
241 | + console.log(`[acquireRepo] Cleaning up incomplete temp directory: ${localPath}`); | |
196 | 242 | rmSync(localPath, { recursive: true, force: true }); |
197 | 243 | } |
198 | 244 | |
199 | - await downloadRepoFromStorage(storagePath, localPath); | |
245 | + // Download from S3 (this might fail if async upload is still in progress) | |
246 | + try { | |
247 | + await downloadRepoFromStorage(storagePath, localPath); | |
248 | + } catch (err) { | |
249 | + console.error(`[acquireRepo] Failed to download from storage:`, err); | |
250 | + // If download fails, the repo might not be uploaded yet | |
251 | + // Try to use local git repos path as fallback | |
252 | + const gitReposPath = import.meta.env?.GIT_REPOS_PATH || process.env.GIT_REPOS_PATH; | |
253 | + const reposPath = gitReposPath | |
254 | + ? (path.isAbsolute(gitReposPath) ? gitReposPath : join(process.cwd(), gitReposPath)) | |
255 | + : join(process.cwd(), "data", "repos"); | |
256 | + const fallbackPath = join(reposPath, owner, `${repoName}.git`); | |
257 | + | |
258 | + if (existsSync(fallbackPath) && existsSync(join(fallbackPath, 'HEAD'))) { | |
259 | + console.log(`[acquireRepo] Using fallback local path: ${fallbackPath}`); | |
260 | + // For local fallback, copy to temp location | |
261 | + // Remove target dir if exists, then copy | |
262 | + if (existsSync(localPath)) { | |
263 | + rmSync(localPath, { recursive: true, force: true }); | |
264 | + } | |
265 | + // Create target directory | |
266 | + mkdirSync(localPath, { recursive: true }); | |
267 | + const { execSync } = await import('child_process'); | |
268 | + // Copy directory CONTENTS (using /. to copy contents, not the directory itself) | |
269 | + execSync(`cp -R "${fallbackPath}/." "${localPath}/"`, { stdio: 'inherit' }); | |
270 | + console.log(`[acquireRepo] Successfully copied from fallback`); | |
271 | + } else { | |
272 | + console.error(`[acquireRepo] No fallback found at: ${fallbackPath}`); | |
273 | + throw new Error(`Repository not found in S3 and local fallback unavailable. S3 upload may still be in progress - try again in a moment.`); | |
274 | + } | |
275 | + } | |
276 | + | |
277 | + // After download, log if repo was initialized | |
278 | + // headPath already declared at line 225 | |
279 | + console.log(`[acquireRepo] After download - HEAD exists: ${existsSync(headPath)}`); | |
200 | 280 | |
201 | 281 | // Cache the path |
202 | 282 | repoCache.set(cacheKey, { |
| @@ -369,3 +449,78 @@ export async function resolveRepoPath(diskPath: string): Promise<string> { | ||
369 | 449 | |
370 | 450 | return acquireRepo(parsed.owner, parsed.repoName); |
371 | 451 | } |
452 | + | |
453 | +/** | |
454 | + * Check if a repository has been initialized with Git | |
455 | + * Checks for the presence of HEAD file in both local and cloud storage | |
456 | + */ | |
457 | +export async function isRepoInitialized(owner: string, repoName: string): Promise<boolean> { | |
458 | + if (!(await isCloudStorage())) { | |
459 | + // Local: check if HEAD file exists | |
460 | + const diskPath = await getDiskPath(owner, repoName); | |
461 | + return existsSync(join(diskPath, 'HEAD')); | |
462 | + } | |
463 | + | |
464 | + // Cloud: check if HEAD exists in S3 | |
465 | + const storage = await getStorage(); | |
466 | + const headPath = `${getStorageRepoPath(owner, repoName)}/HEAD`; | |
467 | + return await storage.exists(headPath); | |
468 | +} | |
469 | + | |
470 | +/** | |
471 | + * Ensure repository is initialized, creating it if needed | |
472 | + * Thread-safe for concurrent first pushes (checks again after acquiring repo) | |
473 | + * | |
474 | + * @returns Local path to the initialized repository | |
475 | + */ | |
476 | +export async function ensureRepoInitialized( | |
477 | + owner: string, | |
478 | + repoName: string, | |
479 | + options: { | |
480 | + defaultBranch?: string; | |
481 | + readme?: boolean; | |
482 | + gitignoreTemplate?: string; | |
483 | + licenseType?: string; | |
484 | + repoName?: string; | |
485 | + ownerName?: string; | |
486 | + } | |
487 | +): Promise<string> { | |
488 | + logger.info({ owner, repoName }, "Ensuring repo is initialized"); | |
489 | + | |
490 | + // Quick check if already initialized (avoid download if possible) | |
491 | + if (await isRepoInitialized(owner, repoName)) { | |
492 | + logger.info("Repo already initialized, acquiring"); | |
493 | + return await acquireRepo(owner, repoName); | |
494 | + } | |
495 | + | |
496 | + logger.info("Repo not initialized, initializing now"); | |
497 | + | |
498 | + // Initialize locally | |
499 | + const localPath = await initRepoInStorage(owner, repoName); | |
500 | + | |
501 | + // Double-check in case of concurrent initialization | |
502 | + const headPath = join(localPath, 'HEAD'); | |
503 | + if (existsSync(headPath)) { | |
504 | + logger.info("HEAD file exists (concurrent init?), using existing"); | |
505 | + return localPath; | |
506 | + } | |
507 | + | |
508 | + logger.info({ localPath }, "Running git init"); | |
509 | + await initRepository(localPath, { | |
510 | + defaultBranch: options.defaultBranch || 'main', | |
511 | + readme: options.readme ?? false, // Don't add README on lazy init by default | |
512 | + gitignoreTemplate: options.gitignoreTemplate, | |
513 | + licenseType: options.licenseType, | |
514 | + repoName: options.repoName || repoName, | |
515 | + ownerName: options.ownerName || owner, | |
516 | + }); | |
517 | + | |
518 | + // Upload to cloud if needed | |
519 | + if (await isCloudStorage()) { | |
520 | + logger.info("Uploading initialized repo to cloud storage"); | |
521 | + await finalizeRepoInit(owner, repoName); | |
522 | + } | |
523 | + | |
524 | + logger.info("Repo initialization complete"); | |
525 | + return localPath; | |
526 | +} | |
372 | 527 | |
▼src/lib/git.ts
+130-52
| @@ -14,7 +14,7 @@ import { | ||
14 | 14 | releaseRepo, |
15 | 15 | } from "@/lib/git-storage"; |
16 | 16 | import { spawn } from "child_process"; |
17 | -import { existsSync, mkdirSync, rmSync } from "fs"; | |
17 | +import { existsSync, mkdirSync, rmSync, readdirSync } from "fs"; | |
18 | 18 | import { basename, dirname, extname, join, resolve } from "path"; |
19 | 19 | import { simpleGit, SimpleGit, SimpleGitOptions } from "simple-git"; |
20 | 20 | |
| @@ -116,78 +116,129 @@ export async function initRepository( | ||
116 | 116 | ownerName = "Owner", |
117 | 117 | } = options; |
118 | 118 | |
119 | + console.log(`[initRepository] Starting initialization at: ${repoPath}`); | |
120 | + | |
119 | 121 | // repoPath should already be a valid local path (provided by caller) |
120 | 122 | const localRepoPath = repoPath; |
121 | 123 | |
122 | - // Ensure directory exists | |
124 | + // Ensure parent directory exists | |
123 | 125 | const dir = dirname(localRepoPath); |
124 | 126 | if (!existsSync(dir)) { |
127 | + console.log(`[initRepository] Creating parent directory: ${dir}`); | |
125 | 128 | mkdirSync(dir, { recursive: true }); |
126 | 129 | } |
127 | 130 | |
131 | + // Ensure the repo directory itself exists | |
132 | + if (!existsSync(localRepoPath)) { | |
133 | + console.log(`[initRepository] Creating repo directory: ${localRepoPath}`); | |
134 | + mkdirSync(localRepoPath, { recursive: true }); | |
135 | + } | |
136 | + | |
128 | 137 | // Initialize bare repository |
129 | - const git = simpleGit(); | |
130 | - await git.init(true, [localRepoPath]); | |
131 | - await installHooks(localRepoPath); | |
138 | + try { | |
139 | + console.log(`[initRepository] Running git init --bare at: ${localRepoPath}`); | |
140 | + const git = simpleGit(localRepoPath); | |
141 | + await git.init(true); | |
142 | + console.log(`[initRepository] git init completed`); | |
143 | + } catch (err) { | |
144 | + console.error(`[initRepository] git init failed:`, err); | |
145 | + throw err; | |
146 | + } | |
147 | + | |
148 | + // Install hooks | |
149 | + try { | |
150 | + console.log(`[initRepository] Installing hooks`); | |
151 | + await installHooks(localRepoPath); | |
152 | + console.log(`[initRepository] Hooks installed`); | |
153 | + } catch (err) { | |
154 | + console.error(`[initRepository] Hook installation failed:`, err); | |
155 | + throw err; | |
156 | + } | |
132 | 157 | |
133 | 158 | // If we need initial content, create a temporary working copy |
134 | 159 | if (readme || gitignoreTemplate || licenseType) { |
135 | 160 | const tempPath = `${localRepoPath}.tmp`; |
161 | + console.log(`[initRepository] Creating temp working copy at: ${tempPath}`); | |
136 | 162 | mkdirSync(tempPath, { recursive: true }); |
137 | 163 | |
138 | - const workingGit = simpleGit(tempPath); | |
139 | - await workingGit.init(); | |
140 | - await workingGit.addConfig("user.name", ownerName); | |
141 | - await workingGit.addConfig("user.email", "[email protected]"); | |
142 | - | |
143 | - // Create README.md | |
144 | - if (readme) { | |
145 | - const readmeContent = `# ${repoName}\\n\\nA new repository created with OpenCodeHub.\\n`; | |
146 | - const readmePath = join(tempPath, "README.md"); | |
147 | - const fs = await import("fs/promises"); | |
148 | - await fs.writeFile(readmePath, readmeContent); | |
149 | - await workingGit.add("README.md"); | |
150 | - } | |
151 | - | |
152 | - // Create .gitignore | |
153 | - if (gitignoreTemplate) { | |
154 | - const gitignorePath = join(tempPath, ".gitignore"); | |
155 | - const gitignoreContent = getGitignoreTemplate(gitignoreTemplate); | |
156 | - const fs = await import("fs/promises"); | |
157 | - await fs.writeFile(gitignorePath, gitignoreContent); | |
158 | - await workingGit.add(".gitignore"); | |
159 | - } | |
164 | + try { | |
165 | + const workingGit = simpleGit(tempPath); | |
166 | + await workingGit.init(); | |
167 | + await workingGit.addConfig("user.name", ownerName); | |
168 | + await workingGit.addConfig("user.email", "[email protected]"); | |
169 | + | |
170 | + // Create README.md | |
171 | + if (readme) { | |
172 | + const readmeContent = `# ${repoName}\n\nA new repository created with OpenCodeHub.\n`; | |
173 | + const readmePath = join(tempPath, "README.md"); | |
174 | + const fs = await import("fs/promises"); | |
175 | + await fs.writeFile(readmePath, readmeContent); | |
176 | + await workingGit.add("README.md"); | |
177 | + console.log(`[initRepository] Created README.md`); | |
178 | + } | |
160 | 179 | |
161 | - // Create LICENSE | |
162 | - if (licenseType) { | |
163 | - const licensePath = join(tempPath, "LICENSE"); | |
164 | - const licenseContent = getLicenseTemplate(licenseType, ownerName); | |
165 | - if (licenseContent) { | |
180 | + // Create .gitignore | |
181 | + if (gitignoreTemplate) { | |
182 | + const gitignorePath = join(tempPath, ".gitignore"); | |
183 | + const gitignoreContent = getGitignoreTemplate(gitignoreTemplate); | |
166 | 184 | const fs = await import("fs/promises"); |
167 | - await fs.writeFile(licensePath, licenseContent); | |
168 | - await workingGit.add("LICENSE"); | |
185 | + await fs.writeFile(gitignorePath, gitignoreContent); | |
186 | + await workingGit.add(".gitignore"); | |
187 | + console.log(`[initRepository] Created .gitignore`); | |
169 | 188 | } |
170 | - } | |
171 | 189 | |
172 | - // Create initial commit | |
173 | - await workingGit.commit("Initial commit"); | |
190 | + // Create LICENSE | |
191 | + if (licenseType) { | |
192 | + const licensePath = join(tempPath, "LICENSE"); | |
193 | + const licenseContent = getLicenseTemplate(licenseType, ownerName); | |
194 | + if (licenseContent) { | |
195 | + const fs = await import("fs/promises"); | |
196 | + await fs.writeFile(licensePath, licenseContent); | |
197 | + await workingGit.add("LICENSE"); | |
198 | + console.log(`[initRepository] Created LICENSE`); | |
199 | + } | |
200 | + } | |
174 | 201 | |
175 | - // Rename branch to default | |
176 | - if (defaultBranch !== "master") { | |
177 | - await workingGit.branch(["-M", defaultBranch]); | |
178 | - } | |
202 | + // Create initial commit | |
203 | + await workingGit.commit("Initial commit"); | |
204 | + console.log(`[initRepository] Created initial commit`); | |
205 | + | |
206 | + // Rename branch to default | |
207 | + if (defaultBranch !== "master") { | |
208 | + await workingGit.branch(["-M", defaultBranch]); | |
209 | + } | |
179 | 210 | |
180 | - // Push to bare repository | |
181 | - await workingGit.addRemote("origin", localRepoPath); | |
182 | - await workingGit.push("origin", defaultBranch); | |
211 | + // Push to bare repository | |
212 | + await workingGit.addRemote("origin", localRepoPath); | |
213 | + await workingGit.push("origin", defaultBranch); | |
214 | + console.log(`[initRepository] Pushed to bare repo`); | |
183 | 215 | |
184 | - // Clean up temp directory | |
185 | - rmSync(tempPath, { recursive: true, force: true }); | |
216 | + // Clean up temp directory | |
217 | + rmSync(tempPath, { recursive: true, force: true }); | |
218 | + console.log(`[initRepository] Cleaned up temp directory`); | |
219 | + } catch (err) { | |
220 | + console.error(`[initRepository] Working copy operations failed:`, err); | |
221 | + // Clean up temp if it exists | |
222 | + if (existsSync(tempPath)) { | |
223 | + rmSync(tempPath, { recursive: true, force: true }); | |
224 | + } | |
225 | + throw err; | |
226 | + } | |
186 | 227 | } |
187 | 228 | |
188 | 229 | // Set default branch in bare repo |
189 | - const bareGit = simpleGit(localRepoPath); | |
190 | - await bareGit.raw(["symbolic-ref", "HEAD", `refs/heads/${defaultBranch}`]); | |
230 | + try { | |
231 | + const bareGit = simpleGit(localRepoPath); | |
232 | + await bareGit.raw(["symbolic-ref", "HEAD", `refs/heads/${defaultBranch}`]); | |
233 | + console.log(`[initRepository] Set default branch to ${defaultBranch}`); | |
234 | + } catch (err) { | |
235 | + console.error(`[initRepository] Failed to set default branch:`, err); | |
236 | + throw err; | |
237 | + } | |
238 | + | |
239 | + // Verify files were created | |
240 | + const files = readdirSync(localRepoPath); | |
241 | + console.log(`[initRepository] Completed. Files in repo: ${files.join(", ")}`); | |
191 | 242 | } |
192 | 243 | |
193 | 244 | /** |
| @@ -592,6 +643,12 @@ export async function getBranches(repoPath: string): Promise<BranchInfo[]> { | ||
592 | 643 | |
593 | 644 | for (const line of output.trim().split("\n").filter(Boolean)) { |
594 | 645 | const [name, sha] = line.split("|"); |
646 | + | |
647 | + // Filter out HEAD and other invalid branch names | |
648 | + if (!name || name === 'HEAD' || name.includes('HEAD')) { | |
649 | + continue; | |
650 | + } | |
651 | + | |
595 | 652 | branches.push({ |
596 | 653 | name, |
597 | 654 | sha, |
| @@ -860,21 +917,41 @@ export async function compareBranches( | ||
860 | 917 | base: string, |
861 | 918 | head: string |
862 | 919 | ): Promise<{ commits: CommitInfo[]; diffs: DiffInfo[] }> { |
920 | + // Verify branches exist first to avoid "ambiguous argument" errors | |
921 | + const fullBase = base.startsWith('refs/') ? base : `refs/heads/${base}`; | |
922 | + const fullHead = head.startsWith('refs/') ? head : `refs/heads/${head}`; | |
923 | + | |
924 | + const git = getGit(repoPath); | |
925 | + | |
926 | + try { | |
927 | + await git.raw(['rev-parse', '--verify', fullBase]); | |
928 | + } catch { | |
929 | + logger.warn({ base, fullBase }, "Base branch not found in compareBranches"); | |
930 | + return { commits: [], diffs: [] }; | |
931 | + } | |
932 | + | |
933 | + try { | |
934 | + await git.raw(['rev-parse', '--verify', fullHead]); | |
935 | + } catch { | |
936 | + // Only warn if head is missing but base exists (uncommon but possible) | |
937 | + logger.warn({ head, fullHead }, "Head branch not found in compareBranches"); | |
938 | + return { commits: [], diffs: [] }; | |
939 | + } | |
940 | + | |
863 | 941 | try { |
864 | 942 | // Get commits between base and head |
865 | 943 | // git log base..head |
866 | 944 | const commits = await getCommits(repoPath, { |
867 | - ref: `${base}..${head}`, | |
945 | + ref: `${fullBase}..${fullHead}`, | |
868 | 946 | limit: 100, // Limit to prevent overload |
869 | 947 | }); |
870 | 948 | |
871 | 949 | // Get diff stats |
872 | 950 | // git diff --numstat base...head (triple dot for merge base comparison) |
873 | - const git = getGit(repoPath); | |
874 | 951 | const output = await git.raw([ |
875 | 952 | "diff", |
876 | 953 | "--numstat", |
877 | - `${base}...${head}`, // Triple dot finds merge base automatically | |
954 | + `${fullBase}...${fullHead}`, // Triple dot finds merge base automatically | |
878 | 955 | ]); |
879 | 956 | |
880 | 957 | const diffs: DiffInfo[] = []; |
| @@ -896,7 +973,8 @@ export async function compareBranches( | ||
896 | 973 | } |
897 | 974 | |
898 | 975 | return { commits, diffs }; |
899 | - } catch (error) { | |
976 | + } catch (error: any) { | |
977 | + // Fallback for any other errors | |
900 | 978 | logger.error({ err: error }, "Error comparing branches"); |
901 | 979 | return { commits: [], diffs: [] }; |
902 | 980 | } |
903 | 981 | |
▼src/lib/queue-worker.ts
+134-0
| @@ -0,0 +1,134 @@ | ||
1 | +import { getDatabase, schema } from "@/db"; | |
2 | +import { eq, and, asc } from "drizzle-orm"; | |
3 | +import { logger } from "@/lib/logger"; | |
4 | +import type { NodePgDatabase } from "drizzle-orm/node-postgres"; | |
5 | +import { mergeBranch } from "@/lib/git"; | |
6 | +import { acquireRepo, releaseRepo } from "@/lib/git-storage"; | |
7 | + | |
8 | +export class QueueWorker { | |
9 | + private isProcessing = false; | |
10 | + | |
11 | + async processQueue(repositoryId: string) { | |
12 | + if (this.isProcessing) return; | |
13 | + this.isProcessing = true; | |
14 | + | |
15 | + const db = getDatabase() as NodePgDatabase<typeof schema>; | |
16 | + | |
17 | + try { | |
18 | + // 1. Check if anything is currently running | |
19 | + const runningItem = await db.query.mergeQueueItems.findFirst({ | |
20 | + where: and( | |
21 | + eq(schema.mergeQueueItems.repositoryId, repositoryId), | |
22 | + eq(schema.mergeQueueItems.status, "running") | |
23 | + ), | |
24 | + }); | |
25 | + | |
26 | + if (runningItem) { | |
27 | + // In a real system, we'd check if the CI job is still active. | |
28 | + // For MVP, we'll assume the previous run crashed if it's been running too long (>10m) | |
29 | + const runtime = Date.now() - (runningItem.startedAt?.getTime() || 0); | |
30 | + if (runtime > 10 * 60 * 1000) { | |
31 | + logger.warn(`Queue item ${runningItem.id} timed out. Marking failed.`); | |
32 | + await db.update(schema.mergeQueueItems) | |
33 | + .set({ status: "failed", completedAt: new Date() }) | |
34 | + .where(eq(schema.mergeQueueItems.id, runningItem.id)); | |
35 | + // Continue to next item | |
36 | + } else { | |
37 | + return; | |
38 | + } | |
39 | + } | |
40 | + | |
41 | + // 2. Pick next item | |
42 | + const nextItem = await db.query.mergeQueueItems.findFirst({ | |
43 | + where: and( | |
44 | + eq(schema.mergeQueueItems.repositoryId, repositoryId), | |
45 | + eq(schema.mergeQueueItems.status, "queued") | |
46 | + ), | |
47 | + orderBy: [asc(schema.mergeQueueItems.queuedAt)], | |
48 | + with: { | |
49 | + repository: { | |
50 | + with: { owner: true } | |
51 | + }, | |
52 | + pullRequest: true | |
53 | + } | |
54 | + }); | |
55 | + | |
56 | + if (!nextItem) { | |
57 | + return; | |
58 | + } | |
59 | + | |
60 | + // 3. Start processing | |
61 | + await db.update(schema.mergeQueueItems) | |
62 | + .set({ | |
63 | + status: "running", | |
64 | + startedAt: new Date(), | |
65 | + attemptCount: (nextItem.attemptCount || 0) + 1, | |
66 | + lastAttemptAt: new Date() | |
67 | + }) | |
68 | + .where(eq(schema.mergeQueueItems.id, nextItem.id)); | |
69 | + | |
70 | + logger.info(`Starting merge for PR ${nextItem.pullRequestId} (${nextItem.repository.owner.username}/${nextItem.repository.name})`); | |
71 | + | |
72 | + // 4. Execution | |
73 | + // A. Acquire Repo (Local or Cloud) | |
74 | + const repoPath = await acquireRepo(nextItem.repository.owner.username, nextItem.repository.name); | |
75 | + | |
76 | + // B. Simulate CI - In a real world, we'd trigger a workflow here and exit, waiting for a webhook callback. | |
77 | + // For MVP "Flesh out", we simulate 'running tests' on the merge result. | |
78 | + | |
79 | + // Attempt Merge Locally first to check conflicts | |
80 | + const result = await mergeBranch(repoPath, nextItem.pullRequest.baseBranch, nextItem.pullRequest.headBranch); | |
81 | + | |
82 | + // Simulate Build Time | |
83 | + await new Promise(r => setTimeout(r, 5000)); | |
84 | + | |
85 | + if (result.success) { | |
86 | + // Success! | |
87 | + // 1. Update PR Status | |
88 | + const now = new Date(); | |
89 | + await db.update(schema.pullRequests) | |
90 | + .set({ | |
91 | + state: "merged", | |
92 | + isMerged: true, | |
93 | + mergedAt: now, | |
94 | + // mergedById: system user? | |
95 | + updatedAt: now, | |
96 | + }) | |
97 | + .where(eq(schema.pullRequests.id, nextItem.pullRequestId)); | |
98 | + | |
99 | + // 2. Update Queue Item | |
100 | + await db.update(schema.mergeQueueItems) | |
101 | + .set({ status: "merged", completedAt: now }) | |
102 | + .where(eq(schema.mergeQueueItems.id, nextItem.id)); | |
103 | + | |
104 | + // 3. Sync Logic (Release Repo with modified=true) | |
105 | + // Since mergeBranch modified the repo (update-ref), we must push back. | |
106 | + await releaseRepo(nextItem.repository.owner.username, nextItem.repository.name, true); | |
107 | + | |
108 | + logger.info(`PR ${nextItem.pullRequestId} merged successfully via queue.`); | |
109 | + } else { | |
110 | + // Failure (Conflict) | |
111 | + await db.update(schema.mergeQueueItems) | |
112 | + .set({ status: "failed", completedAt: new Date() }) | |
113 | + .where(eq(schema.mergeQueueItems.id, nextItem.id)); | |
114 | + | |
115 | + // Release without sync (no changes to base, strict speaking merge-tree doesn't touch base if fail? | |
116 | + // Actually mergeBranch implementation might have failed before update-ref or during conflict check. | |
117 | + await releaseRepo(nextItem.repository.owner.username, nextItem.repository.name, false); | |
118 | + | |
119 | + logger.warn(`PR ${nextItem.pullRequestId} failed to merge: ${result.message}`); | |
120 | + } | |
121 | + | |
122 | + } catch (error) { | |
123 | + logger.error("Error processing merge queue", error); | |
124 | + // Try to release repo if stuck? | |
125 | + // We don't have scope here easily, but acquireRepo is safe to re-acquire (cleans up). | |
126 | + } finally { | |
127 | + this.isProcessing = false; | |
128 | + // Trigger next immediately? | |
129 | + // this.processQueue(repositoryId); | |
130 | + } | |
131 | + } | |
132 | +} | |
133 | + | |
134 | +export const queueWorker = new QueueWorker(); | |
0 | 135 | |
▼src/lib/storage.ts
+69-15
| @@ -90,9 +90,18 @@ export abstract class StorageAdapter { | ||
90 | 90 | |
91 | 91 | abstract put( |
92 | 92 | key: string, |
93 | - data: Buffer | Readable, | |
93 | + data: Buffer | Readable | ReadableStream, | |
94 | 94 | options?: PutOptions |
95 | 95 | ): Promise<void>; |
96 | + | |
97 | + async writeStream( | |
98 | + key: string, | |
99 | + stream: Readable | ReadableStream, | |
100 | + options?: PutOptions | |
101 | + ): Promise<void> { | |
102 | + return this.put(key, stream, options); | |
103 | + } | |
104 | + | |
96 | 105 | abstract get(key: string, options?: GetOptions): Promise<Buffer>; |
97 | 106 | abstract getStream(key: string, options?: GetOptions): Promise<Readable>; |
98 | 107 | abstract delete(key: string): Promise<void>; |
| @@ -115,7 +124,7 @@ export class LocalStorageAdapter extends StorageAdapter { | ||
115 | 124 | |
116 | 125 | async put( |
117 | 126 | key: string, |
118 | - data: Buffer | Readable, | |
127 | + data: Buffer | Readable | ReadableStream, | |
119 | 128 | options?: PutOptions |
120 | 129 | ): Promise<void> { |
121 | 130 | const fullPath = this.getFullPath(key); |
| @@ -125,6 +134,7 @@ export class LocalStorageAdapter extends StorageAdapter { | ||
125 | 134 | await fs.writeFile(fullPath, data); |
126 | 135 | } else { |
127 | 136 | const writeStream = createWriteStream(fullPath); |
137 | + // @ts-ignore | |
128 | 138 | await pipeline(data, writeStream); |
129 | 139 | } |
130 | 140 | |
| @@ -318,16 +328,41 @@ export class S3StorageAdapter extends StorageAdapter { | ||
318 | 328 | await client.send( |
319 | 329 | new PutObjectCommand({ |
320 | 330 | Bucket: this.config.bucket, |
321 | - Key: key, | |
331 | + Key: path.join(this.config.basePath, key), | |
322 | 332 | Body: data, |
323 | 333 | ContentType: options?.contentType, |
324 | 334 | Metadata: options?.metadata, |
325 | 335 | CacheControl: options?.cacheControl, |
326 | - ContentDisposition: options?.contentDisposition, | |
327 | 336 | }) |
328 | 337 | ); |
329 | 338 | } |
330 | 339 | |
340 | + async writeStream( | |
341 | + key: string, | |
342 | + stream: Readable | ReadableStream, | |
343 | + options?: PutOptions | |
344 | + ): Promise<void> { | |
345 | + const { Upload } = await import("@aws-sdk/lib-storage"); | |
346 | + const client = await this.getClient(); | |
347 | + | |
348 | + const upload = new Upload({ | |
349 | + client, | |
350 | + params: { | |
351 | + Bucket: this.config.bucket, | |
352 | + Key: path.join(this.config.basePath, key), | |
353 | + Body: stream, | |
354 | + ContentType: options?.contentType, | |
355 | + Metadata: options?.metadata, | |
356 | + CacheControl: options?.cacheControl, | |
357 | + ContentDisposition: options?.contentDisposition, | |
358 | + }, | |
359 | + queueSize: 4, // Concurrent upload parts | |
360 | + partSize: 5 * 1024 * 1024, // 5MB chunks | |
361 | + }); | |
362 | + | |
363 | + await upload.done(); | |
364 | + } | |
365 | + | |
331 | 366 | async get(key: string, options?: GetOptions): Promise<Buffer> { |
332 | 367 | const { GetObjectCommand } = await import("@aws-sdk/client-s3"); |
333 | 368 | const client = await this.getClient(); |
| @@ -335,7 +370,7 @@ export class S3StorageAdapter extends StorageAdapter { | ||
335 | 370 | const response = await client.send( |
336 | 371 | new GetObjectCommand({ |
337 | 372 | Bucket: this.config.bucket, |
338 | - Key: key, | |
373 | + Key: path.join(this.config.basePath, key), | |
339 | 374 | Range: options?.range |
340 | 375 | ? `bytes=${options.range.start}-${options.range.end}` |
341 | 376 | : undefined, |
| @@ -356,7 +391,7 @@ export class S3StorageAdapter extends StorageAdapter { | ||
356 | 391 | const response = await client.send( |
357 | 392 | new GetObjectCommand({ |
358 | 393 | Bucket: this.config.bucket, |
359 | - Key: key, | |
394 | + Key: path.join(this.config.basePath, key), | |
360 | 395 | Range: options?.range |
361 | 396 | ? `bytes=${options.range.start}-${options.range.end}` |
362 | 397 | : undefined, |
| @@ -373,7 +408,7 @@ export class S3StorageAdapter extends StorageAdapter { | ||
373 | 408 | await client.send( |
374 | 409 | new DeleteObjectCommand({ |
375 | 410 | Bucket: this.config.bucket, |
376 | - Key: key, | |
411 | + Key: path.join(this.config.basePath, key), | |
377 | 412 | }) |
378 | 413 | ); |
379 | 414 | } |
| @@ -386,7 +421,7 @@ export class S3StorageAdapter extends StorageAdapter { | ||
386 | 421 | await client.send( |
387 | 422 | new HeadObjectCommand({ |
388 | 423 | Bucket: this.config.bucket, |
389 | - Key: key, | |
424 | + Key: path.join(this.config.basePath, key), | |
390 | 425 | }) |
391 | 426 | ); |
392 | 427 | return true; |
| @@ -428,13 +463,14 @@ export class S3StorageAdapter extends StorageAdapter { | ||
428 | 463 | const { CopyObjectCommand } = await import("@aws-sdk/client-s3"); |
429 | 464 | const client = await this.getClient(); |
430 | 465 | |
466 | + // CopySource must be key, potentially URL encoded | |
467 | + const sourceFullPath = path.join(this.config.basePath, sourceKey); | |
468 | + const copySource = `${this.config.bucket}/${encodeURIComponent(sourceFullPath)}`; | |
469 | + | |
431 | 470 | await client.send( |
432 | 471 | new CopyObjectCommand({ |
433 | 472 | Bucket: this.config.bucket, |
434 | - CopySource: `${this.config.bucket}/${path.join( | |
435 | - this.config.basePath, | |
436 | - sourceKey | |
437 | - )}`, | |
473 | + CopySource: copySource, | |
438 | 474 | Key: path.join(this.config.basePath, destKey), |
439 | 475 | }) |
440 | 476 | ); |
| @@ -548,7 +584,8 @@ export class RcloneStorageAdapter extends StorageAdapter { | ||
548 | 584 | await fs.writeFile(tempFile, data); |
549 | 585 | } else { |
550 | 586 | const writeStream = createWriteStream(tempFile); |
551 | - await pipeline(data, writeStream); | |
587 | + // @ts-ignore | |
588 | + await pipeline(Readable.from(data as any), writeStream); | |
552 | 589 | } |
553 | 590 | |
554 | 591 | // Use rclone copyto for single file |
| @@ -558,6 +595,14 @@ export class RcloneStorageAdapter extends StorageAdapter { | ||
558 | 595 | } |
559 | 596 | } |
560 | 597 | |
598 | + async writeStream( | |
599 | + key: string, | |
600 | + stream: Readable | ReadableStream, | |
601 | + options?: PutOptions | |
602 | + ): Promise<void> { | |
603 | + return this.put(key, stream, options); // defined above to handle streams via temp file | |
604 | + } | |
605 | + | |
561 | 606 | async get(key: string, options?: GetOptions): Promise<Buffer> { |
562 | 607 | const tempDir = path.join(process.cwd(), 'data', 'temp'); |
563 | 608 | await fs.mkdir(tempDir, { recursive: true }); |
| @@ -1194,9 +1239,18 @@ export async function getStorage(): Promise<StorageAdapter> { | ||
1194 | 1239 | } |
1195 | 1240 | |
1196 | 1241 | if (!storageInstance) { |
1242 | + const storageType = (import.meta.env?.STORAGE_TYPE || process.env.STORAGE_TYPE || "local") as StorageConfig["type"]; | |
1243 | + | |
1244 | + // BasePath should be empty for cloud storage (S3, GCS, etc) | |
1245 | + // Only use directory path for local storage | |
1246 | + let basePath = ""; | |
1247 | + if (storageType === "local") { | |
1248 | + basePath = import.meta.env?.STORAGE_PATH || process.env.STORAGE_PATH || "./data/storage"; | |
1249 | + } | |
1250 | + | |
1197 | 1251 | const config: StorageConfig = { |
1198 | - type: (import.meta.env?.STORAGE_TYPE || process.env.STORAGE_TYPE || "local") as StorageConfig["type"], | |
1199 | - basePath: import.meta.env?.STORAGE_PATH || process.env.STORAGE_PATH || "./data/storage", | |
1252 | + type: storageType, | |
1253 | + basePath, | |
1200 | 1254 | bucket: import.meta.env?.STORAGE_BUCKET || process.env.STORAGE_BUCKET, |
1201 | 1255 | region: import.meta.env?.STORAGE_REGION || process.env.STORAGE_REGION, |
1202 | 1256 | endpoint: import.meta.env?.STORAGE_ENDPOINT || process.env.STORAGE_ENDPOINT, |
1203 | 1257 | |
▼src/middleware.ts
+4-1
| @@ -52,7 +52,10 @@ export const onRequest = defineMiddleware(async (context, next) => { | ||
52 | 52 | context.cookies.delete("och_session", { path: "/" }); |
53 | 53 | } |
54 | 54 | } else { |
55 | - console.log(`[Middleware] No token found for request: ${context.url.pathname}`); | |
55 | + // Only log warning for non-git requests, as git uses Basic Auth handled by backend | |
56 | + if (!context.url.pathname.endsWith(".git") && !context.url.pathname.includes(".git/")) { | |
57 | + console.log(`[Middleware] No token found for request: ${context.url.pathname}`); | |
58 | + } | |
56 | 59 | } |
57 | 60 | |
58 | 61 | // Protected routes logic |
59 | 62 | |
▼src/pages/[owner]/[repo].git/[...path].ts
+19-6
| @@ -34,9 +34,11 @@ export const ALL: APIRoute = async ({ params, request }) => { | ||
34 | 34 | |
35 | 35 | // 2. Auth Check |
36 | 36 | const authHeader = request.headers.get("Authorization"); |
37 | + console.log(`[GitBackend] Auth check for ${ownerName}/${repoName}: authHeader=${authHeader ? 'present' : 'missing'}`); | |
37 | 38 | let userId: string | null = null; |
38 | 39 | if (authHeader) { |
39 | 40 | userId = await validateBasicAuth(authHeader); |
41 | + console.log(`[GitBackend] Auth result: userId=${userId || 'null'}`); | |
40 | 42 | } |
41 | 43 | |
42 | 44 | // 3. Handle Routes |
| @@ -149,18 +151,29 @@ export const ALL: APIRoute = async ({ params, request }) => { | ||
149 | 151 | // Handle process exit |
150 | 152 | child.on("close", async (code) => { |
151 | 153 | if (code === 0) { |
154 | + // Trigger Analysis on successful push | |
152 | 155 | // Trigger Analysis on successful push |
153 | 156 | if (!isUpload) { // git-receive-pack |
154 | 157 | try { |
155 | - // SYNC BACK TO R2 | |
156 | - await releaseRepo(ownerName, repoName, true); | |
157 | - console.log(`Synced ${ownerName}/${repoName} back to R2 after push`); | |
158 | + console.log(`[GitBackend] Push successful, triggering analysis for ${ownerName}/${repoName}`); | |
158 | 159 | |
159 | - // Trigger Analysis | |
160 | + // Trigger Analysis FIRST (while files are still locally present) | |
160 | 161 | const { analyzeRepository } = await import("@/lib/analysis"); |
161 | - await analyzeRepository(repoData.id, userId).catch(console.error); | |
162 | + await analyzeRepository(repoData.id, userId).catch((err) => { | |
163 | + console.error(`[GitBackend] Analysis failed for ${ownerName}/${repoName}:`, err); | |
164 | + }); | |
165 | + console.log(`[GitBackend] Analysis completed for ${ownerName}/${repoName}`); | |
162 | 166 | } catch (err) { |
163 | - console.error("Failed to sync/analyze after push:", err); | |
167 | + console.error("Failed to trigger analysis after push:", err); | |
168 | + } finally { | |
169 | + // SYNC BACK TO R2 (Upload and Cleanup) | |
170 | + // Always run this even if analysis fails | |
171 | + try { | |
172 | + await releaseRepo(ownerName, repoName, true); | |
173 | + console.log(`Synced ${ownerName}/${repoName} back to R2 after push`); | |
174 | + } catch (cleanupErr) { | |
175 | + console.error(`[GitBackend] Failed to clean up ${ownerName}/${repoName}:`, cleanupErr); | |
176 | + } | |
164 | 177 | } |
165 | 178 | } |
166 | 179 | } |
167 | 180 | |
▼src/pages/[owner]/[repo].git/index.ts
+23-0
| @@ -0,0 +1,23 @@ | ||
1 | +import type { APIRoute } from "astro"; | |
2 | + | |
3 | +/** | |
4 | + * Redirect /owner/repo.git to /owner/repo | |
5 | + * This handles the case when a user visits the .git URL directly in a browser | |
6 | + */ | |
7 | +export const GET: APIRoute = async ({ params, redirect }) => { | |
8 | + const { owner, repo } = params; | |
9 | + | |
10 | + if (!owner || !repo) { | |
11 | + return new Response("Not Found", { status: 404 }); | |
12 | + } | |
13 | + | |
14 | + // Remove .git suffix from repo name if present | |
15 | + const repoName = repo.endsWith(".git") ? repo.slice(0, -4) : repo; | |
16 | + | |
17 | + return redirect(`/${owner}/${repoName}`, 302); | |
18 | +}; | |
19 | + | |
20 | +// Also handle POST for git operations that come without a path | |
21 | +export const POST: APIRoute = async ({ params }) => { | |
22 | + return new Response("Bad Request", { status: 400 }); | |
23 | +}; | |
0 | 24 | |
▼src/pages/[owner]/[repo]/commit/[sha].astro
+171-0
| @@ -0,0 +1,171 @@ | ||
1 | +--- | |
2 | +import BaseLayout from "@/layouts/BaseLayout.astro"; | |
3 | +import { getDatabase, schema } from "@/db"; | |
4 | +import { eq, and } from "drizzle-orm"; | |
5 | +import { resolveRepoPath } from "@/lib/git-storage"; | |
6 | +import { getCommitDiff } from "@/lib/git"; | |
7 | +import RepoHeader from "@/components/repo/RepoHeader.astro"; | |
8 | +import { canReadRepo } from "@/lib/permissions"; | |
9 | + | |
10 | +const { owner: ownerName, repo: repoName,sha } = Astro.params; | |
11 | +const db = getDatabase(); | |
12 | + | |
13 | +// Fetch Repo & Owner | |
14 | +const user = await db.query.users.findFirst({ | |
15 | + where: eq(schema.users.username, ownerName!), | |
16 | +}); | |
17 | + | |
18 | +if (!user) return Astro.redirect("/404"); | |
19 | + | |
20 | +const repoData = await db.query.repositories.findFirst({ | |
21 | + where: and( | |
22 | + eq(schema.repositories.ownerId, user.id), | |
23 | + eq(schema.repositories.name, repoName!), | |
24 | + ), | |
25 | + with: { | |
26 | + owner: true, | |
27 | + }, | |
28 | +}); | |
29 | + | |
30 | +if (!repoData) return Astro.redirect("/404"); | |
31 | + | |
32 | +// Check permissions | |
33 | +const currentUser = Astro.locals.user; | |
34 | +const hasAccess = await canReadRepo(currentUser?.id, repoData); | |
35 | + | |
36 | +if (!hasAccess) { | |
37 | + return Astro.redirect("/404"); | |
38 | +} | |
39 | + | |
40 | +const repo = { | |
41 | + owner: repoData.owner.username, | |
42 | + name: repoData.name, | |
43 | + description: repoData.description, | |
44 | + visibility: repoData.visibility, | |
45 | + defaultBranch: repoData.defaultBranch, | |
46 | + stars: repoData.starCount, | |
47 | + forks: repoData.forkCount, | |
48 | + watchers: repoData.watchCount, | |
49 | + language: repoData.language || "Unknown", | |
50 | + license: repoData.licenseType || "None", | |
51 | + topics: repoData.topics ? JSON.parse(repoData.topics) : [], | |
52 | + updatedAt: repoData.updatedAt, | |
53 | + httpCloneUrl: repoData.httpCloneUrl, | |
54 | + sshCloneUrl: repoData.sshCloneUrl, | |
55 | + openIssueCount: repoData.openIssueCount, | |
56 | + openPrCount: repoData.openPrCount, | |
57 | + website: repoData.website, | |
58 | +}; | |
59 | + | |
60 | +// Get commit diff | |
61 | +const resolvedLocalPath = await resolveRepoPath(repoData.diskPath); | |
62 | +let commit: any = null; | |
63 | +let error: string | null = null; | |
64 | + | |
65 | +try { | |
66 | + commit = await getCommitDiff(resolvedLocalPath, sha!); | |
67 | +} catch (e: any) { | |
68 | + console.error("Error fetching commit:", e); | |
69 | + error = e.message || "Failed to fetch commit"; | |
70 | +} | |
71 | + | |
72 | +if (!commit && !error) { | |
73 | + return Astro.redirect("/404"); | |
74 | +} | |
75 | + | |
76 | +function timeAgo(date: Date | string | number) { | |
77 | + if (!date) return ""; | |
78 | + const seconds = Math.floor( | |
79 | + (new Date().getTime() - new Date(date).getTime()) / 1000, | |
80 | + ); | |
81 | + let interval = seconds / 31536000; | |
82 | + if (interval > 1) return Math.floor(interval) + " years ago"; | |
83 | + interval = seconds / 2592000; | |
84 | + if (interval > 1) return Math.floor(interval) + " months ago"; | |
85 | + interval = seconds / 86400; | |
86 | + if (interval > 1) return Math.floor(interval) + " days ago"; | |
87 | + interval = seconds / 3600; | |
88 | + if (interval > 1) return Math.floor(interval) + " hours ago"; | |
89 | + interval = seconds / 60; | |
90 | + if (interval > 1) return Math.floor(interval) + " minutes ago"; | |
91 | + return Math.floor(seconds) + " seconds ago"; | |
92 | +} | |
93 | +--- | |
94 | + | |
95 | +<BaseLayout title={`Commit ${sha?.substring(0, 7)} · ${repo.owner}/${repo.name}`}> | |
96 | + <div class="container py-6"> | |
97 | + <RepoHeader repo={repo} activeTab="code" /> | |
98 | + | |
99 | + {error ? ( | |
100 | + <div class="p-6 text-center"> | |
101 | + <p class="text-destructive">{error}</p> | |
102 | + </div> | |
103 | + ) : commit && ( | |
104 | + <div class="space-y-6"> | |
105 | + <!-- Commit Header --> | |
106 | + <div class="rounded-lg border bg-card p-6"> | |
107 | + <div class="mb-4"> | |
108 | + <h1 class="text-2xl font-bold mb-2">{commit.message}</h1> | |
109 | + {commit.body && ( | |
110 | + <pre class="text-sm text-muted-foreground whitespace-pre-wrap font-sans">{commit.body}</pre> | |
111 | + )} | |
112 | + </div> | |
113 | + | |
114 | + <div class="flex items-center gap-4 text-sm text-muted-foreground border-t pt-4"> | |
115 | + <div class="flex items-center gap-2"> | |
116 | + <div class="h-8 w-8 rounded-full bg-muted flex items-center justify-center"> | |
117 | + <span class="text-sm font-medium"> | |
118 | + {commit.authorName?.[0]?.toUpperCase() || "?"} | |
119 | + </span> | |
120 | + </div> | |
121 | + <div> | |
122 | + <div class="font-medium text-foreground">{commit.authorName}</div> | |
123 | + <div>{commit.authorEmail}</div> | |
124 | + </div> | |
125 | + </div> | |
126 | + <div class="flex-1"></div> | |
127 | + <div> | |
128 | + committed {timeAgo(commit.authorDate)} | |
129 | + </div> | |
130 | + </div> | |
131 | + | |
132 | + <div class="mt-4 flex items-center gap-4 text-sm"> | |
133 | + <div class="font-mono bg-muted px-3 py-1 rounded"> | |
134 | + {(commit.sha || sha)?.substring(0, 7)} | |
135 | + </div> | |
136 | + <div class="text-muted-foreground"> | |
137 | + {commit.stats?.additions || 0} additions, {commit.stats?.deletions || 0} deletions | |
138 | + </div> | |
139 | + </div> | |
140 | + </div> | |
141 | + | |
142 | + <!-- Changed Files --> | |
143 | + <div class="space-y-4"> | |
144 | + <h2 class="text-lg font-semibold">Changed files</h2> | |
145 | + | |
146 | + {commit.files && commit.files.length > 0 ? ( | |
147 | + commit.files.map((file: any) => ( | |
148 | + <div class="rounded-lg border overflow-hidden"> | |
149 | + <div class="flex items-center justify-between bg-muted/30 px-4 py-2 border-b"> | |
150 | + <span class="font-mono text-sm">{file.path}</span> | |
151 | + <span class="text-sm text-muted-foreground"> | |
152 | + +{file.additions || 0} -{file.deletions || 0} | |
153 | + </span> | |
154 | + </div> | |
155 | + {file.diff && ( | |
156 | + <div class="overflow-x-auto"> | |
157 | + <pre class="text-xs p-4 bg-background font-mono"><code>{file.diff}</code></pre> | |
158 | + </div> | |
159 | + )} | |
160 | + </div> | |
161 | + )) | |
162 | + ) : ( | |
163 | + <div class="text-center text-muted-foreground py-8"> | |
164 | + No files changed | |
165 | + </div> | |
166 | + )} | |
167 | + </div> | |
168 | + </div> | |
169 | + )} | |
170 | + </div> | |
171 | +</BaseLayout> | |
0 | 172 | |
▼src/pages/[owner]/[repo]/pulls/[number].astro
+82-12
| @@ -22,10 +22,13 @@ import { | ||
22 | 22 | AlertCircle, |
23 | 23 | Layers, |
24 | 24 | ChevronRight, |
25 | + ListOrdered, | |
25 | 26 | } from "lucide-react"; |
26 | 27 | |
28 | +import type { NodePgDatabase } from "drizzle-orm/node-postgres"; | |
29 | + | |
27 | 30 | const { owner: ownerName, repo: repoName, number } = Astro.params; |
28 | -const db = getDatabase(); | |
31 | +const db = getDatabase() as NodePgDatabase<typeof schema>; | |
29 | 32 | |
30 | 33 | const user = Astro.locals.user; |
31 | 34 | |
| @@ -64,6 +67,11 @@ const pr = await db.query.pullRequests.findFirst({ | ||
64 | 67 | |
65 | 68 | if (!pr) return Astro.redirect("/404"); |
66 | 69 | |
70 | +// Check Queue Status | |
71 | +const queueItem = await db.query.mergeQueueItems.findFirst({ | |
72 | + where: eq(schema.mergeQueueItems.pullRequestId, pr.id), | |
73 | +}); | |
74 | + | |
67 | 75 | // Fetch Stack Info |
68 | 76 | let stackInfo = null; |
69 | 77 | try { |
| @@ -97,7 +105,6 @@ try { | ||
97 | 105 | |
98 | 106 | // Fetch open issue count (for header) |
99 | 107 | const issueCountResult = (await db |
100 | - // @ts-expect-error: count argument mismatch | |
101 | 108 | .select({ count: sql<number>`count(*)` }) |
102 | 109 | .from(schema.issues) |
103 | 110 | .where( |
| @@ -105,10 +112,9 @@ const issueCountResult = (await db | ||
105 | 112 | eq(schema.issues.repositoryId, repoData.id), |
106 | 113 | eq(schema.issues.state, "open"), |
107 | 114 | ), |
108 | - ) | |
109 | - ) as { count: number }[]; | |
115 | + )) as { count: number }[]; | |
110 | 116 | |
111 | -const openIssueCount = issueCountResult?.count || 0; | |
117 | +const openIssueCount = issueCountResult[0]?.count || 0; | |
112 | 118 | |
113 | 119 | const repo = { |
114 | 120 | owner: repoData.owner.username, |
| @@ -135,8 +141,11 @@ let diffData: { commits: CommitInfo[]; diffs: DiffInfo[] } = { | ||
135 | 141 | diffs: [], |
136 | 142 | }; |
137 | 143 | |
144 | +import { resolveRepoPath } from "@/lib/git-storage"; | |
138 | 145 | try { |
139 | - const repoPath = getRepoPath(repoData.owner.username, repoData.name); | |
146 | + const repoPath = await resolveRepoPath( | |
147 | + getRepoPath(repoData.owner.username, repoData.name), | |
148 | + ); | |
140 | 149 | diffData = await compareBranches(repoPath, pr.baseBranch, pr.headBranch); |
141 | 150 | } catch (error) { |
142 | 151 | console.error("Error fetching comparison:", error); |
| @@ -249,19 +258,29 @@ try { | ||
249 | 258 | <div class="border rounded-lg bg-muted/10 p-4"> |
250 | 259 | <div class="flex items-start gap-4"> |
251 | 260 | <div class="mt-1"> |
252 | - <div class="h-8 w-8 rounded-full bg-green-500 flex items-center justify-center text-white"> | |
253 | - <GitMerge className="h-4 w-4" /> | |
254 | - </div> | |
261 | + {queueItem ? ( | |
262 | + <div class="h-8 w-8 rounded-full bg-blue-500 flex items-center justify-center text-white"> | |
263 | + <ListOrdered className="h-4 w-4 animate-pulse" /> | |
264 | + </div> | |
265 | + ) : ( | |
266 | + <div class="h-8 w-8 rounded-full bg-green-500 flex items-center justify-center text-white"> | |
267 | + <GitMerge className="h-4 w-4" /> | |
268 | + </div> | |
269 | + )} | |
255 | 270 | </div> |
256 | 271 | <div class="flex-1"> |
257 | 272 | <h4 class="font-medium mb-1"> |
258 | - This branch has no conflicts with the base branch | |
273 | + {queueItem | |
274 | + ? "This PR is in the merge queue" | |
275 | + : "This branch has no conflicts with the base branch"} | |
259 | 276 | </h4> |
260 | 277 | <p class="text-sm text-muted-foreground mb-4"> |
261 | - Merging can be performed automatically. | |
278 | + {queueItem | |
279 | + ? `Position: ${queueItem.position || "Pending"} • Status: ${queueItem.status}` | |
280 | + : "Merging can be performed automatically."} | |
262 | 281 | </p> |
263 | 282 | |
264 | - {canWrite && ( | |
283 | + {canWrite && !queueItem && ( | |
265 | 284 | <div class="flex items-center gap-2"> |
266 | 285 | <Button |
267 | 286 | id="merge-btn" |
| @@ -269,6 +288,14 @@ try { | ||
269 | 288 | > |
270 | 289 | Merge pull request |
271 | 290 | </Button> |
291 | + <Button | |
292 | + id="queue-btn" | |
293 | + variant="secondary" | |
294 | + className="border-primary/20 hover:bg-primary/10 text-primary" | |
295 | + > | |
296 | + <ListOrdered className="mr-2 h-4 w-4" /> | |
297 | + Add to merge queue | |
298 | + </Button> | |
272 | 299 | <div |
273 | 300 | id="merge-error" |
274 | 301 | class="text-sm text-red-500 hidden font-medium flex items-center gap-1" |
| @@ -278,6 +305,19 @@ try { | ||
278 | 305 | </div> |
279 | 306 | </div> |
280 | 307 | )} |
308 | + {queueItem && ( | |
309 | + <div class="flex items-center gap-2"> | |
310 | + <Button variant="outline" disabled> | |
311 | + In Queue | |
312 | + </Button> | |
313 | + <a | |
314 | + href={`/${repo.owner}/${repo.name}/merge-queue`} | |
315 | + class="text-sm text-blue-500 hover:underline" | |
316 | + > | |
317 | + View Queue | |
318 | + </a> | |
319 | + </div> | |
320 | + )} | |
281 | 321 | </div> |
282 | 322 | </div> |
283 | 323 | </div> |
| @@ -420,11 +460,41 @@ try { | ||
420 | 460 | repoOwner: repo.owner, |
421 | 461 | repoName: repo.name, |
422 | 462 | prNumber: pr.number, |
463 | + prId: pr.id, | |
423 | 464 | }} |
424 | 465 | > |
425 | 466 | const mergeBtn = document.getElementById("merge-btn"); |
467 | + const queueBtn = document.getElementById("queue-btn"); | |
426 | 468 | const errorDiv = document.getElementById("merge-error"); |
427 | 469 | |
470 | + queueBtn?.addEventListener("click", async () => { | |
471 | + queueBtn.setAttribute("disabled", "true"); | |
472 | + queueBtn.textContent = "Queueing..."; | |
473 | + errorDiv.classList.add("hidden"); | |
474 | + | |
475 | + try { | |
476 | + const res = await fetch( | |
477 | + `/api/repos/${repoOwner}/${repoName}/queue/join`, | |
478 | + { | |
479 | + method: "POST", | |
480 | + headers: { "Content-Type": "application/json" }, | |
481 | + body: JSON.stringify({ pullRequestId: prId }), | |
482 | + }, | |
483 | + ); | |
484 | + | |
485 | + if (!res.ok) { | |
486 | + const data = await res.json(); | |
487 | + throw new Error(data.error?.message || "Failed to enqueue"); | |
488 | + } | |
489 | + window.location.reload(); | |
490 | + } catch (e) { | |
491 | + errorDiv.querySelector("span").textContent = e.message; | |
492 | + errorDiv.classList.remove("hidden"); | |
493 | + queueBtn.removeAttribute("disabled"); | |
494 | + queueBtn.textContent = "Add to merge queue"; | |
495 | + } | |
496 | + }); | |
497 | + | |
428 | 498 | mergeBtn?.addEventListener("click", async () => { |
429 | 499 | if (!confirm("Are you sure you want to merge this pull request?")) return; |
430 | 500 | |
431 | 501 | |
▼src/pages/[owner]/[repo]/raw/[branch]/[...path].ts
+5-1
| @@ -1,5 +1,6 @@ | ||
1 | 1 | import { getDatabase, schema } from "@/db"; |
2 | 2 | import { getFileRawContent } from "@/lib/git"; |
3 | +import { resolveRepoPath } from "@/lib/git-storage"; | |
3 | 4 | import { canReadRepo } from "@/lib/permissions"; |
4 | 5 | import type { APIRoute } from "astro"; |
5 | 6 | import { and, eq } from "drizzle-orm"; |
| @@ -39,8 +40,11 @@ export const GET: APIRoute = async ({ params, locals }) => { | ||
39 | 40 | const filePath = path || ""; |
40 | 41 | |
41 | 42 | try { |
43 | + // Resolve disk path for cloud storage | |
44 | + const repoPath = await resolveRepoPath(repoData.diskPath); | |
45 | + | |
42 | 46 | const content = await getFileRawContent( |
43 | - repoData.diskPath, | |
47 | + repoPath, | |
44 | 48 | filePath, |
45 | 49 | currentBranch |
46 | 50 | ); |
47 | 51 | |
▼src/pages/[owner]/[repo]/tree/[...ref].astro
+101-8
| @@ -90,7 +90,13 @@ const refParam = Astro.params.ref || ""; | ||
90 | 90 | let currentBranch = repoData.defaultBranch; |
91 | 91 | let currentPath = ""; |
92 | 92 | |
93 | -// Find the longest matching branch name | |
93 | +// Helper to check if a ref exists | |
94 | +// We need to check if the refParam (or parts of it) is a valid branch/ref | |
95 | +// Since getBranches might return incomplete list or fail, we'll try to resolve it directly | |
96 | +let resolvedBranch = ""; | |
97 | +let resolvedPath = ""; | |
98 | + | |
99 | +// 1. Check against known branches (fastest) | |
94 | 100 | const matchingBranch = branches |
95 | 101 | .filter((b) => refParam === b || refParam.startsWith(b + "/")) |
96 | 102 | .sort((a, b) => b.length - a.length)[0]; |
| @@ -99,13 +105,100 @@ if (matchingBranch) { | ||
99 | 105 | currentBranch = matchingBranch; |
100 | 106 | currentPath = refParam.slice(matchingBranch.length).replace(/^\//, ""); |
101 | 107 | } else { |
102 | - // If no match, maybe it's a commit hash or we default to main and treat Ref as path? | |
103 | - // For now, assume default branch if no match found (or 404) | |
104 | - // Actually, if we are in /tree/, we expect the first part to be a ref. | |
105 | - // If it's a valid commit SHA, we could use that. | |
106 | - // Let's assume it's a branch for now. | |
107 | - currentBranch = refParam.split("/")[0]; | |
108 | - currentPath = refParam.split("/").slice(1).join("/"); | |
108 | + // 2. Fallback: Try to identify where the branch name ends and path starts | |
109 | + // This is tricky for "stack/feature-1/src". Is it branch "stack" path "feature-1/src" or branch "stack/feature-1" path "src"? | |
110 | + // We'll optimistically assume the longest possible prefix that *could* be a ref is the branch. | |
111 | + | |
112 | + // Since we can't easily check every permutation without spamming git, | |
113 | + // and we know getBranches might have missed it if it's new/remote-only that just got synced? | |
114 | + // Actually, resolveRepoPath ensures we have the repo. getBranches should see it. | |
115 | + | |
116 | + // IF getBranches missed it, it might be because the branch is "refs/heads/stack/feature-1" | |
117 | + // and getBranches returned "stack/feature-1". | |
118 | + | |
119 | + // Let's assume the first segment is the branch if no match found, BUT | |
120 | + // for "stack/feature-1", current logic picked "stack". | |
121 | + | |
122 | + // Improved Heuristic: | |
123 | + // If the refParam contains slashes, try to verify if the full thing is a ref first? | |
124 | + // No, because it might be "main/README.md". | |
125 | + | |
126 | + // Better fallback: | |
127 | + // Default to treating the whole first part as branch is dangerous. | |
128 | + // Instead, let's try to pass the WHOLE refParam as the ref if it looks like a branch? | |
129 | + // But subsequent git operations (listFiles) need strict separation. | |
130 | + | |
131 | + // We will try to resolve the branch by invoking a quick check? | |
132 | + // No, we can't easily do async inside this synchronous block structure easily without restructuring. | |
133 | + | |
134 | + // FIX: Just update the fallback to handle common "stack/" or "feature/" prefixes? | |
135 | + // Or, since we know getBranches output matches, maybe getBranches output IS "stack/feature-1"? | |
136 | + // The Logs said: "Available refs... refs/heads/stack/feature-1". | |
137 | + // So getBranches SHOULD have returned "stack/feature-1". | |
138 | + | |
139 | + // Why did it fail? | |
140 | + // "branches" variable is populated via: branches = branchInfos.map(b => b.name); | |
141 | + | |
142 | + // Hypothethis: getBranches failed or returned empty? | |
143 | + // The previous logs showed "Ambiguous argument" error before this. | |
144 | + // Maybe getBranches failed silently in the try/catch block line 85? | |
145 | + | |
146 | + // If getBranches failed, branches = [repoData.defaultBranch]. | |
147 | + // Repo default is "main". User is visiting "stack/feature-1". | |
148 | + // "stack/feature-1" does not start with "main". | |
149 | + // So it goes to fallback. | |
150 | + // Fallback: currentBranch = refParam.split("/")[0] -> "stack". | |
151 | + // currentPath = "feature-1". | |
152 | + // git log stack -- feature-1 -> ERROR. | |
153 | + | |
154 | + // SOLUTION: If getBranches failed or didn't contain it, we need to try to trust the refParam more. | |
155 | + // If the ref looks like a branch, treat it as one. | |
156 | + | |
157 | + // Let's add a check using `git rev-parse --verify` to resolve the split accurately. | |
158 | + // We can do this because we are in an async function context (Astro component script). | |
159 | + | |
160 | + try { | |
161 | + const { getGit } = await import("@/lib/git"); | |
162 | + const git = getGit(resolvedLocalPath); | |
163 | + | |
164 | + // Try to see if the full refParam is a ref | |
165 | + try { | |
166 | + await git.raw(["rev-parse", "--verify", refParam]); | |
167 | + // It is a valid ref! | |
168 | + currentBranch = refParam; | |
169 | + currentPath = ""; | |
170 | + } catch (e) { | |
171 | + // Not a full ref. Try to find the splitting point. | |
172 | + // Split by / and find the longest prefix that is a ref. | |
173 | + const parts = refParam.split("/"); | |
174 | + let found = false; | |
175 | + for (let i = parts.length - 1; i > 0; i--) { | |
176 | + const potentialBranch = parts.slice(0, i).join("/"); | |
177 | + try { | |
178 | + await git.raw(["rev-parse", "--verify", potentialBranch]); | |
179 | + currentBranch = potentialBranch; | |
180 | + currentPath = parts.slice(i).join("/"); | |
181 | + found = true; | |
182 | + break; | |
183 | + } catch {} | |
184 | + } | |
185 | + | |
186 | + if (!found) { | |
187 | + // If still nothing, fallback to first part (legacy behavior) or default branch? | |
188 | + // If we default to defaultBranch, we treat the whole thing as path. | |
189 | + // currentBranch = repoData.defaultBranch; | |
190 | + // currentPath = refParam; | |
191 | + // But existing legacy behavior was split[0]. Let's keep legacy if detection fails, | |
192 | + // OR default to the sophisticated split[0]. | |
193 | + currentBranch = parts[0]; | |
194 | + currentPath = parts.slice(1).join("/"); | |
195 | + } | |
196 | + } | |
197 | + } catch (err) { | |
198 | + // If git fails entirely, fallback | |
199 | + currentBranch = refParam.split("/")[0]; | |
200 | + currentPath = refParam.split("/").slice(1).join("/"); | |
201 | + } | |
109 | 202 | } |
110 | 203 | |
111 | 204 | let files: any[] = []; |
112 | 205 | |
▼src/pages/[owner]/[repo]/tree/[branch]/[...path].astro
+15-15
| @@ -14,6 +14,7 @@ import { | ||
14 | 14 | import { getDatabase, schema } from "@/db"; |
15 | 15 | import { eq, and, sql } from "drizzle-orm"; |
16 | 16 | import { listFiles, getLastCommit, getCommits, getBranches } from "@/lib/git"; |
17 | +import { resolveRepoPath } from "@/lib/git-storage"; | |
17 | 18 | import { canReadRepo } from "@/lib/permissions"; |
18 | 19 | import RepoHeader from "@/components/repo/RepoHeader.astro"; |
19 | 20 | import FileExplorer from "@/components/repo/FileExplorer.astro"; |
| @@ -58,12 +59,19 @@ const issueCountResult = await db | ||
58 | 59 | eq(schema.issues.repositoryId, repoData.id), |
59 | 60 | eq(schema.issues.state, "open"), |
60 | 61 | ), |
61 | - ) | |
62 | - ; | |
63 | - | |
62 | + ); | |
64 | 63 | const openIssueCount = |
65 | 64 | (issueCountResult as { count: number } | undefined)?.count || 0; |
66 | 65 | |
66 | +// Resolve disk path for cloud storage | |
67 | +let repoPath: string; | |
68 | +try { | |
69 | + repoPath = await resolveRepoPath(repoData.diskPath); | |
70 | +} catch (err) { | |
71 | + console.error("Failed to resolve repo path:", err); | |
72 | + return Astro.redirect("/404"); | |
73 | +} | |
74 | + | |
67 | 75 | // 2. Git Operations |
68 | 76 | const currentBranch = branch || repoData.defaultBranch; |
69 | 77 | const currentPath = path || ""; |
| @@ -91,22 +99,14 @@ function timeAgo(date: Date | string | number) { | ||
91 | 99 | |
92 | 100 | try { |
93 | 101 | // Get files |
94 | - const gitFiles = await listFiles( | |
95 | - repoData.diskPath, | |
96 | - currentBranch, | |
97 | - currentPath, | |
98 | - ); | |
102 | + const gitFiles = await listFiles(repoPath, currentBranch, currentPath); | |
99 | 103 | |
100 | 104 | // Map to UI format with commits |
101 | 105 | files = await Promise.all( |
102 | 106 | gitFiles.map(async (f) => { |
103 | 107 | // For subdirectories, we need to pass the full path to getLastCommit |
104 | 108 | // listFiles returns 'path' which is the full relative path |
105 | - const commit = await getLastCommit( | |
106 | - repoData.diskPath, | |
107 | - currentBranch, | |
108 | - f.path, | |
109 | - ); | |
109 | + const commit = await getLastCommit(repoPath, currentBranch, f.path); | |
110 | 110 | |
111 | 111 | const lastCommit = commit |
112 | 112 | ? { |
| @@ -132,7 +132,7 @@ try { | ||
132 | 132 | }); |
133 | 133 | |
134 | 134 | // Get latest commit for the directory |
135 | - const commits = await getCommits(repoData.diskPath, { | |
135 | + const commits = await getCommits(repoPath, { | |
136 | 136 | limit: 1, |
137 | 137 | ref: currentBranch, |
138 | 138 | path: currentPath, |
| @@ -167,7 +167,7 @@ const repo = { | ||
167 | 167 | // Fetch all branches |
168 | 168 | let branches: string[] = [repoData.defaultBranch]; |
169 | 169 | try { |
170 | - const branchInfos = await getBranches(repoData.diskPath); | |
170 | + const branchInfos = await getBranches(repoPath); | |
171 | 171 | branches = branchInfos.map((b) => b.name); |
172 | 172 | // Ensure default branch is first |
173 | 173 | branches = [ |
174 | 174 | |
▼src/pages/api/cron/gc.ts
+3-1
| @@ -1,6 +1,7 @@ | ||
1 | 1 | import { getDatabase, schema } from "@/db"; |
2 | 2 | import type { NodePgDatabase } from "drizzle-orm/node-postgres"; |
3 | 3 | import { logger } from "@/lib/logger"; |
4 | +import { resolveRepoPath } from "@/lib/git-storage"; | |
4 | 5 | import type { APIRoute } from "astro"; |
5 | 6 | import { spawn } from "child_process"; |
6 | 7 | // removed |
| @@ -27,8 +28,9 @@ export const GET: APIRoute = async ({ request }) => { | ||
27 | 28 | try { |
28 | 29 | logger.debug({ owner: repo.ownerId, name: repo.name }, "Processing repository"); |
29 | 30 | // Run git gc --auto --quiet |
31 | + const repoPath = await resolveRepoPath(repo.diskPath); | |
30 | 32 | const child = spawn("git", ["gc", "--auto", "--quiet"], { |
31 | - cwd: repo.diskPath, | |
33 | + cwd: repoPath, | |
32 | 34 | stdio: "ignore", |
33 | 35 | }); |
34 | 36 | |
35 | 37 | |
▼src/pages/api/repos/[owner]/[repo]/branches/[branch].ts
+3-1
| @@ -1,6 +1,7 @@ | ||
1 | 1 | import { getDatabase, schema } from "@/db"; |
2 | 2 | import type { NodePgDatabase } from "drizzle-orm/node-postgres"; |
3 | 3 | import { deleteBranch } from "@/lib/git"; |
4 | +import { resolveRepoPath } from "@/lib/git-storage"; | |
4 | 5 | import { canWriteRepo } from "@/lib/permissions"; |
5 | 6 | import type { APIRoute } from "astro"; |
6 | 7 | import { and, eq } from "drizzle-orm"; |
| @@ -55,7 +56,8 @@ export const DELETE: APIRoute = withErrorHandler(async ({ params, locals }) => { | ||
55 | 56 | } |
56 | 57 | |
57 | 58 | // Delete branch |
58 | - await deleteBranch(repo.diskPath, branch); | |
59 | + const repoPath = await resolveRepoPath(repo.diskPath); | |
60 | + await deleteBranch(repoPath, branch); | |
59 | 61 | |
60 | 62 | logger.info({ userId: user.id, repoId: repo.id, branch }, "Branch deleted"); |
61 | 63 | |
62 | 64 | |
▼src/pages/api/repos/[owner]/[repo]/branches/index.ts
+3-1
| @@ -1,6 +1,7 @@ | ||
1 | 1 | import { getDatabase, schema } from "@/db"; |
2 | 2 | import type { NodePgDatabase } from "drizzle-orm/node-postgres"; |
3 | 3 | import { createBranch, getBranches } from "@/lib/git"; |
4 | +import { resolveRepoPath } from "@/lib/git-storage"; | |
4 | 5 | import { canReadRepo, canWriteRepo } from "@/lib/permissions"; |
5 | 6 | import type { APIRoute } from "astro"; |
6 | 7 | import { and, eq } from "drizzle-orm"; |
| @@ -46,7 +47,8 @@ export const GET: APIRoute = withErrorHandler(async ({ params, locals }) => { | ||
46 | 47 | } |
47 | 48 | |
48 | 49 | // Get branches |
49 | - const branches = await getBranches(repo.diskPath); | |
50 | + const repoPath = await resolveRepoPath(repo.diskPath); | |
51 | + const branches = await getBranches(repoPath); | |
50 | 52 | return success(branches); |
51 | 53 | }); |
52 | 54 | |
53 | 55 | |
▼src/pages/api/repos/[owner]/[repo]/compare/index.ts
+4-2
| @@ -1,6 +1,7 @@ | ||
1 | 1 | import { getDatabase, schema } from "@/db"; |
2 | 2 | import type { NodePgDatabase } from "drizzle-orm/node-postgres"; |
3 | 3 | import { compareBranches, getMergeBase } from "@/lib/git"; |
4 | +import { resolveRepoPath } from "@/lib/git-storage"; | |
4 | 5 | import { canReadRepo } from "@/lib/permissions"; |
5 | 6 | import type { APIRoute } from "astro"; |
6 | 7 | import { and, eq } from "drizzle-orm"; |
| @@ -48,8 +49,9 @@ export const GET: APIRoute = withErrorHandler(async ({ params, request, locals } | ||
48 | 49 | } |
49 | 50 | |
50 | 51 | // Compare branches |
51 | - const { commits, diffs } = await compareBranches(repo.diskPath, base, head); | |
52 | - const mergeBase = await getMergeBase(repo.diskPath, base, head); | |
52 | + const repoPath = await resolveRepoPath(repo.diskPath); | |
53 | + const { commits, diffs } = await compareBranches(repoPath, base, head); | |
54 | + const mergeBase = await getMergeBase(repoPath, base, head); | |
53 | 55 | |
54 | 56 | return success({ commits, diffs, mergeBase }); |
55 | 57 | }); |
56 | 58 | |
▼src/pages/api/repos/[owner]/[repo]/git/push.ts
+31-5
| @@ -17,7 +17,8 @@ import { | ||
17 | 17 | acquireRepo, |
18 | 18 | releaseRepo, |
19 | 19 | getDiskPath, |
20 | - parseStoragePath | |
20 | + parseStoragePath, | |
21 | + ensureRepoInitialized | |
21 | 22 | } from "@/lib/git-storage"; |
22 | 23 | import { spawn, execSync } from "child_process"; |
23 | 24 | import { existsSync, mkdirSync, writeFileSync, unlinkSync } from "fs"; |
| @@ -80,19 +81,39 @@ export const POST: APIRoute = withErrorHandler(async ({ request, params }) => { | ||
80 | 81 | return badRequest("Empty bundle"); |
81 | 82 | } |
82 | 83 | |
83 | - // Get local path to the repository | |
84 | + // Get local path to the repository (with lazy initialization) | |
84 | 85 | let repoPath: string; |
85 | 86 | |
86 | 87 | if (await isCloudStorage()) { |
87 | 88 | const parsed = parseStoragePath(repository.diskPath); |
88 | 89 | if (parsed) { |
89 | - repoPath = await acquireRepo(parsed.owner, parsed.repoName); | |
90 | + // Ensure repo is initialized before accepting push (lazy init) | |
91 | + repoPath = await ensureRepoInitialized( | |
92 | + parsed.owner, | |
93 | + parsed.repoName, | |
94 | + { defaultBranch: repository.defaultBranch } | |
95 | + ); | |
90 | 96 | } else { |
91 | 97 | // Fallback to standard path |
92 | - repoPath = await acquireRepo(owner, repoName); | |
98 | + repoPath = await ensureRepoInitialized( | |
99 | + owner, | |
100 | + repoName, | |
101 | + { defaultBranch: repository.defaultBranch } | |
102 | + ); | |
93 | 103 | } |
94 | 104 | } else { |
95 | - repoPath = repository.diskPath; | |
105 | + // Local storage - ensure repo directory exists and is initialized | |
106 | + const diskPath = repository.diskPath; | |
107 | + if (!existsSync(join(diskPath, 'HEAD'))) { | |
108 | + // Repo not initialized, initialize it | |
109 | + repoPath = await ensureRepoInitialized( | |
110 | + owner, | |
111 | + repoName, | |
112 | + { defaultBranch: repository.defaultBranch } | |
113 | + ); | |
114 | + } else { | |
115 | + repoPath = diskPath; | |
116 | + } | |
96 | 117 | } |
97 | 118 | |
98 | 119 | // Ensure repo directory exists |
| @@ -173,9 +194,14 @@ export const POST: APIRoute = withErrorHandler(async ({ request, params }) => { | ||
173 | 194 | |
174 | 195 | // If using cloud storage, sync back |
175 | 196 | if (await isCloudStorage()) { |
197 | + logger.info({ repoPath, diskPath: repository.diskPath }, "Syncing to cloud storage after bundle push"); | |
176 | 198 | const parsed = parseStoragePath(repository.diskPath); |
177 | 199 | if (parsed) { |
200 | + logger.info({ parsed }, "Releasing repo with modifications"); | |
178 | 201 | await releaseRepo(parsed.owner, parsed.repoName, true); |
202 | + logger.info("Repo released and synced to storage"); | |
203 | + } else { | |
204 | + logger.warn({ diskPath: repository.diskPath }, "Could not parse storage path for sync"); | |
179 | 205 | } |
180 | 206 | } |
181 | 207 | |
182 | 208 | |
▼src/pages/api/repos/[owner]/[repo]/pulls/[number]/merge.ts
+3-1
| @@ -1,6 +1,7 @@ | ||
1 | 1 | import { getDatabase, schema } from "@/db"; |
2 | 2 | import type { NodePgDatabase } from "drizzle-orm/node-postgres"; |
3 | 3 | import { mergeBranch } from "@/lib/git"; |
4 | +import { resolveRepoPath } from "@/lib/git-storage"; | |
4 | 5 | import { canWriteRepo } from "@/lib/permissions"; |
5 | 6 | import type { APIRoute } from "astro"; |
6 | 7 | import { and, eq } from "drizzle-orm"; |
| @@ -66,7 +67,8 @@ export const POST: APIRoute = withErrorHandler(async ({ params, locals }) => { | ||
66 | 67 | } |
67 | 68 | |
68 | 69 | // Merge branch |
69 | - const result = await mergeBranch(repo.diskPath, pr.baseBranch, pr.headBranch); | |
70 | + const repoPath = await resolveRepoPath(repo.diskPath); | |
71 | + const result = await mergeBranch(repoPath, pr.baseBranch, pr.headBranch); | |
70 | 72 | |
71 | 73 | if (result.success) { |
72 | 74 | // Update PR state with all merge fields |
73 | 75 | |
▼src/pages/api/repos/[owner]/[repo]/pulls/index.ts
+1-1
| @@ -62,7 +62,7 @@ export const POST: APIRoute = withErrorHandler(async ({ params, request, locals | ||
62 | 62 | return badRequest("Base and head branches must be different"); |
63 | 63 | } |
64 | 64 | |
65 | - const repoPath = repo.diskPath; | |
65 | + const repoPath = await resolveRepoPath(repo.diskPath); | |
66 | 66 | |
67 | 67 | // Verify branches exist and get SHAs |
68 | 68 | // In a real implementation we should verify they exist using git.branch() or similar |
69 | 69 | |
▼src/pages/api/repos/[owner]/[repo]/queue/join.ts
+72-0
| @@ -0,0 +1,72 @@ | ||
1 | +import { getDatabase, schema } from "@/db"; | |
2 | +import { error, success, unauthorized } from "@/lib/api"; | |
3 | +import { withErrorHandler } from "@/lib/errors"; | |
4 | +import { queueWorker } from "@/lib/queue-worker"; | |
5 | +import { and, eq } from "drizzle-orm"; | |
6 | +import type { NodePgDatabase } from "drizzle-orm/node-postgres"; | |
7 | +import type { APIContext } from "astro"; | |
8 | +import { v4 as uuidv4 } from "uuid"; | |
9 | + | |
10 | +export const POST = withErrorHandler(async ({ params, request, locals }: APIContext) => { | |
11 | + const user = locals.user; | |
12 | + if (!user) { | |
13 | + return unauthorized(); | |
14 | + } | |
15 | + | |
16 | + const { owner, repo } = params; | |
17 | + const { pullRequestId } = await request.json(); | |
18 | + | |
19 | + if (!pullRequestId) { | |
20 | + return error("BAD_REQUEST", "Pull Request ID is required", 400); | |
21 | + } | |
22 | + | |
23 | + const db = getDatabase() as NodePgDatabase<typeof schema>; | |
24 | + | |
25 | + // 1. Verify Repository | |
26 | + const repository = await db.query.repositories.findFirst({ | |
27 | + where: and(eq(schema.repositories.name, repo!), eq(schema.repositories.ownerId, user.id)), // basic check, refine for orgs | |
28 | + with: { owner: true } | |
29 | + }); | |
30 | + | |
31 | + if (!repository || repository.owner.username !== owner) { | |
32 | + const repoByOwner = await db.query.repositories.findFirst({ | |
33 | + where: eq(schema.repositories.name, repo!), | |
34 | + with: { owner: true } | |
35 | + }); | |
36 | + if (!repoByOwner || repoByOwner.owner.username !== owner) { | |
37 | + return error("NOT_FOUND", "Repository not found", 404); | |
38 | + } | |
39 | + // Check basic permissions here... | |
40 | + } | |
41 | + | |
42 | + // 2. Add to Queue | |
43 | + const queueItem = { | |
44 | + id: uuidv4(), | |
45 | + repositoryId: repository!.id, // Need to fetch correct repo ID if permission check passes | |
46 | + pullRequestId, | |
47 | + status: "queued", | |
48 | + attemptCount: 0, | |
49 | + queuedAt: new Date(), | |
50 | + }; | |
51 | + | |
52 | + // Fix repo id fetching above or assume owner/repo is correct: | |
53 | + const targetRepo = await db.query.repositories.findFirst({ | |
54 | + where: and( | |
55 | + eq(schema.repositories.name, repo!), | |
56 | + eq(schema.repositories.ownerId, (await db.query.users.findFirst({ where: eq(schema.users.username, owner!) }))!.id) | |
57 | + ) | |
58 | + }); | |
59 | + | |
60 | + if (!targetRepo) return error("NOT_FOUND", "Repo not found", 404); | |
61 | + | |
62 | + await db.insert(schema.mergeQueueItems).values({ | |
63 | + ...queueItem, | |
64 | + repositoryId: targetRepo.id | |
65 | + }); | |
66 | + | |
67 | + // 3. Trigger Worker (Async) | |
68 | + // In production, this might be a cron or event queue. For now, we trigger immediately. | |
69 | + queueWorker.processQueue(targetRepo.id).catch(console.error); | |
70 | + | |
71 | + return success({ message: "Added to merge queue", queueId: queueItem.id }); | |
72 | +}); | |
0 | 73 | |
▼src/pages/api/repos/[owner]/[repo]/security/scan.ts
+3-1
| @@ -2,6 +2,7 @@ import { getDatabase, schema } from "@/db"; | ||
2 | 2 | import type { NodePgDatabase } from "drizzle-orm/node-postgres"; |
3 | 3 | import { canWriteRepo } from "@/lib/permissions"; |
4 | 4 | import { runSecurityScan } from "@/lib/security"; |
5 | +import { resolveRepoPath } from "@/lib/git-storage"; | |
5 | 6 | import { generateId } from "@/lib/utils"; |
6 | 7 | import type { APIRoute } from "astro"; |
7 | 8 | import { and, eq } from "drizzle-orm"; |
| @@ -50,7 +51,8 @@ export const POST: APIRoute = withErrorHandler(async ({ params, locals }) => { | ||
50 | 51 | }); |
51 | 52 | |
52 | 53 | // Start scan asynchronously |
53 | - runSecurityScan(repo.diskPath, scanId, repo.id).catch(err => { | |
54 | + const repoPath = await resolveRepoPath(repo.diskPath); | |
55 | + runSecurityScan(repoPath, scanId, repo.id).catch(err => { | |
54 | 56 | logger.error({ err, repoId: repo.id, scanId }, "Background scan failed to start properly"); |
55 | 57 | }); |
56 | 58 | |
57 | 59 | |
▼src/pages/api/repos/[repoId]/commit.ts
+3-1
| @@ -4,6 +4,7 @@ import type { NodePgDatabase } from "drizzle-orm/node-postgres"; | ||
4 | 4 | import { getDatabase, schema } from "@/db"; |
5 | 5 | import { eq } from "drizzle-orm"; |
6 | 6 | import { commitFile } from "@/lib/git"; |
7 | +import { resolveRepoPath } from "@/lib/git-storage"; | |
7 | 8 | import { canWriteRepo } from "@/lib/permissions"; |
8 | 9 | import { analyzeRepository } from "@/lib/analysis"; |
9 | 10 | |
| @@ -40,8 +41,9 @@ export const POST: APIRoute = withErrorHandler(async ({ params, request, locals | ||
40 | 41 | if (!hasAccess) return forbidden(); |
41 | 42 | |
42 | 43 | // Commit |
44 | + const repoPath = await resolveRepoPath(repo.diskPath); | |
43 | 45 | const commitSha = await commitFile( |
44 | - repo.diskPath, | |
46 | + repoPath, | |
45 | 47 | branch, |
46 | 48 | path, |
47 | 49 | content, |
48 | 50 | |
▼src/pages/api/repos/index.ts
+10-10
| @@ -245,33 +245,33 @@ export const POST: APIRoute = withErrorHandler(async ({ request }) => { | ||
245 | 245 | updatedAt: timestamp, |
246 | 246 | }); |
247 | 247 | |
248 | - // Initialize git repository | |
248 | + // Initialize git repository immediately (fast, ~100ms) | |
249 | + // Upload to S3 happens asynchronously to not block response | |
249 | 250 | try { |
250 | 251 | // Get local path for git operations (temp path for cloud storage, direct path for local) |
251 | 252 | const localGitPath = await initRepoInStorage(user.username, slug); |
252 | 253 | |
253 | 254 | await initRepository(localGitPath, { |
254 | 255 | defaultBranch, |
255 | - readme, | |
256 | + readme: false, // No README on creation to keep it fast | |
256 | 257 | gitignoreTemplate, |
257 | 258 | licenseType, |
258 | 259 | repoName: name, |
259 | 260 | ownerName: user.displayName || user.username, |
260 | 261 | }); |
261 | 262 | |
262 | - // If using cloud storage, upload the initialized repo | |
263 | + // If using cloud storage, upload asynchronously (don't wait) | |
263 | 264 | const isCloud = await isCloudStorage(); |
264 | - logger.info({ isCloud, storageType: import.meta.env.STORAGE_TYPE }, 'Checking cloud storage strict'); | |
265 | 265 | |
266 | 266 | if (isCloud) { |
267 | - logger.info('Starting cloud storage sync...'); | |
268 | - // Fire-and-forget to avoid blocking the response | |
267 | + logger.info('Uploading to cloud storage (async)...'); | |
268 | + // Fire-and-forget async upload | |
269 | 269 | finalizeRepoInit(user.username, slug) |
270 | - .then(() => logger.info({ repoId, diskPath }, 'Repository synced to cloud storage')) | |
271 | - .catch((err) => logger.error({ err, repoId, diskPath }, 'Background cloud sync failed')); | |
272 | - } else { | |
273 | - logger.info('Skipping cloud sync (isCloudStorage=false)'); | |
270 | + .then(() => logger.info({ repoId, diskPath }, 'Repository uploaded to S3')) | |
271 | + .catch((err) => logger.error({ err, repoId }, 'Background S3 upload failed')); | |
274 | 272 | } |
273 | + | |
274 | + logger.info({ repoId, diskPath }, 'Repository initialized and ready (S3 upload in progress if cloud)'); | |
275 | 275 | } catch (error) { |
276 | 276 | // Rollback database entry if git init fails |
277 | 277 | await db.delete(repositories).where(eq(repositories.id, repoId)); |
278 | 278 | |
▼src/pages/api/stacks/index.ts
+30-2
| @@ -15,7 +15,9 @@ import { z } from "zod"; | ||
15 | 15 | import crypto from "crypto"; |
16 | 16 | |
17 | 17 | const createStackSchema = z.object({ |
18 | - repositoryId: z.string(), | |
18 | + repositoryId: z.string().optional(), | |
19 | + owner: z.string().optional(), | |
20 | + repo: z.string().optional(), | |
19 | 21 | baseBranch: z.string().default("main"), |
20 | 22 | name: z.string().optional(), |
21 | 23 | branches: z.array(z.object({ |
| @@ -24,6 +26,8 @@ const createStackSchema = z.object({ | ||
24 | 26 | description: z.string().optional(), |
25 | 27 | parentBranch: z.string().optional(), |
26 | 28 | })), |
29 | +}).refine(data => data.repositoryId || (data.owner && data.repo), { | |
30 | + message: "Either repositoryId or owner and repo must be provided", | |
27 | 31 | }); |
28 | 32 | |
29 | 33 | type CreateStackInput = z.infer<typeof createStackSchema>; |
| @@ -86,11 +90,35 @@ export const POST: APIRoute = withErrorHandler(async ({ request }) => { | ||
86 | 90 | const parsed = await parseBody(request, createStackSchema); |
87 | 91 | if ("error" in parsed) return parsed.error; |
88 | 92 | |
89 | - const { repositoryId, name, branches } = parsed.data; | |
93 | + const { name, branches } = parsed.data; | |
90 | 94 | const baseBranch = parsed.data.baseBranch || "main"; |
95 | + let repositoryId = parsed.data.repositoryId; | |
91 | 96 | |
92 | 97 | const db = getDatabase() as NodePgDatabase<typeof schema>; |
93 | 98 | |
99 | + // Find repo by owner/name if only provided | |
100 | + if (!repositoryId && parsed.data.owner && parsed.data.repo) { | |
101 | + const ownerUser = await db.query.users.findFirst({ | |
102 | + where: eq(schema.users.username, parsed.data.owner), | |
103 | + }); | |
104 | + | |
105 | + if (ownerUser) { | |
106 | + const repo = await db.query.repositories.findFirst({ | |
107 | + where: and( | |
108 | + eq(schema.repositories.ownerId, ownerUser.id), | |
109 | + eq(schema.repositories.name, parsed.data.repo) | |
110 | + ), | |
111 | + }); | |
112 | + if (repo) { | |
113 | + repositoryId = repo.id; | |
114 | + } | |
115 | + } | |
116 | + } | |
117 | + | |
118 | + if (!repositoryId) { | |
119 | + throw Errors.notFound("Repository not found"); | |
120 | + } | |
121 | + | |
94 | 122 | // Verify repository exists and user has access |
95 | 123 | const repo = await db.query.repositories.findFirst({ |
96 | 124 | where: eq(schema.repositories.id, repositoryId), |
97 | 125 | |
▼src/pages/api/stacks/user.ts
+85-0
| @@ -0,0 +1,85 @@ | ||
1 | +import { getDatabase, schema } from "@/db"; | |
2 | +import { type APIContext } from "astro"; | |
3 | +import { and, desc, eq, inArray } from "drizzle-orm"; | |
4 | +import { success, error, unauthorized } from "@/lib/api"; | |
5 | +import { logger } from "@/lib/logger"; | |
6 | +import { withErrorHandler } from "@/lib/errors"; | |
7 | + | |
8 | +export const GET = withErrorHandler(async ({ locals }: APIContext) => { | |
9 | + const user = locals.user; | |
10 | + if (!user) { | |
11 | + return unauthorized(); | |
12 | + } | |
13 | + | |
14 | + const db = getDatabase(); | |
15 | + | |
16 | + // 1. Find all PRs created by the user | |
17 | + const userPrs = await db.query.pullRequests.findMany({ | |
18 | + where: eq(schema.pullRequests.authorId, user.id), | |
19 | + columns: { id: true } | |
20 | + }); | |
21 | + | |
22 | + if (userPrs.length === 0) { | |
23 | + return success([]); | |
24 | + } | |
25 | + | |
26 | + const prIds = userPrs.map(pr => pr.id); | |
27 | + | |
28 | + // 2. Find which stacks these PRs belong to | |
29 | + // We get unique stackIds from stack entries | |
30 | + const stackEntries = await db.query.prStackEntries.findMany({ | |
31 | + where: inArray(schema.prStackEntries.pullRequestId, prIds), | |
32 | + columns: { stackId: true } | |
33 | + }); | |
34 | + | |
35 | + const uniqueStackIds = [...new Set(stackEntries.map(e => e.stackId))]; | |
36 | + | |
37 | + if (uniqueStackIds.length === 0) { | |
38 | + return success([]); | |
39 | + } | |
40 | + | |
41 | + // 3. Fetch full stack details + all entries (to show full context of the stack) | |
42 | + // We need to fetch the stack info AND all its entries (even PRs not owned by current user, if that ever happens) | |
43 | + const stacks = await db.query.prStacks.findMany({ | |
44 | + where: inArray(schema.prStacks.id, uniqueStackIds), | |
45 | + orderBy: [desc(schema.prStacks.updatedAt)], | |
46 | + with: { | |
47 | + repository: { | |
48 | + with: { | |
49 | + owner: true | |
50 | + } | |
51 | + }, | |
52 | + entries: { | |
53 | + orderBy: (entries, { asc }) => [asc(entries.stackOrder)], | |
54 | + with: { | |
55 | + pullRequest: true | |
56 | + } | |
57 | + } | |
58 | + } | |
59 | + }); | |
60 | + | |
61 | + // 4. Format response for UI | |
62 | + const formattedStacks = stacks.map(stack => { | |
63 | + return { | |
64 | + id: stack.id, | |
65 | + name: stack.name || `Stack-${stack.id.substring(0, 6)}`, // Fallback name | |
66 | + baseBranch: stack.baseBranch, | |
67 | + status: stack.status, | |
68 | + repoName: stack.repository.name, | |
69 | + repoOwner: stack.repository.owner.username, | |
70 | + updatedAt: stack.updatedAt, | |
71 | + prs: stack.entries.map(entry => ({ | |
72 | + id: entry.pullRequest.id, | |
73 | + number: entry.pullRequest.number, | |
74 | + title: entry.pullRequest.title, | |
75 | + status: entry.pullRequest.state, // 'open', 'closed', 'merged' | |
76 | + url: `/${stack.repository.owner.username}/${stack.repository.name}/pulls/${entry.pullRequest.number}`, | |
77 | + position: entry.stackOrder, | |
78 | + isMerged: entry.pullRequest.state === 'merged', | |
79 | + isClosed: entry.pullRequest.state === 'closed', | |
80 | + })) | |
81 | + }; | |
82 | + }); | |
83 | + | |
84 | + return success(formattedStacks); | |
85 | +}); | |
0 | 86 | |
▼src/pages/dashboard.astro
+244-343
| @@ -2,6 +2,19 @@ | ||
2 | 2 | import { getDatabase, schema } from "@/db"; |
3 | 3 | import BaseLayout from "@/layouts/BaseLayout.astro"; |
4 | 4 | import { desc, eq } from "drizzle-orm"; |
5 | +// Import Shadcn UI Components (using path aliases or relative paths) | |
6 | +// Assuming components are in @/components/ui or src/components/ui | |
7 | +import { | |
8 | + Card, | |
9 | + CardContent, | |
10 | + CardDescription, | |
11 | + CardFooter, | |
12 | + CardHeader, | |
13 | + CardTitle, | |
14 | +} from "@/components/ui/card"; | |
15 | +import { Button } from "@/components/ui/button"; | |
16 | +import { UserAvatar } from "@/components/dashboard/UserAvatar"; | |
17 | +import { Badge } from "@/components/ui/badge"; | |
5 | 18 | |
6 | 19 | const user = Astro.locals.user; |
7 | 20 | if (!user) { |
| @@ -10,7 +23,6 @@ if (!user) { | ||
10 | 23 | |
11 | 24 | const db = getDatabase(); |
12 | 25 | |
13 | -// Fetch user's repositories | |
14 | 26 | // Fetch user's repositories |
15 | 27 | const repos = await db.query.repositories.findMany({ |
16 | 28 | where: eq(schema.repositories.ownerId, user.id), |
| @@ -33,310 +45,163 @@ function timeAgo(date: string | Date) { | ||
33 | 45 | --- |
34 | 46 | |
35 | 47 | <BaseLayout title="Dashboard - OpenCodeHub"> |
36 | - <div class="container py-8"> | |
37 | - <div class="flex flex-col lg:flex-row gap-8"> | |
38 | - <!-- Sidebar --> | |
39 | - <aside class="w-full lg:w-72 space-y-6"> | |
40 | - <!-- User Card --> | |
41 | - <div class="relative"> | |
42 | - <div | |
43 | - class="absolute -inset-[1px] bg-gradient-to-b from-cyan-500/30 to-transparent rounded-xl opacity-50" | |
44 | - > | |
45 | - </div> | |
46 | - <div | |
47 | - class="relative rounded-xl border border-white/10 bg-[#0d1117]/80 backdrop-blur-sm p-4" | |
48 | - > | |
49 | - <div class="flex items-center gap-4"> | |
50 | - { | |
51 | - user.avatarUrl ? ( | |
52 | - <img | |
53 | - src={user.avatarUrl} | |
54 | - alt={user.username} | |
55 | - class="h-14 w-14 rounded-full object-cover ring-2 ring-cyan-500/30" | |
56 | - /> | |
57 | - ) : ( | |
58 | - <div class="h-14 w-14 rounded-full bg-gradient-to-br from-cyan-400 to-blue-600 flex items-center justify-center text-xl font-bold text-white ring-2 ring-cyan-500/30"> | |
59 | - {user.username[0].toUpperCase()} | |
60 | - </div> | |
61 | - ) | |
62 | - } | |
63 | - <div class="overflow-hidden"> | |
64 | - <h2 class="font-semibold text-white truncate"> | |
65 | - {user.displayName || user.username} | |
66 | - </h2> | |
67 | - <p class="text-sm text-gray-500 truncate"> | |
68 | - @{user.username} | |
69 | - </p> | |
70 | - </div> | |
71 | - </div> | |
72 | - | |
73 | - <!-- Quick Stats --> | |
74 | - <div | |
75 | - class="grid grid-cols-3 gap-2 mt-4 pt-4 border-t border-white/5" | |
76 | - > | |
77 | - <div class="text-center"> | |
78 | - <div class="text-lg font-bold text-white">{repos.length}</div> | |
79 | - <div class="text-xs text-gray-500">Repos</div> | |
80 | - </div> | |
81 | - <div class="text-center"> | |
82 | - <div class="text-lg font-bold text-yellow-400"> | |
83 | - {totalStars} | |
84 | - </div> | |
85 | - <div class="text-xs text-gray-500">Stars</div> | |
86 | - </div> | |
87 | - <div class="text-center"> | |
88 | - <div class="text-lg font-bold text-purple-400"> | |
89 | - {totalForks} | |
90 | - </div> | |
91 | - <div class="text-xs text-gray-500">Forks</div> | |
92 | - </div> | |
93 | - </div> | |
94 | - </div> | |
48 | + <div class="container py-8 max-w-7xl mx-auto space-y-8"> | |
49 | + <!-- Welcome Header --> | |
50 | + <div | |
51 | + class="flex flex-col md:flex-row items-start md:items-center justify-between gap-4" | |
52 | + > | |
53 | + <div class="flex items-center gap-4"> | |
54 | + <UserAvatar | |
55 | + user={user} | |
56 | + className="h-16 w-16 border-2 border-white/10" | |
57 | + client:load | |
58 | + /> | |
59 | + <div> | |
60 | + <h1 class="text-3xl font-bold text-white tracking-tight"> | |
61 | + Welcome back, {user.displayName || user.username} | |
62 | + </h1> | |
63 | + <p class="text-gray-400"> | |
64 | + Manage your repositories and development workflow. | |
65 | + </p> | |
95 | 66 | </div> |
96 | - | |
97 | - <!-- Quick Links --> | |
98 | - <div class="relative"> | |
99 | - <div | |
100 | - class="absolute -inset-[1px] bg-gradient-to-b from-purple-500/20 to-transparent rounded-xl opacity-50" | |
67 | + </div> | |
68 | + <div class="flex items-center gap-3"> | |
69 | + <a href="/stacks"> | |
70 | + <Button | |
71 | + variant="outline" | |
72 | + className="border-white/10 text-gray-300 hover:text-white hover:bg-white/5" | |
101 | 73 | > |
102 | - </div> | |
103 | - <div | |
104 | - class="relative rounded-xl border border-white/10 bg-[#0d1117]/80 backdrop-blur-sm p-4" | |
105 | - > | |
106 | - <h3 | |
107 | - class="font-semibold text-sm text-white mb-3 flex items-center gap-2" | |
108 | - > | |
109 | - <svg | |
110 | - class="h-4 w-4 text-purple-400" | |
111 | - fill="none" | |
112 | - stroke="currentColor" | |
113 | - viewBox="0 0 24 24" | |
114 | - > | |
115 | - <path | |
116 | - stroke-linecap="round" | |
117 | - stroke-linejoin="round" | |
118 | - stroke-width="2" | |
119 | - d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" | |
120 | - ></path> | |
121 | - </svg> | |
122 | - Your Repositories | |
123 | - </h3> | |
124 | - <nav class="space-y-1 max-h-48 overflow-y-auto custom-scrollbar"> | |
125 | - { | |
126 | - repos.slice(0, 8).map((repo) => ( | |
127 | - <a | |
128 | - href={`/${user.username}/${repo.name}`} | |
129 | - class="flex items-center gap-2 px-3 py-2 text-sm text-gray-400 hover:text-white hover:bg-white/5 rounded-lg transition-colors" | |
130 | - > | |
131 | - <svg | |
132 | - class="h-4 w-4 text-gray-500" | |
133 | - fill="none" | |
134 | - stroke="currentColor" | |
135 | - viewBox="0 0 24 24" | |
136 | - > | |
137 | - <path | |
138 | - stroke-linecap="round" | |
139 | - stroke-linejoin="round" | |
140 | - stroke-width="2" | |
141 | - d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" | |
142 | - /> | |
143 | - </svg> | |
144 | - <span class="truncate">{repo.name}</span> | |
145 | - </a> | |
146 | - )) | |
147 | - } | |
148 | - </nav> | |
149 | - <a | |
150 | - href="/new" | |
151 | - class="flex items-center gap-2 px-3 py-2 mt-2 text-sm font-medium text-cyan-400 hover:bg-cyan-500/10 rounded-lg transition-colors" | |
74 | + <svg | |
75 | + class="mr-2 h-4 w-4" | |
76 | + fill="none" | |
77 | + stroke="currentColor" | |
78 | + viewBox="0 0 24 24" | |
79 | + ><path | |
80 | + stroke-linecap="round" | |
81 | + stroke-linejoin="round" | |
82 | + stroke-width="2" | |
83 | + d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" | |
84 | + ></path></svg | |
152 | 85 | > |
153 | - <svg | |
154 | - class="h-4 w-4" | |
155 | - fill="none" | |
156 | - stroke="currentColor" | |
157 | - viewBox="0 0 24 24" | |
158 | - > | |
159 | - <path | |
160 | - stroke-linecap="round" | |
161 | - stroke-linejoin="round" | |
162 | - stroke-width="2" | |
163 | - d="M12 4v16m8-8H4"></path> | |
164 | - </svg> | |
165 | - New Repository | |
166 | - </a> | |
167 | - </div> | |
168 | - </div> | |
169 | - </aside> | |
170 | - | |
171 | - <!-- Main Content --> | |
172 | - <main class="flex-1 space-y-8"> | |
173 | - <!-- Header --> | |
174 | - <div class="flex items-center justify-between"> | |
175 | - <div> | |
176 | - <h1 class="text-2xl font-bold text-white">Dashboard</h1> | |
177 | - <p class="text-gray-500 text-sm mt-1"> | |
178 | - Welcome back, {user.displayName || user.username} | |
179 | - </p> | |
180 | - </div> | |
181 | - <a | |
182 | - href="/new" | |
183 | - class="inline-flex items-center gap-2 px-5 py-2.5 rounded-lg bg-gradient-to-r from-green-500 to-emerald-600 text-sm font-medium text-white shadow-lg shadow-green-500/25 hover:shadow-green-500/40 transition-all" | |
86 | + View Stacks | |
87 | + </Button> | |
88 | + </a> | |
89 | + <a href="/new"> | |
90 | + <Button | |
91 | + className="bg-gradient-to-r from-green-500 to-emerald-600 hover:from-green-600 hover:to-emerald-700 text-white border-0 shadow-lg shadow-green-500/20" | |
184 | 92 | > |
185 | 93 | <svg |
186 | - class="h-4 w-4" | |
94 | + class="mr-2 h-4 w-4" | |
187 | 95 | fill="none" |
188 | 96 | stroke="currentColor" |
189 | 97 | viewBox="0 0 24 24" |
190 | - > | |
191 | - <path | |
98 | + ><path | |
192 | 99 | stroke-linecap="round" |
193 | 100 | stroke-linejoin="round" |
194 | 101 | stroke-width="2" |
195 | - d="M12 4v16m8-8H4"></path> | |
196 | - </svg> | |
102 | + d="M12 4v16m8-8H4"></path></svg | |
103 | + > | |
197 | 104 | New Repository |
198 | - </a> | |
199 | - </div> | |
105 | + </Button> | |
106 | + </a> | |
107 | + </div> | |
108 | + </div> | |
200 | 109 | |
201 | - <!-- Activity Feed --> | |
202 | - <div class="relative"> | |
203 | - <div | |
204 | - class="absolute -inset-[1px] bg-gradient-to-r from-orange-500/20 via-transparent to-pink-500/20 rounded-xl opacity-50" | |
110 | + <!-- Stats Grid --> | |
111 | + <div class="grid grid-cols-1 md:grid-cols-3 gap-6"> | |
112 | + <Card className="bg-[#0d1117]/50 border-white/10 backdrop-blur-sm"> | |
113 | + <CardHeader className="pb-2"> | |
114 | + <CardTitle className="text-sm font-medium text-gray-400" | |
115 | + >Total Repositories</CardTitle | |
205 | 116 | > |
206 | - </div> | |
207 | - <div | |
208 | - class="relative rounded-xl border border-white/10 bg-[#0d1117]/80 backdrop-blur-sm p-6" | |
117 | + </CardHeader> | |
118 | + <CardContent> | |
119 | + <div class="text-3xl font-bold text-white">{repos.length}</div> | |
120 | + </CardContent> | |
121 | + </Card> | |
122 | + <Card className="bg-[#0d1117]/50 border-white/10 backdrop-blur-sm"> | |
123 | + <CardHeader className="pb-2"> | |
124 | + <CardTitle className="text-sm font-medium text-gray-400" | |
125 | + >Total Stars</CardTitle | |
209 | 126 | > |
210 | - <h2 | |
211 | - class="text-lg font-semibold text-white flex items-center gap-2 mb-4" | |
212 | - > | |
213 | - <svg | |
214 | - class="h-5 w-5 text-orange-400" | |
215 | - fill="none" | |
216 | - stroke="currentColor" | |
217 | - viewBox="0 0 24 24" | |
218 | - > | |
219 | - <path | |
220 | - stroke-linecap="round" | |
221 | - stroke-linejoin="round" | |
222 | - stroke-width="2" | |
223 | - d="M13 10V3L4 14h7v7l9-11h-7z"></path> | |
224 | - </svg> | |
225 | - Recent Activity | |
226 | - </h2> | |
227 | - <div class="text-center py-8"> | |
228 | - <div class="relative inline-block mb-4"> | |
229 | - <svg | |
230 | - class="h-12 w-12 text-gray-600" | |
231 | - fill="none" | |
232 | - stroke="currentColor" | |
233 | - viewBox="0 0 24 24" | |
234 | - > | |
235 | - <path | |
236 | - stroke-linecap="round" | |
237 | - stroke-linejoin="round" | |
238 | - stroke-width="1.5" | |
239 | - d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path> | |
240 | - </svg> | |
241 | - </div> | |
242 | - <p class="text-gray-500">No recent activity to show.</p> | |
243 | - <p class="text-sm text-gray-600 mt-1"> | |
244 | - Get started by creating a repository or exploring existing ones. | |
245 | - </p> | |
246 | - <a | |
247 | - href="/explore" | |
248 | - class="inline-flex items-center gap-2 px-4 py-2 mt-4 rounded-lg border border-white/10 bg-white/5 text-sm text-gray-300 hover:bg-white/10 transition-colors" | |
249 | - > | |
250 | - <svg | |
251 | - class="h-4 w-4" | |
252 | - fill="none" | |
253 | - stroke="currentColor" | |
254 | - viewBox="0 0 24 24" | |
255 | - > | |
256 | - <path | |
257 | - stroke-linecap="round" | |
258 | - stroke-linejoin="round" | |
259 | - stroke-width="2" | |
260 | - d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path> | |
261 | - </svg> | |
262 | - Explore Repositories | |
263 | - </a> | |
264 | - </div> | |
265 | - </div> | |
266 | - </div> | |
267 | - | |
268 | - <!-- Repositories Grid --> | |
269 | - <div> | |
270 | - <h2 | |
271 | - class="text-lg font-semibold text-white mb-4 flex items-center gap-2" | |
127 | + </CardHeader> | |
128 | + <CardContent> | |
129 | + <div class="text-3xl font-bold text-yellow-400">{totalStars}</div> | |
130 | + </CardContent> | |
131 | + </Card> | |
132 | + <Card className="bg-[#0d1117]/50 border-white/10 backdrop-blur-sm"> | |
133 | + <CardHeader className="pb-2"> | |
134 | + <CardTitle className="text-sm font-medium text-gray-400" | |
135 | + >Total Forks</CardTitle | |
272 | 136 | > |
137 | + </CardHeader> | |
138 | + <CardContent> | |
139 | + <div class="text-3xl font-bold text-purple-400">{totalForks}</div> | |
140 | + </CardContent> | |
141 | + </Card> | |
142 | + </div> | |
143 | + | |
144 | + <!-- Main Content Grid --> | |
145 | + <div class="grid grid-cols-1 md:grid-cols-3 gap-8"> | |
146 | + <!-- User's Repositories --> | |
147 | + <div class="md:col-span-2 space-y-6"> | |
148 | + <div class="flex items-center justify-between"> | |
149 | + <h2 class="text-xl font-semibold text-white flex items-center gap-2"> | |
273 | 150 | <svg |
274 | 151 | class="h-5 w-5 text-cyan-400" |
275 | 152 | fill="none" |
276 | 153 | stroke="currentColor" |
277 | 154 | viewBox="0 0 24 24" |
278 | - > | |
279 | - <path | |
155 | + ><path | |
280 | 156 | stroke-linecap="round" |
281 | 157 | stroke-linejoin="round" |
282 | 158 | stroke-width="2" |
283 | 159 | d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" |
284 | - ></path> | |
285 | - </svg> | |
286 | - Your Repositories | |
160 | + ></path></svg | |
161 | + > | |
162 | + Repositories | |
287 | 163 | </h2> |
288 | - { | |
289 | - repos.length > 0 ? ( | |
290 | - <div class="grid gap-4 md:grid-cols-2"> | |
291 | - {repos.map((repo) => ( | |
292 | - <a | |
293 | - href={`/${user.username}/${repo.name}`} | |
294 | - class="group relative" | |
295 | - > | |
296 | - <div class="absolute -inset-[1px] bg-gradient-to-r from-cyan-500/20 via-transparent to-purple-500/20 rounded-xl opacity-0 group-hover:opacity-100 transition-opacity" /> | |
297 | - <div class="relative rounded-xl border border-white/10 bg-[#0d1117]/80 backdrop-blur-sm p-5 hover:bg-white/[0.02] transition-colors"> | |
298 | - <div class="flex items-start justify-between mb-2"> | |
299 | - <div class="flex items-center gap-2"> | |
300 | - <svg | |
301 | - class="h-5 w-5 text-gray-500" | |
302 | - fill="none" | |
303 | - stroke="currentColor" | |
304 | - viewBox="0 0 24 24" | |
305 | - > | |
306 | - <path | |
307 | - stroke-linecap="round" | |
308 | - stroke-linejoin="round" | |
309 | - stroke-width="2" | |
310 | - d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" | |
311 | - /> | |
312 | - </svg> | |
313 | - <span class="font-semibold text-white group-hover:text-cyan-400 transition-colors"> | |
314 | - {repo.name} | |
315 | - </span> | |
316 | - <span | |
317 | - class={`text-xs px-2 py-0.5 rounded-full border ${ | |
318 | - repo.visibility === "public" | |
319 | - ? "border-green-500/30 text-green-400 bg-green-500/10" | |
320 | - : "border-orange-500/30 text-orange-400 bg-orange-500/10" | |
321 | - }`} | |
322 | - > | |
323 | - {repo.visibility} | |
324 | - </span> | |
164 | + <!-- Filter/Search could go here --> | |
165 | + </div> | |
166 | + | |
167 | + { | |
168 | + repos.length > 0 ? ( | |
169 | + <div class="grid gap-4"> | |
170 | + {repos.map((repo) => ( | |
171 | + <a href={`/${user.username}/${repo.name}`} class="block group"> | |
172 | + <Card className="bg-[#0d1117]/80 border-white/10 hover:border-white/20 hover:bg-[#161b22] transition-all duration-200"> | |
173 | + <CardContent className="p-5"> | |
174 | + <div class="flex items-start justify-between"> | |
175 | + <div class="space-y-1"> | |
176 | + <div class="flex items-center gap-2"> | |
177 | + <h3 class="font-semibold text-lg text-white group-hover:text-cyan-400 transition-colors"> | |
178 | + {repo.name} | |
179 | + </h3> | |
180 | + <Badge | |
181 | + variant="secondary" | |
182 | + className={`bg-opacity-10 border ${repo.visibility === "public" ? "border-green-500/30 text-green-400 bg-green-500" : "border-orange-500/30 text-orange-400 bg-orange-500"}`} | |
183 | + > | |
184 | + {repo.visibility} | |
185 | + </Badge> | |
186 | + </div> | |
187 | + <p class="text-sm text-gray-400 line-clamp-1"> | |
188 | + {repo.description || "No description provided."} | |
189 | + </p> | |
190 | + </div> | |
191 | + <div class="text-xs text-gray-500 whitespace-nowrap"> | |
192 | + {timeAgo(repo.updatedAt)} | |
325 | 193 | </div> |
326 | 194 | </div> |
327 | - <p class="text-sm text-gray-500 line-clamp-2 mb-4"> | |
328 | - {repo.description || "No description provided."} | |
329 | - </p> | |
330 | - <div class="flex items-center gap-4 text-xs text-gray-500"> | |
195 | + <div class="mt-4 flex items-center gap-6 text-sm text-gray-500"> | |
331 | 196 | {repo.language && ( |
332 | - <div class="flex items-center gap-1"> | |
333 | - <span class="h-2.5 w-2.5 rounded-full bg-blue-500" /> | |
197 | + <div class="flex items-center gap-1.5"> | |
198 | + <span class="w-2 h-2 rounded-full bg-blue-500" /> | |
334 | 199 | {repo.language} |
335 | 200 | </div> |
336 | 201 | )} |
337 | - <div class="flex items-center gap-1"> | |
202 | + <div class="flex items-center gap-1 hover:text-yellow-400 transition-colors"> | |
338 | 203 | <svg |
339 | - class="h-3.5 w-3.5 text-yellow-400" | |
204 | + class="h-4 w-4" | |
340 | 205 | fill="currentColor" |
341 | 206 | viewBox="0 0 20 20" |
342 | 207 | > |
| @@ -344,9 +209,9 @@ function timeAgo(date: string | Date) { | ||
344 | 209 | </svg> |
345 | 210 | {repo.starCount || 0} |
346 | 211 | </div> |
347 | - <div class="flex items-center gap-1"> | |
212 | + <div class="flex items-center gap-1 hover:text-purple-400 transition-colors"> | |
348 | 213 | <svg |
349 | - class="h-3.5 w-3.5 text-purple-400" | |
214 | + class="h-4 w-4" | |
350 | 215 | fill="none" |
351 | 216 | stroke="currentColor" |
352 | 217 | viewBox="0 0 24 24" |
| @@ -360,78 +225,114 @@ function timeAgo(date: string | Date) { | ||
360 | 225 | </svg> |
361 | 226 | {repo.forkCount || 0} |
362 | 227 | </div> |
363 | - <div class="ml-auto text-gray-600"> | |
364 | - Updated {timeAgo(repo.updatedAt)} | |
365 | - </div> | |
366 | 228 | </div> |
367 | - </div> | |
368 | - </a> | |
369 | - ))} | |
229 | + </CardContent> | |
230 | + </Card> | |
231 | + </a> | |
232 | + ))} | |
233 | + </div> | |
234 | + ) : ( | |
235 | + <div class="bg-[#0d1117]/30 border border-white/5 rounded-xl p-12 text-center"> | |
236 | + <div class="inline-flex items-center justify-center p-4 bg-white/5 rounded-full mb-4"> | |
237 | + <svg | |
238 | + class="h-8 w-8 text-gray-500" | |
239 | + fill="none" | |
240 | + stroke="currentColor" | |
241 | + viewBox="0 0 24 24" | |
242 | + > | |
243 | + <path | |
244 | + stroke-linecap="round" | |
245 | + stroke-linejoin="round" | |
246 | + stroke-width="2" | |
247 | + d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" | |
248 | + /> | |
249 | + </svg> | |
370 | 250 | </div> |
371 | - ) : ( | |
372 | - <div class="relative"> | |
373 | - <div class="absolute -inset-[1px] bg-gradient-to-r from-cyan-500/20 via-purple-500/20 to-pink-500/20 rounded-xl opacity-50" /> | |
374 | - <div class="relative rounded-xl border border-white/10 bg-[#0d1117]/80 backdrop-blur-sm p-12 text-center"> | |
375 | - <div class="relative inline-block mb-4"> | |
376 | - <svg | |
377 | - class="h-16 w-16 text-cyan-400" | |
378 | - fill="none" | |
379 | - stroke="currentColor" | |
380 | - viewBox="0 0 24 24" | |
381 | - > | |
382 | - <path | |
383 | - stroke-linecap="round" | |
384 | - stroke-linejoin="round" | |
385 | - stroke-width="1.5" | |
386 | - d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" | |
387 | - /> | |
388 | - </svg> | |
389 | - <div class="absolute inset-0 bg-cyan-500 blur-2xl opacity-20" /> | |
390 | - </div> | |
391 | - <h3 class="text-lg font-semibold text-white mb-2"> | |
392 | - No repositories yet | |
393 | - </h3> | |
394 | - <p class="text-gray-500 mb-6"> | |
395 | - Create your first repository to get started. | |
396 | - </p> | |
397 | - <a | |
398 | - href="/new" | |
399 | - class="inline-flex items-center gap-2 px-6 py-2.5 rounded-lg bg-gradient-to-r from-cyan-500 to-blue-600 text-sm font-medium text-white shadow-lg shadow-cyan-500/25" | |
251 | + <h3 class="text-lg font-medium text-white mb-2"> | |
252 | + No repositories found | |
253 | + </h3> | |
254 | + <p class="text-gray-500 mb-6"> | |
255 | + Get started by creating your first repository. | |
256 | + </p> | |
257 | + <a href="/new"> | |
258 | + <Button>Create Repository</Button> | |
259 | + </a> | |
260 | + </div> | |
261 | + ) | |
262 | + } | |
263 | + </div> | |
264 | + | |
265 | + <!-- Sidebar / Activity --> | |
266 | + <div class="space-y-6"> | |
267 | + <Card className="bg-[#0d1117]/50 border-white/10 backdrop-blur-sm"> | |
268 | + <CardHeader> | |
269 | + <CardTitle className="flex items-center gap-2 text-white"> | |
270 | + <svg | |
271 | + class="h-5 w-5 text-orange-400" | |
272 | + fill="none" | |
273 | + stroke="currentColor" | |
274 | + viewBox="0 0 24 24" | |
275 | + ><path | |
276 | + stroke-linecap="round" | |
277 | + stroke-linejoin="round" | |
278 | + stroke-width="2" | |
279 | + d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg | |
280 | + > | |
281 | + Recent Activity | |
282 | + </CardTitle> | |
283 | + </CardHeader> | |
284 | + <CardContent> | |
285 | + <div class="text-center py-6 text-gray-500 text-sm"> | |
286 | + No recent activity to show. | |
287 | + </div> | |
288 | + <div class="pt-4 border-t border-white/5"> | |
289 | + <a href="/explore" class="block"> | |
290 | + <Button | |
291 | + variant="ghost" | |
292 | + className="w-full justify-start text-gray-400 hover:text-white" | |
293 | + > | |
294 | + <svg | |
295 | + class="mr-2 h-4 w-4" | |
296 | + fill="none" | |
297 | + stroke="currentColor" | |
298 | + viewBox="0 0 24 24" | |
299 | + ><path | |
300 | + stroke-linecap="round" | |
301 | + stroke-linejoin="round" | |
302 | + stroke-width="2" | |
303 | + d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" | |
304 | + ></path></svg | |
400 | 305 | > |
401 | - <svg | |
402 | - class="h-4 w-4" | |
403 | - fill="none" | |
404 | - stroke="currentColor" | |
405 | - viewBox="0 0 24 24" | |
406 | - > | |
407 | - <path | |
408 | - stroke-linecap="round" | |
409 | - stroke-linejoin="round" | |
410 | - stroke-width="2" | |
411 | - d="M12 4v16m8-8H4" | |
412 | - /> | |
413 | - </svg> | |
414 | - Create a repository | |
415 | - </a> | |
416 | - </div> | |
417 | - </div> | |
418 | - ) | |
419 | - } | |
420 | - </div> | |
421 | - </main> | |
306 | + Explore Repositories | |
307 | + </Button> | |
308 | + </a> | |
309 | + </div> | |
310 | + </CardContent> | |
311 | + </Card> | |
312 | + | |
313 | + <Card | |
314 | + className="bg-gradient-to-br from-purple-900/10 to-blue-900/10 border-white/10" | |
315 | + > | |
316 | + <CardContent className="p-6"> | |
317 | + <h3 class="font-semibold text-white mb-2">Try the CLI</h3> | |
318 | + <p class="text-sm text-gray-400 mb-4"> | |
319 | + Push code, create PRs, and manage stacks directly from your | |
320 | + terminal. | |
321 | + </p> | |
322 | + <div | |
323 | + class="bg-black/50 rounded-lg p-3 font-mono text-xs text-green-400 mb-4 border border-white/10" | |
324 | + > | |
325 | + npm install -g opencodehub | |
326 | + </div> | |
327 | + <a | |
328 | + href="/docs/cli" | |
329 | + class="text-sm text-blue-400 hover:text-blue-300 hover:underline" | |
330 | + > | |
331 | + Read the documentation → | |
332 | + </a> | |
333 | + </CardContent> | |
334 | + </Card> | |
335 | + </div> | |
422 | 336 | </div> |
423 | 337 | </div> |
424 | 338 | </BaseLayout> |
425 | - | |
426 | -<style> | |
427 | - .custom-scrollbar::-webkit-scrollbar { | |
428 | - width: 4px; | |
429 | - } | |
430 | - .custom-scrollbar::-webkit-scrollbar-track { | |
431 | - background: transparent; | |
432 | - } | |
433 | - .custom-scrollbar::-webkit-scrollbar-thumb { | |
434 | - background: rgba(255, 255, 255, 0.1); | |
435 | - border-radius: 4px; | |
436 | - } | |
437 | -</style> | |
438 | 339 | |
▼src/pages/git/[owner]/[repo]/git-receive-pack.ts
+56-0
| @@ -0,0 +1,56 @@ | ||
1 | + | |
2 | +import type { APIRoute } from "astro"; | |
3 | +import { handleReceivePack } from "@/lib/git-server"; | |
4 | +import { acquireRepo, releaseRepo, getStorageRepoPath } from "@/lib/git-storage"; | |
5 | +import { logger } from "@/lib/logger"; | |
6 | + | |
7 | +export const POST: APIRoute = async ({ params, request }) => { | |
8 | + const { owner, repo } = params; | |
9 | + | |
10 | + if (!owner || !repo) { | |
11 | + return new Response("Missing owner or repo", { status: 400 }); | |
12 | + } | |
13 | + | |
14 | + // Handle .git suffix | |
15 | + const repoName = repo.endsWith(".git") ? repo.slice(0, -4) : repo; | |
16 | + | |
17 | + // Check Content-Type | |
18 | + const contentType = request.headers.get("Content-Type"); | |
19 | + if (contentType !== "application/x-git-receive-pack-request") { | |
20 | + return new Response("Invalid Content-Type", { status: 415 }); | |
21 | + } | |
22 | + | |
23 | + logger.info({ owner, repoName }, "Git receive-pack request"); | |
24 | + | |
25 | + let repoPath: string; | |
26 | + try { | |
27 | + // Repos are always initialized on creation now, just acquire | |
28 | + repoPath = await acquireRepo(owner, repoName); | |
29 | + } catch (err) { | |
30 | + logger.error({ err }, "Failed to acquire repo"); | |
31 | + return new Response("Repository not found", { status: 404 }); | |
32 | + } | |
33 | + | |
34 | + const storagePath = getStorageRepoPath(owner, repoName); | |
35 | + | |
36 | + try { | |
37 | + // Process the pack stream | |
38 | + const responseStream = await handleReceivePack(repoPath, request.body!, storagePath); | |
39 | + | |
40 | + // Release repo with modification flag true | |
41 | + // Note: This might trigger re-upload of the packfile effectively checking consistency | |
42 | + await releaseRepo(owner, repoName, true); | |
43 | + | |
44 | + return new Response(responseStream as any, { | |
45 | + headers: { | |
46 | + "Content-Type": "application/x-git-receive-pack-result", | |
47 | + "Cache-Control": "no-cache", | |
48 | + }, | |
49 | + }); | |
50 | + } catch (err) { | |
51 | + logger.error({ err }, "Failed to handle receive-pack"); | |
52 | + // Release repo without saving changes (rollback attempt) | |
53 | + await releaseRepo(owner, repoName, false); | |
54 | + return new Response("Internal Server Error", { status: 500 }); | |
55 | + } | |
56 | +}; | |
0 | 57 | |
▼src/pages/git/[owner]/[repo]/git-upload-pack.ts
+63-0
| @@ -0,0 +1,63 @@ | ||
1 | + | |
2 | +import type { APIRoute } from "astro"; | |
3 | +import { handleUploadPack } from "@/lib/git-server"; | |
4 | +import { acquireRepo, releaseRepo } from "@/lib/git-storage"; | |
5 | +import { logger } from "@/lib/logger"; | |
6 | + | |
7 | +export const POST: APIRoute = async ({ params, request }) => { | |
8 | + const { owner, repo } = params; | |
9 | + | |
10 | + if (!owner || !repo) { | |
11 | + return new Response("Missing owner or repo", { status: 400 }); | |
12 | + } | |
13 | + | |
14 | + // Handle .git suffix | |
15 | + const repoName = repo.endsWith(".git") ? repo.slice(0, -4) : repo; | |
16 | + | |
17 | + // Check Content-Type | |
18 | + const contentType = request.headers.get("Content-Type"); | |
19 | + if (contentType !== "application/x-git-upload-pack-request") { | |
20 | + return new Response("Invalid Content-Type", { status: 415 }); | |
21 | + } | |
22 | + | |
23 | + logger.info({ owner, repoName }, "Git upload-pack request"); | |
24 | + | |
25 | + let repoPath: string; | |
26 | + try { | |
27 | + repoPath = await acquireRepo(owner, repoName); | |
28 | + } catch (err) { | |
29 | + logger.error({ err }, "Failed to acquire repo"); | |
30 | + return new Response("Repository not found", { status: 404 }); | |
31 | + } | |
32 | + | |
33 | + // Check if repository is initialized (has HEAD file) | |
34 | + const { existsSync } = await import("fs"); | |
35 | + const { join } = await import("path"); | |
36 | + const headPath = join(repoPath, 'HEAD'); | |
37 | + | |
38 | + if (!existsSync(headPath)) { | |
39 | + logger.warn({ repoPath }, "Attempted to clone uninitialized repository"); | |
40 | + return new Response( | |
41 | + "Repository is empty. Push some code first before cloning.", | |
42 | + { status: 404 } | |
43 | + ); | |
44 | + } | |
45 | + | |
46 | + try { | |
47 | + // Process the upload request | |
48 | + const responseStream = await handleUploadPack(repoPath, request.body!); | |
49 | + | |
50 | + return new Response(responseStream as any, { | |
51 | + headers: { | |
52 | + "Content-Type": "application/x-git-upload-pack-result", | |
53 | + "Cache-Control": "no-cache", | |
54 | + }, | |
55 | + }); | |
56 | + } catch (err) { | |
57 | + logger.error({ err }, "Failed to handle upload-pack"); | |
58 | + return new Response("Internal Server Error", { status: 500 }); | |
59 | + } finally { | |
60 | + // Release repo (read-only) | |
61 | + await releaseRepo(owner, repoName, false); | |
62 | + } | |
63 | +}; | |
0 | 64 | |
▼src/pages/git/[owner]/[repo]/info/refs.ts
+88-0
| @@ -0,0 +1,88 @@ | ||
1 | + | |
2 | +import type { APIRoute } from "astro"; | |
3 | +import { getAdvertisedRefs } from "@/lib/git-server"; | |
4 | +import { acquireRepo, releaseRepo } from "@/lib/git-storage"; | |
5 | +import { logger } from "@/lib/logger"; | |
6 | + | |
7 | +export const GET: APIRoute = async ({ params, request, url }) => { | |
8 | + const { owner, repo } = params; | |
9 | + | |
10 | + if (!owner || !repo) { | |
11 | + return new Response("Missing owner or repo", { status: 400 }); | |
12 | + } | |
13 | + | |
14 | + // Handle .git suffix | |
15 | + const repoName = repo.endsWith(".git") ? repo.slice(0, -4) : repo; | |
16 | + | |
17 | + const service = url.searchParams.get("service"); | |
18 | + | |
19 | + // Git protocol requires service param (e.g., git-upload-pack or git-receive-pack) | |
20 | + if (!service || !["git-upload-pack", "git-receive-pack"].includes(service)) { | |
21 | + // Dumb protocol buffer? Or just error. Modern clients use smart protocol | |
22 | + return new Response("Service not specified or invalid", { status: 400 }); | |
23 | + } | |
24 | + | |
25 | + logger.info({ owner, repoName, service }, "=== GIT INFO/REFS REQUEST START ==="); | |
26 | + | |
27 | + // Acquire repo (download/cache) | |
28 | + let repoPath: string; | |
29 | + try { | |
30 | + repoPath = await acquireRepo(owner, repoName); | |
31 | + } catch (err) { | |
32 | + logger.error({ err }, "Failed to acquire repo"); | |
33 | + return new Response("Repository not found", { status: 404 }); | |
34 | + } | |
35 | + | |
36 | + // Check if repository is initialized (has HEAD file) | |
37 | + const { existsSync } = await import("fs"); | |
38 | + const { join } = await import("path"); | |
39 | + const headPath = join(repoPath, 'HEAD'); | |
40 | + | |
41 | + logger.info({ headPath, exists: existsSync(headPath) }, "Checking if repo is initialized"); | |
42 | + | |
43 | + if (!existsSync(headPath)) { | |
44 | + // Repository not initialized yet (lazy init) | |
45 | + logger.warn({ repoName, service, headPath }, "Repository not initialized - returning error"); | |
46 | + | |
47 | + if (service === "git-upload-pack") { | |
48 | + // Return error for clone attempts on empty repo | |
49 | + logger.error({ repoName }, "Blocking clone attempt on empty repository"); | |
50 | + return new Response("Repository is empty. Push some code first before cloning.", { status: 404 }); | |
51 | + } | |
52 | + | |
53 | + // For receive-pack (push), return minimal capabilities to allow first push | |
54 | + logger.info("Returning empty refs for receive-pack"); | |
55 | + const emptyRefs = `001e# service=${service}\n0000` + | |
56 | + `00000000000000000000000000000000000000000000 capabilities^{}\0report-status report-status-v2 side-band-64k object-format=sha1\n` + | |
57 | + `0000`; | |
58 | + | |
59 | + return new Response(emptyRefs, { | |
60 | + headers: { | |
61 | + "Content-Type": `application/x-${service}-advertisement`, | |
62 | + "Cache-Control": "no-cache", | |
63 | + }, | |
64 | + }); | |
65 | + } | |
66 | + | |
67 | + logger.info("Repository is initialized, proceeding with normal refs"); | |
68 | + | |
69 | + try { | |
70 | + const refs = await getAdvertisedRefs({ | |
71 | + repoPath, | |
72 | + service: service as "git-upload-pack" | "git-receive-pack", | |
73 | + }); | |
74 | + | |
75 | + return new Response(refs, { | |
76 | + headers: { | |
77 | + "Content-Type": `application/x-${service}-advertisement`, | |
78 | + "Cache-Control": "no-cache", | |
79 | + }, | |
80 | + }); | |
81 | + } catch (err) { | |
82 | + logger.error({ err }, "Failed to get refs"); | |
83 | + return new Response("Internal Server Error", { status: 500 }); | |
84 | + } finally { | |
85 | + // Release repo (no modification) | |
86 | + await releaseRepo(owner, repoName, false); | |
87 | + } | |
88 | +}; | |
0 | 89 | |
▼src/pages/stacks.astro
+131-0
| @@ -0,0 +1,131 @@ | ||
1 | +--- | |
2 | +import { getDatabase, schema } from "@/db"; | |
3 | +import BaseLayout from "@/layouts/BaseLayout.astro"; | |
4 | +import { desc, eq, inArray } from "drizzle-orm"; | |
5 | +import StackCard from "@/components/dashboard/StackCard.astro"; | |
6 | + | |
7 | +const user = Astro.locals.user; | |
8 | +if (!user) { | |
9 | + return Astro.redirect("/login"); | |
10 | +} | |
11 | + | |
12 | +const db = getDatabase(); | |
13 | + | |
14 | +// Fetch user's stacks | |
15 | +const userPrs = await db.query.pullRequests.findMany({ | |
16 | + where: eq(schema.pullRequests.authorId, user.id), | |
17 | + columns: { id: true }, | |
18 | +}); | |
19 | + | |
20 | +let stacks: any[] = []; | |
21 | +const prIds = userPrs.map((pr) => pr.id); | |
22 | + | |
23 | +if (prIds.length > 0) { | |
24 | + const stackEntries = await db.query.prStackEntries.findMany({ | |
25 | + where: inArray(schema.prStackEntries.pullRequestId, prIds), | |
26 | + columns: { stackId: true }, | |
27 | + }); | |
28 | + | |
29 | + const uniqueStackIds = [...new Set(stackEntries.map((e) => e.stackId))]; | |
30 | + | |
31 | + if (uniqueStackIds.length > 0) { | |
32 | + const dbStacks = await db.query.prStacks.findMany({ | |
33 | + where: inArray(schema.prStacks.id, uniqueStackIds), | |
34 | + orderBy: [desc(schema.prStacks.updatedAt)], | |
35 | + with: { | |
36 | + repository: { | |
37 | + with: { | |
38 | + owner: true, | |
39 | + }, | |
40 | + }, | |
41 | + entries: { | |
42 | + orderBy: (entries, { asc }) => [asc(entries.stackOrder)], | |
43 | + with: { | |
44 | + pullRequest: true, | |
45 | + }, | |
46 | + }, | |
47 | + }, | |
48 | + }); | |
49 | + | |
50 | + stacks = dbStacks.map((stack) => ({ | |
51 | + id: stack.id, | |
52 | + name: stack.name || `Stack-${stack.id.substring(0, 6)}`, | |
53 | + baseBranch: stack.baseBranch, | |
54 | + status: stack.status, | |
55 | + repoName: stack.repository.name, | |
56 | + repoOwner: stack.repository.owner.username, | |
57 | + updatedAt: stack.updatedAt.toISOString(), | |
58 | + prs: stack.entries.map((entry) => ({ | |
59 | + id: entry.pullRequest.id, | |
60 | + number: entry.pullRequest.number, | |
61 | + title: entry.pullRequest.title, | |
62 | + status: entry.pullRequest.state, | |
63 | + url: `/${stack.repository.owner.username}/${stack.repository.name}/pulls/${entry.pullRequest.number}`, | |
64 | + position: entry.stackOrder, | |
65 | + isMerged: entry.pullRequest.state === "merged", | |
66 | + isClosed: entry.pullRequest.state === "closed", | |
67 | + })), | |
68 | + })); | |
69 | + } | |
70 | +} | |
71 | +--- | |
72 | + | |
73 | +<BaseLayout title={`Your Stacks - OpenCodeHub`}> | |
74 | + <div class="container py-8 max-w-5xl mx-auto"> | |
75 | + <div class="flex items-center justify-between mb-8"> | |
76 | + <div> | |
77 | + <h1 class="text-2xl font-bold text-white mb-2">Your Stacks</h1> | |
78 | + <p class="text-gray-400"> | |
79 | + Manage and visualize your stacked pull requests. | |
80 | + </p> | |
81 | + </div> | |
82 | + <a | |
83 | + href="/dashboard" | |
84 | + class="px-4 py-2 rounded-lg bg-white/5 hover:bg-white/10 text-sm text-gray-300 transition-colors" | |
85 | + > | |
86 | + Back to Dashboard | |
87 | + </a> | |
88 | + </div> | |
89 | + | |
90 | + { | |
91 | + stacks.length > 0 ? ( | |
92 | + <div class="grid gap-6 md:grid-cols-2 lg:grid-cols-2"> | |
93 | + {stacks.map((stack) => ( | |
94 | + <StackCard stack={stack} /> | |
95 | + ))} | |
96 | + </div> | |
97 | + ) : ( | |
98 | + <div class="text-center py-20 bg-[#0d1117]/50 rounded-xl border border-white/5"> | |
99 | + <div class="inline-flex items-center justify-center w-16 h-16 rounded-full bg-blue-500/10 text-blue-400 mb-4"> | |
100 | + <svg | |
101 | + class="w-8 h-8" | |
102 | + fill="none" | |
103 | + stroke="currentColor" | |
104 | + viewBox="0 0 24 24" | |
105 | + > | |
106 | + <path | |
107 | + stroke-linecap="round" | |
108 | + stroke-linejoin="round" | |
109 | + stroke-width="2" | |
110 | + d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" | |
111 | + /> | |
112 | + </svg> | |
113 | + </div> | |
114 | + <h3 class="text-lg font-medium text-white mb-2"> | |
115 | + No active stacks | |
116 | + </h3> | |
117 | + <p class="text-gray-500 max-w-sm mx-auto mb-6"> | |
118 | + Create stacked pull requests to see them visualized | |
119 | + here. | |
120 | + </p> | |
121 | + <a | |
122 | + href="/docs/stacks" | |
123 | + class="text-blue-400 hover:text-blue-300 text-sm" | |
124 | + > | |
125 | + Learn how to create stacks → | |
126 | + </a> | |
127 | + </div> | |
128 | + ) | |
129 | + } | |
130 | + </div> | |
131 | +</BaseLayout> | |
0 | 132 | |