@base44-preview/vite-plugin 1.0.48-pr.138.622eb14 → 1.0.48-pr.142.9fcc12e

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/README.md +24 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +8 -2
  4. package/dist/index.js.map +1 -1
  5. package/dist/private-data-sources/build-http.d.ts +9 -0
  6. package/dist/private-data-sources/build-http.d.ts.map +1 -0
  7. package/dist/private-data-sources/build-http.js +38 -0
  8. package/dist/private-data-sources/build-http.js.map +1 -0
  9. package/dist/private-data-sources/elasticsearch.d.ts +8 -0
  10. package/dist/private-data-sources/elasticsearch.d.ts.map +1 -0
  11. package/dist/private-data-sources/elasticsearch.js +6 -0
  12. package/dist/private-data-sources/elasticsearch.js.map +1 -0
  13. package/dist/private-data-sources/http-url.d.ts +10 -0
  14. package/dist/private-data-sources/http-url.d.ts.map +1 -0
  15. package/dist/private-data-sources/http-url.js +20 -0
  16. package/dist/private-data-sources/http-url.js.map +1 -0
  17. package/dist/private-data-sources/http.d.ts +8 -0
  18. package/dist/private-data-sources/http.d.ts.map +1 -0
  19. package/dist/private-data-sources/http.js +6 -0
  20. package/dist/private-data-sources/http.js.map +1 -0
  21. package/dist/private-data-sources/hyperdrive.d.ts +28 -0
  22. package/dist/private-data-sources/hyperdrive.d.ts.map +1 -0
  23. package/dist/private-data-sources/hyperdrive.js +39 -0
  24. package/dist/private-data-sources/hyperdrive.js.map +1 -0
  25. package/dist/private-data-sources/ioredis-adapter.d.ts +35 -0
  26. package/dist/private-data-sources/ioredis-adapter.d.ts.map +1 -0
  27. package/dist/private-data-sources/ioredis-adapter.js +203 -0
  28. package/dist/private-data-sources/ioredis-adapter.js.map +1 -0
  29. package/dist/private-data-sources/manifest.d.ts +7 -0
  30. package/dist/private-data-sources/manifest.d.ts.map +1 -0
  31. package/dist/private-data-sources/manifest.js +95 -0
  32. package/dist/private-data-sources/manifest.js.map +1 -0
  33. package/dist/private-data-sources/mariadb.d.ts +14 -0
  34. package/dist/private-data-sources/mariadb.d.ts.map +1 -0
  35. package/dist/private-data-sources/mariadb.js +6 -0
  36. package/dist/private-data-sources/mariadb.js.map +1 -0
  37. package/dist/private-data-sources/mongodb.d.ts +24 -0
  38. package/dist/private-data-sources/mongodb.d.ts.map +1 -0
  39. package/dist/private-data-sources/mongodb.js +52 -0
  40. package/dist/private-data-sources/mongodb.js.map +1 -0
  41. package/dist/private-data-sources/mysql.d.ts +14 -0
  42. package/dist/private-data-sources/mysql.d.ts.map +1 -0
  43. package/dist/private-data-sources/mysql.js +6 -0
  44. package/dist/private-data-sources/mysql.js.map +1 -0
  45. package/dist/private-data-sources/node-net-adapter.d.ts +20 -0
  46. package/dist/private-data-sources/node-net-adapter.d.ts.map +1 -0
  47. package/dist/private-data-sources/node-net-adapter.js +219 -0
  48. package/dist/private-data-sources/node-net-adapter.js.map +1 -0
  49. package/dist/private-data-sources/oracle.d.ts +20 -0
  50. package/dist/private-data-sources/oracle.d.ts.map +1 -0
  51. package/dist/private-data-sources/oracle.js +32 -0
  52. package/dist/private-data-sources/oracle.js.map +1 -0
  53. package/dist/private-data-sources/postgres.d.ts +14 -0
  54. package/dist/private-data-sources/postgres.d.ts.map +1 -0
  55. package/dist/private-data-sources/postgres.js +6 -0
  56. package/dist/private-data-sources/postgres.js.map +1 -0
  57. package/dist/private-data-sources/redis-auth.d.ts +3 -0
  58. package/dist/private-data-sources/redis-auth.d.ts.map +1 -0
  59. package/dist/private-data-sources/redis-auth.js +72 -0
  60. package/dist/private-data-sources/redis-auth.js.map +1 -0
  61. package/dist/private-data-sources/redis.d.ts +46 -0
  62. package/dist/private-data-sources/redis.d.ts.map +1 -0
  63. package/dist/private-data-sources/redis.js +27 -0
  64. package/dist/private-data-sources/redis.js.map +1 -0
  65. package/dist/private-data-sources/runtime-environment.d.ts +2 -0
  66. package/dist/private-data-sources/runtime-environment.d.ts.map +1 -0
  67. package/dist/private-data-sources/runtime-environment.js +6 -0
  68. package/dist/private-data-sources/runtime-environment.js.map +1 -0
  69. package/dist/private-data-sources/sqlserver.d.ts +18 -0
  70. package/dist/private-data-sources/sqlserver.d.ts.map +1 -0
  71. package/dist/private-data-sources/sqlserver.js +13 -0
  72. package/dist/private-data-sources/sqlserver.js.map +1 -0
  73. package/dist/private-data-sources/tcp.d.ts +29 -0
  74. package/dist/private-data-sources/tcp.d.ts.map +1 -0
  75. package/dist/private-data-sources/tcp.js +63 -0
  76. package/dist/private-data-sources/tcp.js.map +1 -0
  77. package/dist/private-data-sources/tedious-adapter.d.ts +2 -0
  78. package/dist/private-data-sources/tedious-adapter.d.ts.map +1 -0
  79. package/dist/private-data-sources/tedious-adapter.js +63 -0
  80. package/dist/private-data-sources/tedious-adapter.js.map +1 -0
  81. package/dist/private-data-sources/types.d.ts +27 -0
  82. package/dist/private-data-sources/types.d.ts.map +1 -0
  83. package/dist/private-data-sources/types.js +2 -0
  84. package/dist/private-data-sources/types.js.map +1 -0
  85. package/dist/private-data-sources-plugin.d.ts +3 -0
  86. package/dist/private-data-sources-plugin.d.ts.map +1 -0
  87. package/dist/private-data-sources-plugin.js +51 -0
  88. package/dist/private-data-sources-plugin.js.map +1 -0
  89. package/package.json +1 -1
  90. package/src/index.ts +9 -2
  91. package/src/private-data-sources/build-http.ts +51 -0
  92. package/src/private-data-sources/cloudflare-workers.d.ts +3 -0
  93. package/src/private-data-sources/elasticsearch.ts +8 -0
  94. package/src/private-data-sources/http-url.ts +23 -0
  95. package/src/private-data-sources/http.ts +6 -0
  96. package/src/private-data-sources/hyperdrive.ts +48 -0
  97. package/src/private-data-sources/ioredis-adapter.ts +229 -0
  98. package/src/private-data-sources/manifest.ts +127 -0
  99. package/src/private-data-sources/mariadb.ts +8 -0
  100. package/src/private-data-sources/mongodb.ts +70 -0
  101. package/src/private-data-sources/mysql.ts +8 -0
  102. package/src/private-data-sources/node-net-adapter.ts +247 -0
  103. package/src/private-data-sources/oracle.ts +34 -0
  104. package/src/private-data-sources/postgres.ts +8 -0
  105. package/src/private-data-sources/redis-auth.ts +83 -0
  106. package/src/private-data-sources/redis.ts +47 -0
  107. package/src/private-data-sources/runtime-environment.ts +6 -0
  108. package/src/private-data-sources/sqlserver.ts +22 -0
  109. package/src/private-data-sources/tcp.ts +86 -0
  110. package/src/private-data-sources/tedious-adapter.ts +67 -0
  111. package/src/private-data-sources/types.ts +29 -0
  112. package/src/private-data-sources-plugin.ts +55 -0
@@ -0,0 +1,23 @@
1
+ import type { PrivateDataSourceManifestEntry } from "./types.js";
2
+
3
+ const FALLBACK_BASE_URL = "http://private-data-source.local";
4
+
5
+ /**
6
+ * Resolve a fetch target for an HTTP private data source. Relative paths resolve
7
+ * against the source's base URL; absolute URLs pass through. There is no host
8
+ * allowlist: for a fixed VPC service Cloudflare pins the single target, and for a
9
+ * network binding the reachable set is the customer's tunnel scope — the app can
10
+ * fetch any host behind it (e.g. Trino router + cluster nextUri hosts).
11
+ */
12
+ export function resolveHttpPrivateDataSourceUrl(
13
+ entry: PrivateDataSourceManifestEntry,
14
+ resource: RequestInfo | URL,
15
+ ): RequestInfo | URL {
16
+ if (resource instanceof Request) return resource;
17
+ const raw = resource instanceof URL ? resource.toString() : String(resource);
18
+ try {
19
+ return new URL(raw).toString();
20
+ } catch {
21
+ return new URL(raw || "/", entry.baseUrl || FALLBACK_BASE_URL).toString();
22
+ }
23
+ }
@@ -0,0 +1,6 @@
1
+ import { buildHttpPrivateDataSource } from "./build-http.js";
2
+ import { privateDataSourceReference } from "./manifest.js";
3
+
4
+ export function http(name: unknown) {
5
+ return buildHttpPrivateDataSource(privateDataSourceReference(name, "http"));
6
+ }
@@ -0,0 +1,48 @@
1
+ import {
2
+ currentPrivateDataSource,
3
+ privateDataSourceReference,
4
+ privateDataSourceBinding,
5
+ } from "./manifest.js";
6
+ import type { PrivateDataSourceManifestEntry } from "./types.js";
7
+
8
+ export function buildHyperdrivePrivateDataSource(entry: PrivateDataSourceManifestEntry) {
9
+ const binding = () =>
10
+ privateDataSourceBinding(entry) as Record<string, unknown>;
11
+ return Object.freeze({
12
+ name: entry.name,
13
+ type: entry.type,
14
+ get bindingName() {
15
+ return currentPrivateDataSource(entry).bindingName;
16
+ },
17
+ get connectionString() {
18
+ return binding().connectionString;
19
+ },
20
+ get host() {
21
+ return binding().host;
22
+ },
23
+ get port() {
24
+ return binding().port;
25
+ },
26
+ get user() {
27
+ return binding().user;
28
+ },
29
+ get username() {
30
+ return binding().user;
31
+ },
32
+ get password() {
33
+ return binding().password;
34
+ },
35
+ get database() {
36
+ return binding().database;
37
+ },
38
+ get binding() {
39
+ return binding();
40
+ },
41
+ });
42
+ }
43
+
44
+ export function hyperdrive(name: unknown) {
45
+ return buildHyperdrivePrivateDataSource(
46
+ privateDataSourceReference(name, "hyperdrive"),
47
+ );
48
+ }
@@ -0,0 +1,229 @@
1
+ import { Buffer } from "node:buffer";
2
+ import { EventEmitter } from "node:events";
3
+
4
+ import { isCloudflareTcpSocket } from "./tcp.js";
5
+
6
+ type IoredisErrorEmitter = (type: string, err: Error) => void;
7
+
8
+ export interface IoredisNetStream extends EventEmitter {
9
+ connecting: boolean;
10
+ destroyed: boolean;
11
+ readable: boolean;
12
+ writable: boolean;
13
+ remoteAddress?: string;
14
+ remotePort?: number;
15
+ _writableState: { ended: boolean };
16
+ write(data: string | Uint8Array, callback?: (err?: Error | null) => void): boolean;
17
+ end(data?: string | Uint8Array | (() => void), callback?: () => void): IoredisNetStream;
18
+ destroy(error?: Error): IoredisNetStream;
19
+ setNoDelay(noDelay?: boolean): IoredisNetStream;
20
+ setKeepAlive(enable?: boolean, initialDelay?: number): IoredisNetStream;
21
+ setTimeout(timeout: number, callback?: () => void): IoredisNetStream;
22
+ resume(): IoredisNetStream;
23
+ pause(): IoredisNetStream;
24
+ }
25
+
26
+ function exactNodeBuffer(value: Uint8Array): Buffer {
27
+ const bytes = new Uint8Array(value.byteLength);
28
+ bytes.set(value);
29
+ return Buffer.from(bytes.buffer);
30
+ }
31
+
32
+ function buildIoredisNetStream(
33
+ socket: unknown,
34
+ errorEmitter?: IoredisErrorEmitter,
35
+ ): IoredisNetStream {
36
+ if (!isCloudflareTcpSocket(socket)) {
37
+ throw new Error("Redis private data source did not return a readable/writable TCP socket");
38
+ }
39
+ const cloudflareSocket = socket;
40
+
41
+ const encoder = new TextEncoder();
42
+ const stream = new EventEmitter() as IoredisNetStream;
43
+ let reader: ReadableStreamDefaultReader<Uint8Array> | null = null;
44
+ let writer: WritableStreamDefaultWriter<Uint8Array> | null = null;
45
+ let readStarted = false;
46
+ let connectEmitted = false;
47
+ let closed = false;
48
+ let timeout: ReturnType<typeof setTimeout> | null = null;
49
+ let writeChain = Promise.resolve();
50
+
51
+ function setClosed() {
52
+ if (closed) return;
53
+ closed = true;
54
+ stream.destroyed = true;
55
+ stream.readable = false;
56
+ stream.writable = false;
57
+ stream._writableState.ended = true;
58
+ if (timeout) {
59
+ clearTimeout(timeout);
60
+ timeout = null;
61
+ }
62
+ try {
63
+ reader?.releaseLock();
64
+ } catch {
65
+ // Ignore release errors when the stream is already closed.
66
+ }
67
+ reader = null;
68
+ try {
69
+ writer?.releaseLock();
70
+ } catch {
71
+ // Ignore release errors when the stream is already closed.
72
+ }
73
+ writer = null;
74
+ stream.emit("close");
75
+ }
76
+
77
+ function emitError(error: unknown) {
78
+ const err = error instanceof Error ? error : new Error(String(error));
79
+ errorEmitter?.("error", err);
80
+ stream.emit("error", err);
81
+ }
82
+
83
+ function markConnected() {
84
+ if (closed || connectEmitted) return;
85
+ connectEmitted = true;
86
+ stream.connecting = false;
87
+ stream.emit("connect");
88
+ }
89
+
90
+ async function readLoop() {
91
+ const activeReader = reader ?? cloudflareSocket.readable.getReader();
92
+ reader = activeReader;
93
+ try {
94
+ while (!closed) {
95
+ const { value, done } = await activeReader.read();
96
+ if (done) break;
97
+ if (value) stream.emit("data", exactNodeBuffer(value));
98
+ }
99
+ setClosed();
100
+ } catch (error) {
101
+ if (!closed) {
102
+ emitError(error);
103
+ setClosed();
104
+ }
105
+ }
106
+ }
107
+
108
+ function writeBytes(bytes: Uint8Array) {
109
+ if (closed) return Promise.reject(new Error("Redis connection is closed"));
110
+ const activeWriter = writer ?? cloudflareSocket.writable.getWriter();
111
+ writer = activeWriter;
112
+ return activeWriter.write(bytes);
113
+ }
114
+
115
+ stream.connecting = true;
116
+ stream.destroyed = false;
117
+ stream.readable = true;
118
+ stream.writable = true;
119
+ stream._writableState = { ended: false };
120
+ stream.write = (data, callback) => {
121
+ const bytes = typeof data === "string" ? encoder.encode(data) : data;
122
+ writeChain = writeChain
123
+ .then(() => writeBytes(bytes))
124
+ .then(
125
+ () => callback?.(),
126
+ (error) => {
127
+ const err = error instanceof Error ? error : new Error(String(error));
128
+ callback?.(err);
129
+ emitError(err);
130
+ },
131
+ );
132
+ return true;
133
+ };
134
+ stream.end = (data?: string | Uint8Array | (() => void), callback?: () => void) => {
135
+ const done = typeof data === "function" ? data : callback;
136
+ if (typeof data === "string" || data instanceof Uint8Array) {
137
+ stream.write(data);
138
+ }
139
+ writeChain
140
+ .finally(() => {
141
+ done?.();
142
+ try {
143
+ cloudflareSocket.close?.();
144
+ } finally {
145
+ setClosed();
146
+ }
147
+ })
148
+ .catch(() => {});
149
+ return stream;
150
+ };
151
+ stream.destroy = (error?: Error) => {
152
+ if (error) emitError(error);
153
+ try {
154
+ cloudflareSocket.close?.();
155
+ } finally {
156
+ setClosed();
157
+ }
158
+ return stream;
159
+ };
160
+ stream.setNoDelay = () => stream;
161
+ stream.setKeepAlive = () => stream;
162
+ stream.setTimeout = (duration, callback) => {
163
+ if (timeout) clearTimeout(timeout);
164
+ timeout = null;
165
+ if (duration > 0) {
166
+ timeout = setTimeout(() => {
167
+ callback?.();
168
+ stream.emit("timeout");
169
+ }, duration);
170
+ }
171
+ return stream;
172
+ };
173
+ stream.resume = () => {
174
+ if (!readStarted) {
175
+ readStarted = true;
176
+ readLoop();
177
+ }
178
+ return stream;
179
+ };
180
+ stream.pause = () => stream;
181
+
182
+ if (cloudflareSocket.opened) {
183
+ cloudflareSocket.opened.then(markConnected, (error) => {
184
+ emitError(error);
185
+ stream.destroy(error instanceof Error ? error : new Error(String(error)));
186
+ });
187
+ } else {
188
+ queueMicrotask(markConnected);
189
+ }
190
+ cloudflareSocket.closed?.finally(setClosed).catch(() => {});
191
+ return stream;
192
+ }
193
+
194
+ export function buildIoredisConnectorFactory(connect: () => unknown) {
195
+ return class Base44IoredisConnector {
196
+ firstError?: Error;
197
+ #stream: IoredisNetStream | undefined;
198
+ #disconnectTimeout: number;
199
+
200
+ constructor(options?: { disconnectTimeout?: number }) {
201
+ this.#disconnectTimeout =
202
+ typeof options?.disconnectTimeout === "number" ? options.disconnectTimeout : 2000;
203
+ }
204
+
205
+ check() {
206
+ return true;
207
+ }
208
+
209
+ connect(errorEmitter?: IoredisErrorEmitter) {
210
+ return Promise.resolve(connect()).then((socket) => {
211
+ try {
212
+ this.#stream = buildIoredisNetStream(socket, errorEmitter);
213
+ return this.#stream;
214
+ } catch (error) {
215
+ this.firstError = error instanceof Error ? error : new Error(String(error));
216
+ throw this.firstError;
217
+ }
218
+ });
219
+ }
220
+
221
+ disconnect() {
222
+ const stream = this.#stream;
223
+ if (!stream || stream.destroyed) return;
224
+ const timeout = setTimeout(() => stream.destroy(), this.#disconnectTimeout);
225
+ stream.once("close", () => clearTimeout(timeout));
226
+ stream.end();
227
+ }
228
+ };
229
+ }
@@ -0,0 +1,127 @@
1
+ import { workerEnvironment } from "./runtime-environment.js";
2
+ import type { PrivateDataSourceManifestEntry } from "./types.js";
3
+
4
+ const PRIVATE_DATA_SOURCES_MANIFEST_ENV = "BASE44_PRIVATE_DATA_SOURCES";
5
+
6
+ function readStringVar(key: string): string | undefined {
7
+ const value = workerEnvironment()[key];
8
+ return typeof value === "string" ? value : undefined;
9
+ }
10
+
11
+ // The manifest is a Worker binding frozen with the script's Hyperdrive/VPC bindings,
12
+ // so every entry it lists has its binding on this worker.
13
+ function parsePrivateDataSourceManifest(): PrivateDataSourceManifestEntry[] {
14
+ const raw = readStringVar(PRIVATE_DATA_SOURCES_MANIFEST_ENV);
15
+ if (!raw) return [];
16
+ let parsed: unknown;
17
+ try {
18
+ parsed = JSON.parse(raw);
19
+ } catch {
20
+ return [];
21
+ }
22
+ return Array.isArray(parsed)
23
+ ? parsed.filter(
24
+ (entry): entry is PrivateDataSourceManifestEntry =>
25
+ entry !== null && typeof entry === "object",
26
+ )
27
+ : [];
28
+ }
29
+
30
+ export function normalizePrivateDataSourceKey(value: unknown): string {
31
+ return String(value || "")
32
+ .trim()
33
+ .toLowerCase()
34
+ .replace(/[^a-z0-9]+/g, "_")
35
+ .replace(/^_+|_+$/g, "");
36
+ }
37
+
38
+ export function privateDataSourceReference(
39
+ requestedName: unknown,
40
+ expectedType: string,
41
+ ): PrivateDataSourceManifestEntry {
42
+ return lookupPrivateDataSource(requestedName, expectedType);
43
+ }
44
+
45
+ function privateDataSourceMatchRank(
46
+ entry: PrivateDataSourceManifestEntry,
47
+ requestedName: unknown,
48
+ ): number | null {
49
+ const requested = String(requestedName || "");
50
+ const normalizedRequested = normalizePrivateDataSourceKey(requested);
51
+ const candidates = [
52
+ { value: entry.name, rank: 0 },
53
+ { value: entry.bindingName, rank: 1 },
54
+ { value: entry.name, rank: 2, normalized: true },
55
+ { value: entry.bindingName, rank: 3, normalized: true },
56
+ ];
57
+ let bestRank: number | null = null;
58
+ for (const candidate of candidates) {
59
+ if (typeof candidate.value !== "string") continue;
60
+ const matches = candidate.normalized
61
+ ? normalizePrivateDataSourceKey(candidate.value) === normalizedRequested
62
+ : candidate.value === requested;
63
+ if (matches && (bestRank === null || candidate.rank < bestRank)) {
64
+ bestRank = candidate.rank;
65
+ }
66
+ }
67
+ return bestRank;
68
+ }
69
+
70
+ function privateDataSourceMatchesExpectedType(
71
+ entry: PrivateDataSourceManifestEntry,
72
+ expectedType: string,
73
+ ): boolean {
74
+ return entry.type === expectedType || (expectedType === "hyperdrive" && entry.bindingKind === "hyperdrive");
75
+ }
76
+
77
+ export function lookupPrivateDataSource(
78
+ requestedName: unknown,
79
+ expectedType?: string,
80
+ ): PrivateDataSourceManifestEntry {
81
+ const matches = parsePrivateDataSourceManifest()
82
+ .map((entry) => ({ entry, rank: privateDataSourceMatchRank(entry, requestedName) }))
83
+ .filter((match): match is { entry: PrivateDataSourceManifestEntry; rank: number } => match.rank !== null)
84
+ .sort((a, b) => a.rank - b.rank);
85
+ if (matches.length === 0) {
86
+ throw new Error(
87
+ `Private data source "${requestedName}" is not bound to this app. Private data sources are available on the published app, not in the editor's live preview`,
88
+ );
89
+ }
90
+
91
+ const typeMatches = expectedType
92
+ ? matches.filter((candidate) => privateDataSourceMatchesExpectedType(candidate.entry, expectedType))
93
+ : matches;
94
+ const [best] = typeMatches;
95
+ if (!best) {
96
+ throw new Error(`Private data source "${requestedName}" is not a ${expectedType} data source`);
97
+ }
98
+
99
+ const bestMatches = typeMatches.filter((candidate) => candidate.rank === best.rank);
100
+ if (bestMatches.length > 1) {
101
+ const kind = expectedType ? ` ${expectedType}` : "";
102
+ throw new Error(
103
+ `Private data source "${requestedName}" is ambiguous: ${bestMatches.length}${kind} data sources match this name`,
104
+ );
105
+ }
106
+ return best.entry;
107
+ }
108
+
109
+ export function privateDataSourceBinding(entry: PrivateDataSourceManifestEntry): unknown {
110
+ const current = lookupPrivateDataSource(entry.name, entry.type);
111
+ if (!current.bindingName) {
112
+ throw new Error(`Private data source "${current.name}" has no Worker binding name`);
113
+ }
114
+ const binding = workerEnvironment()[current.bindingName];
115
+ if (!binding) {
116
+ throw new Error(
117
+ `Private data source binding "${current.bindingName}" is missing from the Worker environment`,
118
+ );
119
+ }
120
+ return binding;
121
+ }
122
+
123
+ export function currentPrivateDataSource(
124
+ entry: PrivateDataSourceManifestEntry,
125
+ ): PrivateDataSourceManifestEntry {
126
+ return lookupPrivateDataSource(entry.name, entry.type);
127
+ }
@@ -0,0 +1,8 @@
1
+ import { buildHyperdrivePrivateDataSource } from "./hyperdrive.js";
2
+ import { privateDataSourceReference } from "./manifest.js";
3
+
4
+ export function mariadb(name: unknown) {
5
+ return buildHyperdrivePrivateDataSource(
6
+ privateDataSourceReference(name, "mariadb"),
7
+ );
8
+ }
@@ -0,0 +1,70 @@
1
+ import {
2
+ currentPrivateDataSource,
3
+ normalizePrivateDataSourceKey,
4
+ privateDataSourceReference,
5
+ } from "./manifest.js";
6
+ import { buildTcpPrivateDataSource } from "./tcp.js";
7
+ import { installPrivateNodeNetAdapter, registerPrivateNodeNetRoute } from "./node-net-adapter.js";
8
+ import type { PrivateDataSourceManifestEntry } from "./types.js";
9
+
10
+ function encodeMongoConnectionPart(value: unknown): string {
11
+ return encodeURIComponent(String(value ?? ""));
12
+ }
13
+
14
+ function buildMongoConnectionString(entry: PrivateDataSourceManifestEntry, hostname: string): string {
15
+ const username = entry.username ? encodeMongoConnectionPart(entry.username) : "";
16
+ const password = entry.password ? encodeMongoConnectionPart(entry.password) : "";
17
+ const auth = username ? `${username}${password ? `:${password}` : ""}@` : "";
18
+ const database = entry.database ? `/${encodeMongoConnectionPart(entry.database)}` : "";
19
+ const port = typeof entry.port === "number" ? entry.port : 27017;
20
+ return `mongodb://${auth}${hostname}:${port}${database}?directConnection=true`;
21
+ }
22
+
23
+ export function mongodb(name: unknown) {
24
+ installPrivateNodeNetAdapter();
25
+ const entry = privateDataSourceReference(name, "mongodb");
26
+ const source = buildTcpPrivateDataSource(entry) as ReturnType<typeof buildTcpPrivateDataSource> & {
27
+ connect: (options?: unknown) => unknown;
28
+ };
29
+ const driverHostname = `base44-private-${normalizePrivateDataSourceKey(
30
+ entry.bindingName || entry.name || "mongodb",
31
+ )}`;
32
+
33
+ function registerRoute() {
34
+ const current = currentPrivateDataSource(entry);
35
+ const port = typeof current.port === "number" ? current.port : 27017;
36
+ const label = `MongoDB private data source "${current.name || current.bindingName || driverHostname}"`;
37
+ registerPrivateNodeNetRoute(driverHostname, port, {
38
+ label,
39
+ connect: () => source.connect(),
40
+ });
41
+ }
42
+
43
+ const extension = {
44
+ driverHost: driverHostname,
45
+ get connectionString() {
46
+ const current = currentPrivateDataSource(entry);
47
+ registerRoute();
48
+ return buildMongoConnectionString(current, driverHostname);
49
+ },
50
+ get uri() {
51
+ const current = currentPrivateDataSource(entry);
52
+ registerRoute();
53
+ return buildMongoConnectionString(current, driverHostname);
54
+ },
55
+ mongoClientOptions(options?: Record<string, unknown>) {
56
+ registerRoute();
57
+ return Object.freeze({
58
+ directConnection: true,
59
+ serverSelectionTimeoutMS: 5000,
60
+ ...options,
61
+ });
62
+ },
63
+ };
64
+ return Object.freeze(
65
+ Object.defineProperties(
66
+ extension,
67
+ Object.getOwnPropertyDescriptors(source),
68
+ ) as typeof source & typeof extension,
69
+ );
70
+ }
@@ -0,0 +1,8 @@
1
+ import { buildHyperdrivePrivateDataSource } from "./hyperdrive.js";
2
+ import { privateDataSourceReference } from "./manifest.js";
3
+
4
+ export function mysql(name: unknown) {
5
+ return buildHyperdrivePrivateDataSource(
6
+ privateDataSourceReference(name, "mysql"),
7
+ );
8
+ }