Skip to content

Commit 3148833

Browse files
feat: remove usage of Node built-ins (#154)
1 parent 8259e5e commit 3148833

File tree

6 files changed

+81
-20
lines changed

6 files changed

+81
-20
lines changed

src/environment.ts

+49-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,48 @@
1-
import { Buffer } from 'node:buffer'
2-
import { env } from 'node:process'
1+
import { base64Decode, base64Encode } from './util.ts'
2+
3+
interface EnvironmentVariables {
4+
delete: (key: string) => void
5+
get: (key: string) => string | undefined
6+
has: (key: string) => boolean
7+
set: (key: string, value: string) => void
8+
toObject: () => Record<string, string>
9+
}
10+
11+
interface Globals {
12+
Deno?: {
13+
env: EnvironmentVariables
14+
}
15+
Netlify?: {
16+
env: EnvironmentVariables
17+
}
18+
process?: {
19+
env: Record<string, string>
20+
}
21+
}
22+
23+
/**
24+
* Returns a cross-runtime interface for handling environment variables. It
25+
* uses the `Netlify.env` global if available, otherwise looks for `Deno.env`
26+
* and `process.env`.
27+
*/
28+
export const getEnvironment = (): EnvironmentVariables => {
29+
const { Deno, Netlify, process } = globalThis as Globals
30+
31+
return (
32+
Netlify?.env ??
33+
Deno?.env ?? {
34+
delete: (key: string) => delete process?.env[key],
35+
get: (key: string) => process?.env[key],
36+
has: (key: string) => Boolean(process?.env[key]),
37+
set: (key: string, value: string) => {
38+
if (process?.env) {
39+
process.env[key] = value
40+
}
41+
},
42+
toObject: () => process?.env ?? {},
43+
}
44+
)
45+
}
346

447
declare global {
548
// Using `var` so that the declaration is hoisted in such a way that we can
@@ -21,13 +64,13 @@ export interface EnvironmentContext {
2164
}
2265

2366
export const getEnvironmentContext = (): EnvironmentContext => {
24-
const context = globalThis.netlifyBlobsContext || env.NETLIFY_BLOBS_CONTEXT
67+
const context = globalThis.netlifyBlobsContext || getEnvironment().get('NETLIFY_BLOBS_CONTEXT')
2568

2669
if (typeof context !== 'string' || !context) {
2770
return {}
2871
}
2972

30-
const data = Buffer.from(context, 'base64').toString()
73+
const data = base64Decode(context)
3174

3275
try {
3376
return JSON.parse(data) as EnvironmentContext
@@ -39,9 +82,9 @@ export const getEnvironmentContext = (): EnvironmentContext => {
3982
}
4083

4184
export const setEnvironmentContext = (context: EnvironmentContext) => {
42-
const encodedContext = Buffer.from(JSON.stringify(context)).toString('base64')
85+
const encodedContext = base64Encode(JSON.stringify(context))
4386

44-
env.NETLIFY_BLOBS_CONTEXT = encodedContext
87+
getEnvironment().set('NETLIFY_BLOBS_CONTEXT', encodedContext)
4588
}
4689

4790
export class MissingBlobsEnvironmentError extends Error {

src/lambda_compat.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
import { Buffer } from 'node:buffer'
2-
31
import { EnvironmentContext, setEnvironmentContext } from './environment.ts'
42
import type { LambdaEvent } from './types.ts'
3+
import { base64Decode } from './util.ts'
54

65
interface BlobsEventData {
76
token: string
87
url: string
98
}
109

1110
export const connectLambda = (event: LambdaEvent) => {
12-
const rawData = Buffer.from(event.blobs, 'base64')
13-
const data = JSON.parse(rawData.toString('ascii')) as BlobsEventData
11+
const rawData = base64Decode(event.blobs)
12+
const data = JSON.parse(rawData) as BlobsEventData
1413
const environmentContext: EnvironmentContext = {
1514
deployID: event.headers['x-nf-deploy-id'],
1615
edgeURL: data.url,

src/metadata.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Buffer } from 'node:buffer'
1+
import { base64Decode, base64Encode } from './util.ts'
22

33
export type Metadata = Record<string, unknown>
44

@@ -12,7 +12,7 @@ export const encodeMetadata = (metadata?: Metadata) => {
1212
return null
1313
}
1414

15-
const encodedObject = Buffer.from(JSON.stringify(metadata)).toString('base64')
15+
const encodedObject = base64Encode(JSON.stringify(metadata))
1616
const payload = `b64;${encodedObject}`
1717

1818
if (METADATA_HEADER_EXTERNAL.length + payload.length > METADATA_MAX_SIZE) {
@@ -28,7 +28,7 @@ export const decodeMetadata = (header: string | null): Metadata => {
2828
}
2929

3030
const encodedData = header.slice(BASE64_PREFIX.length)
31-
const decodedData = Buffer.from(encodedData, 'base64').toString()
31+
const decodedData = base64Decode(encodedData)
3232
const metadata = JSON.parse(decodedData)
3333

3434
return metadata

src/retry.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import { env } from 'node:process'
2-
1+
import { getEnvironment } from './environment.ts'
32
import type { Fetcher } from './types.ts'
43

5-
const DEFAULT_RETRY_DELAY = env.NODE_ENV === 'test' ? 1 : 5000
4+
const DEFAULT_RETRY_DELAY = getEnvironment().get('NODE_ENV') === 'test' ? 1 : 5000
65
const MIN_RETRY_DELAY = 1000
76
const MAX_RETRY = 5
87
const RATE_LIMIT_HEADER = 'X-RateLimit-Reset'

src/store.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { Buffer } from 'node:buffer'
2-
31
import { ListResponse, ListResponseBlob } from './backend/list.ts'
42
import { Client } from './client.ts'
53
import type { ConsistencyMode } from './consistency.ts'
@@ -341,7 +339,7 @@ export class Store {
341339
throw new Error('Blob key must not start with forward slash (/).')
342340
}
343341

344-
if (Buffer.byteLength(key, 'utf8') > 600) {
342+
if (new TextEncoder().encode(key).length > 600) {
345343
throw new Error(
346344
'Blob key must be a sequence of Unicode characters whose UTF-8 encoding is at most 600 bytes long.',
347345
)
@@ -363,7 +361,7 @@ export class Store {
363361
throw new Error('Store name must not contain forward slashes (/).')
364362
}
365363

366-
if (Buffer.byteLength(name, 'utf8') > 64) {
364+
if (new TextEncoder().encode(name).length > 64) {
367365
throw new Error(
368366
'Store name must be a sequence of Unicode characters whose UTF-8 encoding is at most 64 bytes long.',
369367
)

src/util.ts

+22
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,25 @@ export const collectIterator = async <T>(iterator: AsyncIterable<T>): Promise<T[
1919
export const isNodeError = (error: unknown): error is NodeJS.ErrnoException => error instanceof Error
2020

2121
export type Logger = (...message: unknown[]) => void
22+
23+
export const base64Decode = (input: string) => {
24+
// eslint-disable-next-line n/prefer-global/buffer
25+
const { Buffer } = globalThis
26+
27+
if (Buffer) {
28+
return Buffer.from(input, 'base64').toString()
29+
}
30+
31+
return atob(input)
32+
}
33+
34+
export const base64Encode = (input: string) => {
35+
// eslint-disable-next-line n/prefer-global/buffer
36+
const { Buffer } = globalThis
37+
38+
if (Buffer) {
39+
return Buffer.from(input).toString('base64')
40+
}
41+
42+
return btoa(input)
43+
}

0 commit comments

Comments
 (0)