Skip to content

Commit e56b65b

Browse files
authored
Hyperscope (#383)
1 parent 81c84ad commit e56b65b

9 files changed

Lines changed: 453 additions & 62 deletions

File tree

bin/cli.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,25 @@
33
import fs from 'fs/promises'
44
import packageJson from '../package.json' with { type: 'json' }
55
import { chat } from './chat.js'
6+
import { scope } from './scope.js'
67
import { serve } from './serve.js'
78

89
const updateCheck = checkForUpdates()
910

1011
const arg = process.argv[2]
11-
if (arg === '--help' || arg === '-H' || arg === '-h') {
12+
if (arg === 'scope') {
13+
const filePath = process.argv[3]
14+
if (!filePath) {
15+
console.error('Error: hyperparam scope requires a file argument')
16+
process.exit(1)
17+
}
18+
scope(filePath)
19+
} else if (arg === '--help' || arg === '-H' || arg === '-h') {
1220
console.log('Usage:')
1321
console.log(' hyperparam start chat client')
1422
console.log(' hyperparam [path] start hyperparam webapp. "path" is a directory or a URL.')
23+
console.log(' defaults to the current directory.')
24+
console.log(' hyperparam scope start hyperscope client')
1525
console.log(' ')
1626
console.log(' hyperparam -h, --help, give this help list')
1727
console.log(' hyperparam -v, --version print program version')

bin/s3.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/**
2+
* Parse an S3 URL into bucket and key components
3+
* @param {string} url - S3 URL in format:
4+
* - s3://bucket/key
5+
* - https://bucket.s3.amazonaws.com/key
6+
* - https://s3.amazonaws.com/bucket/key
7+
* - https://bucket.s3.region.amazonaws.com/key
8+
* @returns {{bucket: string, key: string}} Object with bucket and key
9+
* @throws {Error} If URL format is invalid
10+
*/
11+
export function parseS3Url(url) {
12+
if (!url || typeof url !== 'string') {
13+
throw new Error('Invalid S3 URL: URL must be a non-empty string')
14+
}
15+
16+
// Handle s3:// protocol
17+
if (url.startsWith('s3://')) {
18+
const withoutProtocol = url.slice(5) // Remove 's3://'
19+
const firstSlashIndex = withoutProtocol.indexOf('/')
20+
21+
if (firstSlashIndex === -1) {
22+
throw new Error('Invalid S3 URL: Missing key after bucket name')
23+
}
24+
25+
const bucket = withoutProtocol.slice(0, firstSlashIndex)
26+
const key = withoutProtocol.slice(firstSlashIndex + 1)
27+
28+
if (!bucket) {
29+
throw new Error('Invalid S3 URL: Empty bucket name')
30+
}
31+
32+
if (!key) {
33+
throw new Error('Invalid S3 URL: Empty key')
34+
}
35+
36+
return { bucket, key }
37+
}
38+
39+
// Handle https:// protocol
40+
if (url.startsWith('https://') || url.startsWith('http://')) {
41+
const urlObj = new URL(url)
42+
const { hostname } = urlObj
43+
const pathname = urlObj.pathname.startsWith('/')
44+
? urlObj.pathname.slice(1)
45+
: urlObj.pathname
46+
47+
if (!pathname) {
48+
throw new Error('Invalid S3 URL: Missing key in path')
49+
}
50+
51+
// Virtual-hosted-style URL: https://bucket.s3.amazonaws.com/key
52+
// or https://bucket.s3.region.amazonaws.com/key
53+
if (hostname.includes('.s3.') || hostname.includes('.s3-')) {
54+
const bucket = hostname.split('.')[0]
55+
const key = pathname
56+
57+
if (!bucket) {
58+
throw new Error('Invalid S3 URL: Empty bucket name')
59+
}
60+
61+
return { bucket, key }
62+
}
63+
64+
// Path-style URL: https://s3.amazonaws.com/bucket/key
65+
// or https://s3.region.amazonaws.com/bucket/key
66+
if (hostname.startsWith('s3.') || hostname.startsWith('s3-') || hostname === 's3.amazonaws.com') {
67+
const firstSlashIndex = pathname.indexOf('/')
68+
69+
if (firstSlashIndex === -1) {
70+
// pathname is just the bucket with no key
71+
throw new Error('Invalid S3 URL: Missing key after bucket name')
72+
}
73+
74+
const bucket = pathname.slice(0, firstSlashIndex)
75+
const key = pathname.slice(firstSlashIndex + 1)
76+
77+
if (!bucket) {
78+
throw new Error('Invalid S3 URL: Empty bucket name')
79+
}
80+
81+
if (!key) {
82+
throw new Error('Invalid S3 URL: Empty key')
83+
}
84+
85+
return { bucket, key }
86+
}
87+
88+
throw new Error('Invalid S3 URL: Hostname does not match S3 URL patterns')
89+
}
90+
91+
throw new Error('Invalid S3 URL: Must start with s3:// or https://')
92+
}

0 commit comments

Comments
 (0)