Skip to content

Commit 5c152c5

Browse files
committed
Add support for Cloudflare Workers
1 parent fa3ceaf commit 5c152c5

16 files changed

+189
-165
lines changed

.eslintrc.cjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ module.exports = {
1414
// aren't imported as 'import type' in other parts of the generated
1515
// querybuilder, so set this option to ensure we always do that
1616
"@typescript-eslint/consistent-type-imports": "error",
17-
"@typescript-eslint/no-namespace": "off"
17+
"@typescript-eslint/no-namespace": "off",
18+
"@typescript-eslint/no-inferrable-types": "off",
1819
}
1920
};

compileForDeno.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ export async function run({
135135

136136
let resolvedImportPath = resolveImportPath(importPath, sourcePath);
137137

138-
for (const name of ["adapter", "adapter.shared", "adapter.crypto"]) {
138+
for (const name of ["adapter", "adapter.crypto"]) {
139139
if (resolvedImportPath.endsWith(`/${name}.node.ts`)) {
140140
resolvedImportPath = resolvedImportPath.replace(
141141
`/${name}.node.ts`,

packages/driver/src/adapter.node.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import * as crypto from "crypto";
2-
import { promises as fs } from "fs";
3-
import * as net from "net";
4-
import * as os from "os";
5-
import * as path from "path";
6-
import * as tls from "tls";
1+
import * as crypto from "node:crypto";
2+
import { promises as fs } from "node:fs";
3+
import * as net from "node:net";
4+
import * as os from "node:os";
5+
import * as path from "node:path";
6+
import * as tls from "node:tls";
77

8-
import process from "process";
9-
import * as readline from "readline";
10-
import { Writable } from "stream";
8+
import process from "node:process";
9+
import * as readline from "node:readline";
10+
import { Writable } from "node:stream";
1111

1212
export { path, net, fs, tls, process };
1313

@@ -84,7 +84,7 @@ export function input(
8484
): Promise<string> {
8585
let silent = false;
8686

87-
const output = !!params?.silent
87+
const output = params?.silent
8888
? new Writable({
8989
write(
9090
chunk: any,
@@ -101,7 +101,7 @@ export function input(
101101
output,
102102
});
103103

104-
return new Promise((resolve, rej) => {
104+
return new Promise((resolve) => {
105105
rl.question(message, (val) => {
106106
rl.close();
107107
resolve(val);

packages/driver/src/adapter.shared.deno.ts

Lines changed: 0 additions & 12 deletions
This file was deleted.

packages/driver/src/adapter.shared.node.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.

packages/driver/src/browserClient.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
import { BaseClientPool, Client, ConnectOptions } from "./baseClient";
1+
import { BaseClientPool, Client, type ConnectOptions } from "./baseClient";
22
import { getConnectArgumentsParser } from "./conUtils";
33
import cryptoUtils from "./browserCrypto";
44
import { EdgeDBError } from "./errors";
55
import { FetchConnection } from "./fetchConn";
66
import { getHTTPSCRAMAuth } from "./httpScram";
77
import { Options } from "./options";
88

9-
const parseConnectArguments = getConnectArgumentsParser(null);
9+
const makeConnectArgumentsParser = (env: Record<string, string | undefined>) =>
10+
getConnectArgumentsParser(null, env);
1011
const httpSCRAMAuth = getHTTPSCRAMAuth(cryptoUtils);
1112

1213
class FetchClientPool extends BaseClientPool {
@@ -22,11 +23,12 @@ export function createClient(): Client {
2223
}
2324

2425
export function createHttpClient(
25-
options?: string | ConnectOptions | null
26+
options?: string | ConnectOptions | null,
27+
env: Record<string, string | undefined> = {}
2628
): Client {
2729
return new Client(
2830
new FetchClientPool(
29-
parseConnectArguments,
31+
makeConnectArgumentsParser(env),
3032
typeof options === "string" ? { dsn: options } : options ?? {}
3133
),
3234
Options.defaults()

packages/driver/src/conUtils.server.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,5 @@ export const serverUtils = {
5959
searchConfigDir: platform.searchConfigDir,
6060
};
6161

62-
export const parseConnectArguments = getConnectArgumentsParser(serverUtils);
62+
export const makeConnectArgumentsParser = () =>
63+
getConnectArgumentsParser(serverUtils, process.env);

packages/driver/src/conUtils.ts

Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,11 @@
1818

1919
import * as errors from "./errors";
2020
import {
21-
Credentials,
21+
type Credentials,
2222
getCredentialsPath,
2323
readCredentialsFile,
2424
validateCredentials,
2525
} from "./credentials";
26-
import { getEnv } from "./adapter.shared.node";
2726
import { Duration, parseHumanDurationString } from "./datatypes/datetime";
2827
import { checkValidEdgeDBDuration } from "./codecs/datetime";
2928
import { InterfaceError } from "./errors";
@@ -101,11 +100,12 @@ export type ConnectArgumentsParser = (
101100
) => Promise<NormalizedConnectConfig>;
102101

103102
export function getConnectArgumentsParser(
104-
utils: ServerUtils | null
103+
utils: ServerUtils | null,
104+
env: { [key: string]: string | undefined }
105105
): ConnectArgumentsParser {
106106
return async (opts: ConnectConfig) => {
107107
return {
108-
...(await parseConnectDsnAndArgs(opts, utils)),
108+
...(await parseConnectDsnAndArgs(opts, utils, env)),
109109
connectTimeout: opts.timeout,
110110
logging: opts.logging ?? true,
111111
};
@@ -156,8 +156,11 @@ export class ResolvedConnectConfig {
156156
_waitUntilAvailableSource: string | null = null;
157157

158158
serverSettings: { [key: string]: string } = {};
159+
env: { [key: string]: string | undefined } = {};
160+
161+
constructor(env: { [key: string]: string | undefined }) {
162+
this.env = env;
159163

160-
constructor() {
161164
this.setHost = this.setHost.bind(this);
162165
this.setPort = this.setPort.bind(this);
163166
this.setDatabase = this.setDatabase.bind(this);
@@ -271,7 +274,7 @@ export class ResolvedConnectConfig {
271274
.join(", ")}`
272275
);
273276
}
274-
const clientSecurity = getEnv("EDGEDB_CLIENT_SECURITY");
277+
const clientSecurity = this.env["EDGEDB_CLIENT_SECURITY"];
275278
if (clientSecurity !== undefined) {
276279
if (
277280
!["default", "insecure_dev_mode", "strict"].includes(clientSecurity)
@@ -483,9 +486,10 @@ export function parseDuration(duration: string | number | Duration): number {
483486

484487
async function parseConnectDsnAndArgs(
485488
config: ConnectConfig,
486-
serverUtils: ServerUtils | null
489+
serverUtils: ServerUtils | null,
490+
env: { [key: string]: string | undefined }
487491
): Promise<PartiallyNormalizedConfig> {
488-
const resolvedConfig = new ResolvedConnectConfig();
492+
const resolvedConfig = new ResolvedConnectConfig(env);
489493
let fromEnv = false;
490494
let fromProject = false;
491495

@@ -510,7 +514,7 @@ async function parseConnectDsnAndArgs(
510514
user: config.user,
511515
password: config.password,
512516
secretKey: config.secretKey,
513-
cloudProfile: getEnv("EDGEDB_CLOUD_PROFILE"),
517+
cloudProfile: env["EDGEDB_CLOUD_PROFILE"],
514518
tlsCA: config.tlsCA,
515519
tlsCAFile: config.tlsCAFile,
516520
tlsSecurity: config.tlsSecurity,
@@ -540,13 +544,14 @@ async function parseConnectDsnAndArgs(
540544
},
541545
`Cannot have more than one of the following connection options: ` +
542546
`'dsn', 'instanceName', 'credentials', 'credentialsFile' or 'host'/'port'`,
543-
serverUtils
547+
serverUtils,
548+
env
544549
);
545550

546551
if (!hasCompoundOptions) {
547552
// resolve config from env vars
548553

549-
let port: string | undefined = getEnv("EDGEDB_PORT");
554+
let port: string | undefined = env["EDGEDB_PORT"];
550555
if (resolvedConfig._port === null && port?.startsWith("tcp://")) {
551556
// EDGEDB_PORT is set by 'docker --link' so ignore and warn
552557
// tslint:disable-next-line: no-console
@@ -560,20 +565,20 @@ async function parseConnectDsnAndArgs(
560565
await resolveConfigOptions(
561566
resolvedConfig,
562567
{
563-
dsn: getEnv("EDGEDB_DSN"),
564-
instanceName: getEnv("EDGEDB_INSTANCE"),
565-
credentials: getEnv("EDGEDB_CREDENTIALS"),
566-
credentialsFile: getEnv("EDGEDB_CREDENTIALS_FILE"),
567-
host: getEnv("EDGEDB_HOST"),
568+
dsn: env["EDGEDB_DSN"],
569+
instanceName: env["EDGEDB_INSTANCE"],
570+
credentials: env["EDGEDB_CREDENTIALS"],
571+
credentialsFile: env["EDGEDB_CREDENTIALS_FILE"],
572+
host: env["EDGEDB_HOST"],
568573
port,
569-
database: getEnv("EDGEDB_DATABASE"),
570-
user: getEnv("EDGEDB_USER"),
571-
password: getEnv("EDGEDB_PASSWORD"),
572-
secretKey: getEnv("EDGEDB_SECRET_KEY"),
573-
tlsCA: getEnv("EDGEDB_TLS_CA"),
574-
tlsCAFile: getEnv("EDGEDB_TLS_CA_FILE"),
575-
tlsSecurity: getEnv("EDGEDB_CLIENT_TLS_SECURITY"),
576-
waitUntilAvailable: getEnv("EDGEDB_WAIT_UNTIL_AVAILABLE"),
574+
database: env["EDGEDB_DATABASE"],
575+
user: env["EDGEDB_USER"],
576+
password: env["EDGEDB_PASSWORD"],
577+
secretKey: env["EDGEDB_SECRET_KEY"],
578+
tlsCA: env["EDGEDB_TLS_CA"],
579+
tlsCAFile: env["EDGEDB_TLS_CA_FILE"],
580+
tlsSecurity: env["EDGEDB_CLIENT_TLS_SECURITY"],
581+
waitUntilAvailable: env["EDGEDB_WAIT_UNTIL_AVAILABLE"],
577582
},
578583
{
579584
dsn: `'EDGEDB_DSN' environment variable`,
@@ -594,7 +599,8 @@ async function parseConnectDsnAndArgs(
594599
`Cannot have more than one of the following connection environment variables: ` +
595600
`'EDGEDB_DSN', 'EDGEDB_INSTANCE', 'EDGEDB_CREDENTIALS', ` +
596601
`'EDGEDB_CREDENTIALS_FILE' or 'EDGEDB_HOST'`,
597-
serverUtils
602+
serverUtils,
603+
env
598604
));
599605
}
600606

@@ -643,7 +649,8 @@ async function parseConnectDsnAndArgs(
643649
database: `project default database`,
644650
},
645651
"",
646-
serverUtils
652+
serverUtils,
653+
env
647654
);
648655
fromProject = true;
649656
} else {
@@ -690,7 +697,8 @@ async function resolveConfigOptions<
690697
config: Config,
691698
sources: { [key in keyof Config]: string },
692699
compoundParamsError: string,
693-
serverUtils: ServerUtils | null
700+
serverUtils: ServerUtils | null,
701+
env: Record<string, string | undefined>
694702
): Promise<{ hasCompoundOptions: boolean; anyOptionsUsed: boolean }> {
695703
let anyOptionsUsed = false;
696704

@@ -780,7 +788,8 @@ async function resolveConfigOptions<
780788
: config.host !== undefined
781789
? sources.host!
782790
: sources.port!,
783-
readFile
791+
readFile,
792+
env
784793
);
785794
} else {
786795
let creds: Credentials;
@@ -848,13 +857,14 @@ async function parseDSNIntoConfig(
848857
_dsnString: string,
849858
config: ResolvedConnectConfig,
850859
source: string,
851-
readFile: (fn: string) => Promise<string>
860+
readFile: (fn: string) => Promise<string>,
861+
env: Record<string, string | undefined>
852862
): Promise<void> {
853863
// URL api does not support ipv6 zone ids, so extract zone id before parsing
854864
// https://url.spec.whatwg.org/#host-representation
855865
let dsnString = _dsnString;
856866
let regexHostname: string | null = null;
857-
let zoneId: string = "";
867+
let zoneId = "";
858868
const regexResult = /\[(.*?)(%25.+?)\]/.exec(_dsnString);
859869
if (regexResult) {
860870
regexHostname = regexResult[1];
@@ -920,15 +930,15 @@ async function parseDSNIntoConfig(
920930
let param = value || (searchParams.get(paramName) ?? null);
921931
let paramSource = source;
922932
if (param === null) {
923-
const env = searchParams.get(`${paramName}_env`);
924-
if (env != null) {
925-
param = getEnv(env, true) ?? null;
933+
const key = searchParams.get(`${paramName}_env`);
934+
if (key != null) {
935+
param = env[key] ?? null;
926936
if (param === null) {
927937
throw new InterfaceError(
928-
`'${paramName}_env' environment variable '${env}' doesn't exist`
938+
`'${paramName}_env' environment variable '${key}' doesn't exist`
929939
);
930940
}
931-
paramSource += ` (${paramName}_env: ${env})`;
941+
paramSource += ` (${paramName}_env: ${key})`;
932942
}
933943
}
934944
if (param === null) {

packages/driver/src/nodeClient.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
import { BaseClientPool, Client, ConnectOptions } from "./baseClient";
2-
import { parseConnectArguments } from "./conUtils.server";
1+
import { BaseClientPool, Client, type ConnectOptions } from "./baseClient";
2+
import { makeConnectArgumentsParser } from "./conUtils.server";
33
import cryptoUtils from "./adapter.crypto.node";
44
import { Options } from "./options";
55
import { RawConnection } from "./rawConn";
66
import { FetchConnection } from "./fetchConn";
77
import { getHTTPSCRAMAuth } from "./httpScram";
88

9+
const parseConnectArguments = makeConnectArgumentsParser();
10+
911
class ClientPool extends BaseClientPool {
1012
isStateless = false;
1113
_connectWithTimeout = RawConnection.connectWithTimeout.bind(RawConnection);

packages/driver/src/primitives/buffer.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,19 @@ let decodeB64: (b64: string) => Uint8Array;
3434
let encodeB64: (data: Uint8Array) => string;
3535

3636
// @ts-ignore: Buffer is not defined in Deno
37-
if (Buffer === "function") {
37+
globalThis.Buffer = globalThis.Buffer || undefined;
38+
39+
// @ts-ignore: Buffer is not defined in Deno
40+
if (globalThis.Buffer && globalThis.Buffer === "function") {
3841
decodeB64 = (b64: string): Uint8Array => {
3942
// @ts-ignore: Buffer is not defined in Deno
40-
return Buffer.from(b64, "base64");
43+
return globalThis.Buffer.from(b64, "base64");
4144
};
4245
encodeB64 = (data: Uint8Array): string => {
4346
// @ts-ignore: Buffer is not defined in Deno
44-
const buf = !Buffer.isBuffer(data)
47+
const buf = !globalThis.Buffer.isBuffer(data)
4548
? // @ts-ignore: Buffer is not defined in Deno
46-
Buffer.from(data.buffer, data.byteOffset, data.byteLength)
49+
globalThis.Buffer.from(data.buffer, data.byteOffset, data.byteLength)
4750
: data;
4851
return buf.toString("base64");
4952
};

0 commit comments

Comments
 (0)