• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

StauroDEV / filebase-upload / 7005261298

27 Nov 2023 12:53PM UTC coverage: 29.699% (+1.6%) from 28.077%
7005261298

push

github

web-flow
Merge pull request #1 from StauroDEV/aaron/api

feat: made `apiUrl` optional and added tests

7 of 9 branches covered (0.0%)

Branch coverage included in aggregate %.

6 of 10 new or added lines in 4 files covered. (60.0%)

72 of 257 relevant lines covered (28.02%)

0.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

26.24
/utils.ts
1
import { FILEBASE_API_URL } from './constants.ts'
2✔
2
import { aws4, AwsCredentialIdentity, Buffer, IHttpRequest, QueryParameterBag } from './deps.ts'
2✔
3
import { RequiredArgs } from './types.ts'
4

5
export const parseUrl = (
2✔
6
  url: string | URL,
2✔
7
): Pick<IHttpRequest, 'hostname' | 'port' | 'protocol' | 'path' | 'query'> => {
8
  if (typeof url === 'string') {
7✔
9
    return parseUrl(new URL(url))
10✔
10
  }
10✔
11
  const { hostname, pathname, port, protocol } = url as URL
9✔
12

13
  return {
9✔
14
    hostname,
9✔
15
    port: port ? parseInt(port) : undefined,
7✔
16
    protocol,
7✔
17
    path: pathname,
7✔
18
    query: undefined,
7✔
19
  }
7✔
20
}
2✔
21

22
export const generateFilebaseRequestOptions = (
2✔
23
  token: string,
2✔
24
  requestOptions: aws4.Request & { key?: string },
2✔
25
) => {
26
  const [accessKeyId, secretAccessKey] = atob(token).split(':')
4✔
27
  if (!accessKeyId || !secretAccessKey) {
×
28
    throw new Error('Missing access key ID and secret access key')
×
29
  }
×
30
  aws4.sign(requestOptions, { accessKeyId, secretAccessKey })
16✔
31
  return requestOptions
4✔
32
}
2✔
33

34
const te = new TextEncoder()
2✔
35

36
export const toUint8Array = (
2✔
37
  data: string | ArrayBuffer | ArrayBufferView,
2✔
38
): Uint8Array => {
39
  if (typeof data === 'string') {
4✔
40
    return te.encode(data)
5✔
41
  }
5✔
42

43
  if (ArrayBuffer.isView(data)) {
×
44
    return new Uint8Array(
×
45
      data.buffer,
×
46
      data.byteOffset,
×
47
      data.byteLength / Uint8Array.BYTES_PER_ELEMENT,
×
48
    )
49
  }
✔
50

51
  return new Uint8Array(data)
5✔
52
}
2✔
53
const hexEncode = (c: string) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`
×
54

55
const escapeUri = (uri: string): string =>
×
56
  // AWS percent-encodes some extra non-standard characters in a URI
×
57
  encodeURIComponent(uri).replace(/[!'()*]/g, hexEncode)
×
58

59
export const buildQueryString = (query: QueryParameterBag): string => {
×
60
  const parts: string[] = []
×
61
  for (let key of Object.keys(query).sort()) {
×
62
    const value = query[key]
×
63
    key = escapeUri(key)
×
64
    if (Array.isArray(value)) {
×
65
      for (let i = 0, iLen = value.length; i < iLen; i++) {
×
66
        parts.push(`${key}=${escapeUri(value[i])}`)
×
67
      }
×
68
    } else {
×
69
      let qsEntry = key
×
70
      if (value || typeof value === 'string') {
×
71
        qsEntry += `=${escapeUri(value)}`
×
72
      }
×
73
      parts.push(qsEntry)
×
74
    }
×
75
  }
×
76

77
  return parts.join('&')
×
78
}
×
79

80
export const castSourceData = (
×
81
  toCast: string | Buffer | ArrayBuffer,
×
82
  encoding?: BufferEncoding,
×
83
): Buffer => {
84
  if (Buffer.isBuffer(toCast)) {
×
85
    return toCast
×
86
  }
×
87

88
  if (typeof toCast === 'string') {
×
89
    return Buffer.from(toCast, encoding)
×
90
  }
×
91

92
  if (ArrayBuffer.isView(toCast)) {
×
93
    return Buffer.from(toCast.buffer, toCast.byteOffset, toCast.byteLength)
×
94
  }
×
95

96
  return Buffer.from(toCast)
×
97
}
×
98

99
export const formatUrl = (
×
100
  request: Omit<IHttpRequest, 'headers' | 'method'>,
×
101
): string => {
102
  const { port, query } = request
×
103
  let { protocol, path, hostname } = request
×
104
  if (protocol && protocol.slice(-1) !== ':') {
×
105
    protocol += ':'
×
106
  }
×
107
  if (port) {
×
108
    hostname += `:${port}`
×
109
  }
×
110
  if (path && path.charAt(0) !== '/') {
×
111
    path = `/${path}`
×
112
  }
×
113
  let queryString = query ? buildQueryString(query) : ''
×
114
  if (queryString && queryString[0] !== '?') {
×
115
    queryString = `?${queryString}`
×
116
  }
×
117
  let auth = ''
×
118
  if (request.username != null || request.password != null) {
×
119
    const username = request.username ?? ''
×
120
    const password = request.password ?? ''
×
121
    auth = `${username}:${password}@`
×
122
  }
×
123
  let fragment = ''
×
124
  if (request.fragment) {
×
125
    fragment = `#${request.fragment}`
×
126
  }
×
127
  return `${protocol}//${auth}${hostname}${path}${queryString}${fragment}`
×
128
}
×
129

130
export const fromEnv = (filebaseToken: string): () => Promise<AwsCredentialIdentity> => {
×
131
  return async () => {
×
132
    const [accessKeyId, secretAccessKey] = atob(filebaseToken).split(':')
×
133
    if (!accessKeyId || !secretAccessKey) {
×
134
      throw new Error('Missing access key ID and secret access key')
×
135
    }
×
136
    return {
×
137
      accessKeyId,
×
138
      secretAccessKey,
×
139
    }
×
140
  }
×
141
}
×
142

143
export const createBucket = async (
×
144
  { bucketName, apiUrl, token }: RequiredArgs,
×
145
) => {
146
  let requestOptions: aws4.Request = {
×
NEW
147
    host: `${bucketName}.${apiUrl ?? FILEBASE_API_URL}`,
×
148
    region: 'us-east-1',
×
149
    method: 'PUT',
×
150
    service: 's3',
×
151
    headers: {
×
152
      'Content-Length': 0,
×
153
    },
×
154
  }
×
155
  requestOptions = generateFilebaseRequestOptions(token, requestOptions)
×
156
  return await fetch(`https://${requestOptions.host}/`, requestOptions as RequestInit)
×
157
    .then((res) => res.status == 200)
×
158
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc