@lunora/hyperdrive 1.0.0-alpha.225 → 1.0.0-alpha.227
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.
- package/README.md +25 -7
- package/dist/global.d.mts +21 -11
- package/dist/global.d.ts +21 -11
- package/dist/global.mjs +1 -1
- package/dist/index.d.mts +22 -12
- package/dist/index.d.ts +22 -12
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/buildMysqlExec-DX34snyg.mjs +1 -0
- package/dist/packem_shared/createHyperdrive-Bw1Au7bE.mjs +1 -0
- package/dist/packem_shared/mysql-params-BYlr9fFZ.mjs +1 -0
- package/dist/packem_shared/{types.d-DKB5Qb1Z.d.ts → types.d-DmkKECp5.d.mts} +3 -2
- package/dist/packem_shared/{types.d-DKB5Qb1Z.d.mts → types.d-DmkKECp5.d.ts} +3 -2
- package/package.json +4 -4
- package/dist/packem_shared/buildMysqlExec-DrnJfCYF.mjs +0 -1
- package/dist/packem_shared/createHyperdrive-HbpYCCgt.mjs +0 -1
- package/dist/packem_shared/mysql-params-D4Ijlvo5.mjs +0 -1
package/README.md
CHANGED
|
@@ -95,18 +95,25 @@ Prefer to manage it yourself? Run `wrangler hyperdrive create my-db --connection
|
|
|
95
95
|
// src/server/index.ts
|
|
96
96
|
import type { HyperdriveLike } from "@lunora/hyperdrive";
|
|
97
97
|
import { createHyperdrive, fromPostgresJs } from "@lunora/hyperdrive";
|
|
98
|
-
import postgres from "postgres";
|
|
99
98
|
|
|
100
99
|
import { defineApp } from "../../lunora/_generated/app";
|
|
101
100
|
|
|
102
101
|
const app = defineApp<Env>()
|
|
103
102
|
.shard((env) => env.SHARD)
|
|
104
|
-
.hyperdrive((env) =>
|
|
103
|
+
.hyperdrive((env) =>
|
|
104
|
+
fromPostgresJs(async () => {
|
|
105
|
+
const { default: postgres } = await import("postgres");
|
|
106
|
+
|
|
107
|
+
return postgres(createHyperdrive(env.HYPERDRIVE as HyperdriveLike).connectionString, { fetch_types: false, max: 5 });
|
|
108
|
+
}),
|
|
109
|
+
)
|
|
105
110
|
.build();
|
|
106
111
|
|
|
107
112
|
export const ShardDO = app.ShardDO;
|
|
108
113
|
```
|
|
109
114
|
|
|
115
|
+
The adapter takes a loader, not a driver: it runs on the first query and the client is reused, so the driver stays out of the Worker's startup graph. A static `import postgres from "postgres"` in the entry is evaluated at startup and defeats this. A failed load rejects that query; the next one retries. For `pg`, the loader may `await client.connect()` before returning.
|
|
116
|
+
|
|
110
117
|
Hand-composing the worker instead? The same thunk is `createShardDO({ sql: (env) => … })`. Without it, every `ctx.sql` method throws a message pointing back at this wiring.
|
|
111
118
|
|
|
112
119
|
Handlers then just read it. The procedure builders (`action`, `v`) and `api` come from your app-local generated modules:
|
|
@@ -157,7 +164,13 @@ Supply the driver once, on the app builder — required, or every tick records `
|
|
|
157
164
|
```ts
|
|
158
165
|
export default defineApp<Env>()
|
|
159
166
|
.shard((env) => env.SHARD)
|
|
160
|
-
.sourceClient((env, binding) =>
|
|
167
|
+
.sourceClient((env, binding) =>
|
|
168
|
+
fromPostgresJs(async () => {
|
|
169
|
+
const { default: postgres } = await import("postgres");
|
|
170
|
+
|
|
171
|
+
return postgres((env[binding] as { connectionString: string }).connectionString, { fetch_types: false, max: 5 });
|
|
172
|
+
}),
|
|
173
|
+
)
|
|
161
174
|
.build();
|
|
162
175
|
```
|
|
163
176
|
|
|
@@ -178,13 +191,18 @@ The `@lunora/hyperdrive/global` subpath is the opposite trade-off: Lunora **owns
|
|
|
178
191
|
```ts
|
|
179
192
|
import { fromPostgresJs } from "@lunora/hyperdrive";
|
|
180
193
|
import { createPostgresGlobalCtxDb } from "@lunora/hyperdrive/global";
|
|
181
|
-
import postgres from "postgres";
|
|
182
194
|
|
|
183
|
-
const
|
|
184
|
-
|
|
195
|
+
const globalDb = createPostgresGlobalCtxDb(
|
|
196
|
+
fromPostgresJs(async () => {
|
|
197
|
+
const { default: postgres } = await import("postgres");
|
|
198
|
+
|
|
199
|
+
return postgres(env.HYPERDRIVE.connectionString, { fetch_types: false, max: 5 });
|
|
200
|
+
}),
|
|
201
|
+
{ schema },
|
|
202
|
+
);
|
|
185
203
|
```
|
|
186
204
|
|
|
187
|
-
For MySQL use `createMysqlGlobalCtxDb` with a `mysql2/promise` pool created with `disableEval: true` (required on Workers) and `flags: ["FOUND_ROWS"]` — without `CLIENT_FOUND_ROWS` the affected-rows OCC guard sees changed (not matched) rows and raises spurious conflicts. Lower-level building blocks (`buildPgExec`, `buildMysqlExec`, `postgresDialect`, `mysqlDialect`, `createHyperdriveGlobalCtxDb`) are exported for custom wiring.
|
|
205
|
+
For MySQL use `createMysqlGlobalCtxDb` with a loader returning a `mysql2/promise` pool created with `disableEval: true` (required on Workers) and `flags: ["FOUND_ROWS"]` (`import()` the driver inside it, as with `fromMysql2`) — without `CLIENT_FOUND_ROWS` the affected-rows OCC guard sees changed (not matched) rows and raises spurious conflicts. Lower-level building blocks (`buildPgExec`, `buildMysqlExec`, `postgresDialect`, `mysqlDialect`, `createHyperdriveGlobalCtxDb`) are exported for custom wiring.
|
|
188
206
|
|
|
189
207
|
The Hyperdrive config behind `.global()` must have **query caching disabled** (`wrangler hyperdrive create … --caching-disabled`, or `wrangler hyperdrive update <id> --caching-disabled`). Hyperdrive caches reads for up to 75 s by default and writes don't invalidate them, so the store's OCC re-reads, change-log polls and live-query re-runs would see stale rows. `lunora deploy` sets this on the configs it creates when the schema has `.global({ backend: "hyperdrive" })` tables, and warns about an already-bound config that still caches (when Cloudflare API credentials are set).
|
|
190
208
|
|
package/dist/global.d.mts
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
*/
|
|
31
31
|
import { SchemaLike, ImportConflictMode, CdcChange, DatabaseWriterLike } from '@lunora/shard-engine';
|
|
32
32
|
import { SqlExec, SqlDialect, SqlCtxDbOptions, FacetGlobalColumnOptions, GlobalFacetResult, GlobalTableInfo, ReadGlobalTablePageOptions, GlobalTablePage, ExportRow, ImportResult } from '@lunora/sql-store';
|
|
33
|
-
import { M as Mysql2Like, S as SqlClient } from "./packem_shared/types.d-
|
|
33
|
+
import { M as Mysql2Like, S as SqlClient } from "./packem_shared/types.d-DmkKECp5.mjs";
|
|
34
34
|
import { VectorMetric, VectorizeIndexLike } from '@lunora/platform';
|
|
35
35
|
/**
|
|
36
36
|
* Minimal row-returning client (e.g. `@lunora/hyperdrive`'s `fromPostgresJs`/`fromNodePg`
|
|
@@ -97,10 +97,11 @@ type Mysql2Client = Mysql2Like & {
|
|
|
97
97
|
*/
|
|
98
98
|
declare const buildPgExec: (client: RowClient) => SqlExec;
|
|
99
99
|
/**
|
|
100
|
-
* Wrap a `mysql2/promise` connection/pool
|
|
101
|
-
* renders backtick identifiers and `?`
|
|
102
|
-
*
|
|
103
|
-
* for the store's affected-rows
|
|
100
|
+
* Wrap a `mysql2/promise` connection/pool, built by `load` on the first statement,
|
|
101
|
+
* as a {@link SqlExec}. The core already renders backtick identifiers and `?`
|
|
102
|
+
* placeholders for MySQL, so `all`/`run` forward verbatim. MySQL has no
|
|
103
|
+
* `RETURNING`, so `run` surfaces `affectedRows` for the store's affected-rows
|
|
104
|
+
* OCC guard.
|
|
104
105
|
*
|
|
105
106
|
* Statements go over as text with client-side escaping, so the server must not
|
|
106
107
|
* run with `NO_BACKSLASH_ESCAPES` (see {@link Mysql2Like}).
|
|
@@ -109,12 +110,21 @@ declare const buildPgExec: (client: RowClient) => SqlExec;
|
|
|
109
110
|
* (mysql2: `createPool({ flags: ["FOUND_ROWS"] })`). Without it, `affectedRows`
|
|
110
111
|
* counts *changed* rows, so an idempotent `patch`/`replace` that re-writes the
|
|
111
112
|
* same values reports 0 and the OCC guard raises a spurious conflict. Verified
|
|
112
|
-
*
|
|
113
|
+
* when the loader resolves — see {@link assertFoundRows} — never per statement. A
|
|
114
|
+
* connection without the flag fails that statement and is not kept, so every
|
|
115
|
+
* later statement fails the same way rather than running unguarded.
|
|
116
|
+
*
|
|
117
|
+
* `load` runs on the first statement, not here: `.hyperdriveGlobal`'s `exec(env)`
|
|
118
|
+
* is built with the request's ctx, which can precede the mutation's input-gated
|
|
119
|
+
* span. The `import("mysql2/promise")` inside the loader must start inside that
|
|
120
|
+
* span and finish there, as `buildPgExec(fromPostgresJs(load))` does, so a load
|
|
121
|
+
* begun outside the gate is never awaited inside it.
|
|
113
122
|
*
|
|
114
123
|
* Given a **pool** (anything with `getConnection`), `transaction` takes one
|
|
115
124
|
* connection for the store's row + companion writes, so they commit together.
|
|
116
|
-
* A single connection
|
|
117
|
-
*
|
|
125
|
+
* A single connection cannot hold one apart from other writers' statements, so
|
|
126
|
+
* `transaction` is present but rejects with `GLOBAL_TRANSACTION_UNSUPPORTED`: a
|
|
127
|
+
* write to a table with companions fails before it writes anything.
|
|
118
128
|
*
|
|
119
129
|
* `batch` dispatches every statement concurrently (`Promise.all`), same
|
|
120
130
|
* rationale as {@link buildPgExec}'s `batch` — `Mysql2Like` only exposes a
|
|
@@ -123,7 +133,7 @@ declare const buildPgExec: (client: RowClient) => SqlExec;
|
|
|
123
133
|
* at-least-once, and unordered between elements, safe only for statements
|
|
124
134
|
* with no cross-effect (what every current caller batches).
|
|
125
135
|
*/
|
|
126
|
-
declare const buildMysqlExec: (
|
|
136
|
+
declare const buildMysqlExec: (load: () => Mysql2Client | Promise<Mysql2Client>) => SqlExec;
|
|
127
137
|
/**
|
|
128
138
|
* **Postgres** dialect. Differs from SQLite only in column types
|
|
129
139
|
* (`DOUBLE PRECISION`/`BYTEA`/`BIGSERIAL`), the `information_schema` catalog
|
|
@@ -225,8 +235,8 @@ interface ImportHyperdriveGlobalRowsOptions {
|
|
|
225
235
|
declare const importHyperdriveGlobalRows: ({ cdc, dryRun, engine, exec, onConflict, rows, schema, startLine }: ImportHyperdriveGlobalRowsOptions) => Promise<ImportResult>;
|
|
226
236
|
/** Convenience: a **Postgres** `.global()` writer from a row-client (postgres.js/pg over Hyperdrive). */
|
|
227
237
|
declare const createPostgresGlobalCtxDb: (client: RowClient, options: Omit<CreateHyperdriveGlobalCtxDbOptions, "engine" | "exec">) => DatabaseWriterLike;
|
|
228
|
-
/** Convenience: a **MySQL** `.global()` writer
|
|
229
|
-
declare const createMysqlGlobalCtxDb: (
|
|
238
|
+
/** Convenience: a **MySQL** `.global()` writer over a `mysql2/promise` connection/pool (created with `disableEval: true` and `flags: ["FOUND_ROWS"]`) that `load` builds on the first statement. */
|
|
239
|
+
declare const createMysqlGlobalCtxDb: (load: () => Mysql2Client | Promise<Mysql2Client>, options: Omit<CreateHyperdriveGlobalCtxDbOptions, "engine" | "exec">) => DatabaseWriterLike;
|
|
230
240
|
/** The studio's global data browser over a Hyperdrive database — every table in the connection's schema, internal ones hidden. */
|
|
231
241
|
interface HyperdriveGlobalIntrospector {
|
|
232
242
|
facetColumn: (options: FacetGlobalColumnOptions) => Promise<GlobalFacetResult>;
|
package/dist/global.d.ts
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
*/
|
|
31
31
|
import { SchemaLike, ImportConflictMode, CdcChange, DatabaseWriterLike } from '@lunora/shard-engine';
|
|
32
32
|
import { SqlExec, SqlDialect, SqlCtxDbOptions, FacetGlobalColumnOptions, GlobalFacetResult, GlobalTableInfo, ReadGlobalTablePageOptions, GlobalTablePage, ExportRow, ImportResult } from '@lunora/sql-store';
|
|
33
|
-
import { M as Mysql2Like, S as SqlClient } from "./packem_shared/types.d-
|
|
33
|
+
import { M as Mysql2Like, S as SqlClient } from "./packem_shared/types.d-DmkKECp5.js";
|
|
34
34
|
import { VectorMetric, VectorizeIndexLike } from '@lunora/platform';
|
|
35
35
|
/**
|
|
36
36
|
* Minimal row-returning client (e.g. `@lunora/hyperdrive`'s `fromPostgresJs`/`fromNodePg`
|
|
@@ -97,10 +97,11 @@ type Mysql2Client = Mysql2Like & {
|
|
|
97
97
|
*/
|
|
98
98
|
declare const buildPgExec: (client: RowClient) => SqlExec;
|
|
99
99
|
/**
|
|
100
|
-
* Wrap a `mysql2/promise` connection/pool
|
|
101
|
-
* renders backtick identifiers and `?`
|
|
102
|
-
*
|
|
103
|
-
* for the store's affected-rows
|
|
100
|
+
* Wrap a `mysql2/promise` connection/pool, built by `load` on the first statement,
|
|
101
|
+
* as a {@link SqlExec}. The core already renders backtick identifiers and `?`
|
|
102
|
+
* placeholders for MySQL, so `all`/`run` forward verbatim. MySQL has no
|
|
103
|
+
* `RETURNING`, so `run` surfaces `affectedRows` for the store's affected-rows
|
|
104
|
+
* OCC guard.
|
|
104
105
|
*
|
|
105
106
|
* Statements go over as text with client-side escaping, so the server must not
|
|
106
107
|
* run with `NO_BACKSLASH_ESCAPES` (see {@link Mysql2Like}).
|
|
@@ -109,12 +110,21 @@ declare const buildPgExec: (client: RowClient) => SqlExec;
|
|
|
109
110
|
* (mysql2: `createPool({ flags: ["FOUND_ROWS"] })`). Without it, `affectedRows`
|
|
110
111
|
* counts *changed* rows, so an idempotent `patch`/`replace` that re-writes the
|
|
111
112
|
* same values reports 0 and the OCC guard raises a spurious conflict. Verified
|
|
112
|
-
*
|
|
113
|
+
* when the loader resolves — see {@link assertFoundRows} — never per statement. A
|
|
114
|
+
* connection without the flag fails that statement and is not kept, so every
|
|
115
|
+
* later statement fails the same way rather than running unguarded.
|
|
116
|
+
*
|
|
117
|
+
* `load` runs on the first statement, not here: `.hyperdriveGlobal`'s `exec(env)`
|
|
118
|
+
* is built with the request's ctx, which can precede the mutation's input-gated
|
|
119
|
+
* span. The `import("mysql2/promise")` inside the loader must start inside that
|
|
120
|
+
* span and finish there, as `buildPgExec(fromPostgresJs(load))` does, so a load
|
|
121
|
+
* begun outside the gate is never awaited inside it.
|
|
113
122
|
*
|
|
114
123
|
* Given a **pool** (anything with `getConnection`), `transaction` takes one
|
|
115
124
|
* connection for the store's row + companion writes, so they commit together.
|
|
116
|
-
* A single connection
|
|
117
|
-
*
|
|
125
|
+
* A single connection cannot hold one apart from other writers' statements, so
|
|
126
|
+
* `transaction` is present but rejects with `GLOBAL_TRANSACTION_UNSUPPORTED`: a
|
|
127
|
+
* write to a table with companions fails before it writes anything.
|
|
118
128
|
*
|
|
119
129
|
* `batch` dispatches every statement concurrently (`Promise.all`), same
|
|
120
130
|
* rationale as {@link buildPgExec}'s `batch` — `Mysql2Like` only exposes a
|
|
@@ -123,7 +133,7 @@ declare const buildPgExec: (client: RowClient) => SqlExec;
|
|
|
123
133
|
* at-least-once, and unordered between elements, safe only for statements
|
|
124
134
|
* with no cross-effect (what every current caller batches).
|
|
125
135
|
*/
|
|
126
|
-
declare const buildMysqlExec: (
|
|
136
|
+
declare const buildMysqlExec: (load: () => Mysql2Client | Promise<Mysql2Client>) => SqlExec;
|
|
127
137
|
/**
|
|
128
138
|
* **Postgres** dialect. Differs from SQLite only in column types
|
|
129
139
|
* (`DOUBLE PRECISION`/`BYTEA`/`BIGSERIAL`), the `information_schema` catalog
|
|
@@ -225,8 +235,8 @@ interface ImportHyperdriveGlobalRowsOptions {
|
|
|
225
235
|
declare const importHyperdriveGlobalRows: ({ cdc, dryRun, engine, exec, onConflict, rows, schema, startLine }: ImportHyperdriveGlobalRowsOptions) => Promise<ImportResult>;
|
|
226
236
|
/** Convenience: a **Postgres** `.global()` writer from a row-client (postgres.js/pg over Hyperdrive). */
|
|
227
237
|
declare const createPostgresGlobalCtxDb: (client: RowClient, options: Omit<CreateHyperdriveGlobalCtxDbOptions, "engine" | "exec">) => DatabaseWriterLike;
|
|
228
|
-
/** Convenience: a **MySQL** `.global()` writer
|
|
229
|
-
declare const createMysqlGlobalCtxDb: (
|
|
238
|
+
/** Convenience: a **MySQL** `.global()` writer over a `mysql2/promise` connection/pool (created with `disableEval: true` and `flags: ["FOUND_ROWS"]`) that `load` builds on the first statement. */
|
|
239
|
+
declare const createMysqlGlobalCtxDb: (load: () => Mysql2Client | Promise<Mysql2Client>, options: Omit<CreateHyperdriveGlobalCtxDbOptions, "engine" | "exec">) => DatabaseWriterLike;
|
|
230
240
|
/** The studio's global data browser over a Hyperdrive database — every table in the connection's schema, internal ones hidden. */
|
|
231
241
|
interface HyperdriveGlobalIntrospector {
|
|
232
242
|
facetColumn: (options: FacetGlobalColumnOptions) => Promise<GlobalFacetResult>;
|
package/dist/global.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{applyCdcChanges as d,CDC_LOG_TABLE as b}from"@lunora/shard-engine";import{createSqlCtxDb as p,readSqlGlobalTablePage as g,listSqlGlobalTables as m,facetSqlGlobalColumn as y,exportSqlGlobalRows as C,importSqlGlobalRows as G,readSqlCdcChanges as x}from"@lunora/sql-store";import{postgresDialect as q,mysqlDialect as u}from"./packem_shared/mysqlDialect-BS1Sz60B.mjs";import{buildMysqlExec as f,buildPgExec as v}from"./packem_shared/buildMysqlExec-
|
|
1
|
+
import{applyCdcChanges as d,CDC_LOG_TABLE as b}from"@lunora/shard-engine";import{createSqlCtxDb as p,readSqlGlobalTablePage as g,listSqlGlobalTables as m,facetSqlGlobalColumn as y,exportSqlGlobalRows as C,importSqlGlobalRows as G,readSqlCdcChanges as x}from"@lunora/sql-store";import{postgresDialect as q,mysqlDialect as u}from"./packem_shared/mysqlDialect-BS1Sz60B.mjs";import{buildMysqlExec as f,buildPgExec as v}from"./packem_shared/buildMysqlExec-DX34snyg.mjs";import{createPgVectorIndex as A}from"./packem_shared/createPgVectorIndex-B2Wbzqns.mjs";const o=e=>e==="postgres"?q:u,c=({engine:e,exec:l,...r})=>p({...r,dialect:o(e),exec:l}),H=({engine:e,exec:l,schema:r,tables:t})=>C(l,r,o(e),t===void 0?{}:{tables:t}),P=({cdc:e,dryRun:l,engine:r,exec:t,onConflict:a,rows:s,schema:n,startLine:i})=>G(c({cdc:e,engine:r,exec:t,schema:n}),n,o(r),{dryRun:l===!0,exec:t,onConflict:a??"skip",rows:s,...i===void 0?{}:{startLine:i}}),R=(e,l)=>c({...l,engine:"postgres",exec:v(e)}),T=(e,l)=>c({...l,engine:"mysql",exec:f(e)}),E=(e,l,r)=>{const t=o(e);return{facetColumn:a=>y(l,r,t,a),listTables:()=>m(l,r,t),readTablePage:a=>g(l,r,t,a)}},I=async(e,l,r)=>{const t=o(e),{params:a,sql:s}=t.render(t.tableExists(b));return(await l.all(s,a)).length===0?{changes:[],cursor:r.sinceSeq}:x(l,r,t)},M=async e=>(await d(c({cdc:e.cdc,engine:e.engine,exec:e.exec,schema:e.schema}),e.changes),e.changes.length);export{M as applyHyperdriveGlobalCdc,f as buildMysqlExec,v as buildPgExec,c as createHyperdriveGlobalCtxDb,E as createHyperdriveGlobalIntrospector,T as createMysqlGlobalCtxDb,A as createPgVectorIndex,R as createPostgresGlobalCtxDb,H as exportHyperdriveGlobalRows,P as importHyperdriveGlobalRows,u as mysqlDialect,q as postgresDialect,I as readHyperdriveGlobalCdc};
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { H as HyperdriveLike, a as HyperdriveConnection, M as Mysql2Like, S as SqlClient, N as NodePgLike, P as PostgresJsLike } from "./packem_shared/types.d-
|
|
1
|
+
import { H as HyperdriveLike, a as HyperdriveConnection, M as Mysql2Like, S as SqlClient, N as NodePgLike, P as PostgresJsLike } from "./packem_shared/types.d-DmkKECp5.mjs";
|
|
2
2
|
/**
|
|
3
3
|
* Surface a Cloudflare Hyperdrive binding as a connection ready to feed a
|
|
4
4
|
* user-supplied SQL driver.
|
|
@@ -9,20 +9,25 @@ import { H as HyperdriveLike, a as HyperdriveConnection, M as Mysql2Like, S as S
|
|
|
9
9
|
* the binding's connection details out; the user constructs their own driver
|
|
10
10
|
* from `connectionString` and wraps it with one of the {@link fromPostgresJs} /
|
|
11
11
|
* {@link fromNodePg} / {@link fromMysql2} adapters to get a {@link SqlClient}.
|
|
12
|
+
* The adapters take a LOADER, not a driver: it runs on the first query, so the
|
|
13
|
+
* driver's `import()` keeps it out of the Worker's startup graph (a static
|
|
14
|
+
* `import postgres from "postgres"` in the entry is evaluated by every isolate
|
|
15
|
+
* before its first event).
|
|
12
16
|
* @example
|
|
13
17
|
* ```ts
|
|
14
18
|
* import { createHyperdrive, fromPostgresJs } from "@lunora/hyperdrive";
|
|
15
|
-
* import postgres from "postgres";
|
|
16
19
|
*
|
|
17
20
|
* // Wire the client once, on the app builder — called per shard construction,
|
|
18
21
|
* // not per request. `ctx.sql` is emitted `readonly`; it is never assigned.
|
|
19
22
|
* const app = defineApp<Env>()
|
|
20
23
|
* .shard((env) => env.SHARD)
|
|
21
|
-
* .hyperdrive((env) =>
|
|
22
|
-
*
|
|
24
|
+
* .hyperdrive((env) =>
|
|
25
|
+
* fromPostgresJs(async () => {
|
|
26
|
+
* const { default: postgres } = await import("postgres");
|
|
23
27
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
28
|
+
* return postgres(createHyperdrive(env.HYPERDRIVE).connectionString, { fetch_types: false, max: 5 });
|
|
29
|
+
* }),
|
|
30
|
+
* )
|
|
26
31
|
* .build();
|
|
27
32
|
*
|
|
28
33
|
* // Then, inside an action (never a query/mutation):
|
|
@@ -44,7 +49,9 @@ declare const createHyperdrive: (binding: HyperdriveLike) => {
|
|
|
44
49
|
connectionString: string;
|
|
45
50
|
};
|
|
46
51
|
/**
|
|
47
|
-
* Wrap a `postgres` (postgres.js) client
|
|
52
|
+
* Wrap a `postgres` (postgres.js) client, built by `load` on the first query
|
|
53
|
+
* and reused, as a {@link SqlClient}. A failed load rejects that query and the
|
|
54
|
+
* next one retries.
|
|
48
55
|
*
|
|
49
56
|
* Uses the driver's `.unsafe(text, params)` escape hatch so the caller supplies
|
|
50
57
|
* a plain SQL string with `$1, $2, …` placeholders and a positional params
|
|
@@ -57,15 +64,18 @@ declare const createHyperdrive: (binding: HyperdriveLike) => {
|
|
|
57
64
|
* wins. Prepared reads are cacheable by Hyperdrive, so a `.global()` store's
|
|
58
65
|
* config must have caching disabled (see `@lunora/hyperdrive/global`).
|
|
59
66
|
*/
|
|
60
|
-
declare const fromPostgresJs: (
|
|
67
|
+
declare const fromPostgresJs: (load: () => Promise<PostgresJsLike> | PostgresJsLike) => SqlClient;
|
|
61
68
|
/**
|
|
62
|
-
* Wrap a `pg` (node-postgres) `Client` or `Pool`
|
|
69
|
+
* Wrap a `pg` (node-postgres) `Client` or `Pool`, built by `load` on the first
|
|
70
|
+
* query, as a {@link SqlClient}. `load` may `await client.connect()` before
|
|
71
|
+
* returning.
|
|
63
72
|
*
|
|
64
73
|
* node-postgres returns a result object whose `rows` field holds the row array.
|
|
65
74
|
*/
|
|
66
|
-
declare const fromNodePg: (
|
|
75
|
+
declare const fromNodePg: (load: () => Promise<NodePgLike> | NodePgLike) => SqlClient;
|
|
67
76
|
/**
|
|
68
|
-
* Wrap a `mysql2/promise` connection or pool
|
|
77
|
+
* Wrap a `mysql2/promise` connection or pool, built by `load` on the first
|
|
78
|
+
* query, as a {@link SqlClient}.
|
|
69
79
|
*
|
|
70
80
|
* Use `?` placeholders (MySQL positional syntax). `mysql2`'s `query` resolves
|
|
71
81
|
* to a `[rows, fields]` tuple; the adapter returns the first element. For a
|
|
@@ -73,7 +83,7 @@ declare const fromNodePg: (client: NodePgLike) => SqlClient;
|
|
|
73
83
|
* row array, so the adapter normalises that to `[]` — matching the empty-array
|
|
74
84
|
* contract the postgres.js / node-postgres adapters already honour.
|
|
75
85
|
*/
|
|
76
|
-
declare const fromMysql2: (
|
|
86
|
+
declare const fromMysql2: (load: () => Promise<Mysql2Like> | Mysql2Like) => SqlClient;
|
|
77
87
|
/** How an external row maps to a Lunora document. */
|
|
78
88
|
interface ProjectOptions {
|
|
79
89
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { H as HyperdriveLike, a as HyperdriveConnection, M as Mysql2Like, S as SqlClient, N as NodePgLike, P as PostgresJsLike } from "./packem_shared/types.d-
|
|
1
|
+
import { H as HyperdriveLike, a as HyperdriveConnection, M as Mysql2Like, S as SqlClient, N as NodePgLike, P as PostgresJsLike } from "./packem_shared/types.d-DmkKECp5.js";
|
|
2
2
|
/**
|
|
3
3
|
* Surface a Cloudflare Hyperdrive binding as a connection ready to feed a
|
|
4
4
|
* user-supplied SQL driver.
|
|
@@ -9,20 +9,25 @@ import { H as HyperdriveLike, a as HyperdriveConnection, M as Mysql2Like, S as S
|
|
|
9
9
|
* the binding's connection details out; the user constructs their own driver
|
|
10
10
|
* from `connectionString` and wraps it with one of the {@link fromPostgresJs} /
|
|
11
11
|
* {@link fromNodePg} / {@link fromMysql2} adapters to get a {@link SqlClient}.
|
|
12
|
+
* The adapters take a LOADER, not a driver: it runs on the first query, so the
|
|
13
|
+
* driver's `import()` keeps it out of the Worker's startup graph (a static
|
|
14
|
+
* `import postgres from "postgres"` in the entry is evaluated by every isolate
|
|
15
|
+
* before its first event).
|
|
12
16
|
* @example
|
|
13
17
|
* ```ts
|
|
14
18
|
* import { createHyperdrive, fromPostgresJs } from "@lunora/hyperdrive";
|
|
15
|
-
* import postgres from "postgres";
|
|
16
19
|
*
|
|
17
20
|
* // Wire the client once, on the app builder — called per shard construction,
|
|
18
21
|
* // not per request. `ctx.sql` is emitted `readonly`; it is never assigned.
|
|
19
22
|
* const app = defineApp<Env>()
|
|
20
23
|
* .shard((env) => env.SHARD)
|
|
21
|
-
* .hyperdrive((env) =>
|
|
22
|
-
*
|
|
24
|
+
* .hyperdrive((env) =>
|
|
25
|
+
* fromPostgresJs(async () => {
|
|
26
|
+
* const { default: postgres } = await import("postgres");
|
|
23
27
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
28
|
+
* return postgres(createHyperdrive(env.HYPERDRIVE).connectionString, { fetch_types: false, max: 5 });
|
|
29
|
+
* }),
|
|
30
|
+
* )
|
|
26
31
|
* .build();
|
|
27
32
|
*
|
|
28
33
|
* // Then, inside an action (never a query/mutation):
|
|
@@ -44,7 +49,9 @@ declare const createHyperdrive: (binding: HyperdriveLike) => {
|
|
|
44
49
|
connectionString: string;
|
|
45
50
|
};
|
|
46
51
|
/**
|
|
47
|
-
* Wrap a `postgres` (postgres.js) client
|
|
52
|
+
* Wrap a `postgres` (postgres.js) client, built by `load` on the first query
|
|
53
|
+
* and reused, as a {@link SqlClient}. A failed load rejects that query and the
|
|
54
|
+
* next one retries.
|
|
48
55
|
*
|
|
49
56
|
* Uses the driver's `.unsafe(text, params)` escape hatch so the caller supplies
|
|
50
57
|
* a plain SQL string with `$1, $2, …` placeholders and a positional params
|
|
@@ -57,15 +64,18 @@ declare const createHyperdrive: (binding: HyperdriveLike) => {
|
|
|
57
64
|
* wins. Prepared reads are cacheable by Hyperdrive, so a `.global()` store's
|
|
58
65
|
* config must have caching disabled (see `@lunora/hyperdrive/global`).
|
|
59
66
|
*/
|
|
60
|
-
declare const fromPostgresJs: (
|
|
67
|
+
declare const fromPostgresJs: (load: () => Promise<PostgresJsLike> | PostgresJsLike) => SqlClient;
|
|
61
68
|
/**
|
|
62
|
-
* Wrap a `pg` (node-postgres) `Client` or `Pool`
|
|
69
|
+
* Wrap a `pg` (node-postgres) `Client` or `Pool`, built by `load` on the first
|
|
70
|
+
* query, as a {@link SqlClient}. `load` may `await client.connect()` before
|
|
71
|
+
* returning.
|
|
63
72
|
*
|
|
64
73
|
* node-postgres returns a result object whose `rows` field holds the row array.
|
|
65
74
|
*/
|
|
66
|
-
declare const fromNodePg: (
|
|
75
|
+
declare const fromNodePg: (load: () => Promise<NodePgLike> | NodePgLike) => SqlClient;
|
|
67
76
|
/**
|
|
68
|
-
* Wrap a `mysql2/promise` connection or pool
|
|
77
|
+
* Wrap a `mysql2/promise` connection or pool, built by `load` on the first
|
|
78
|
+
* query, as a {@link SqlClient}.
|
|
69
79
|
*
|
|
70
80
|
* Use `?` placeholders (MySQL positional syntax). `mysql2`'s `query` resolves
|
|
71
81
|
* to a `[rows, fields]` tuple; the adapter returns the first element. For a
|
|
@@ -73,7 +83,7 @@ declare const fromNodePg: (client: NodePgLike) => SqlClient;
|
|
|
73
83
|
* row array, so the adapter normalises that to `[]` — matching the empty-array
|
|
74
84
|
* contract the postgres.js / node-postgres adapters already honour.
|
|
75
85
|
*/
|
|
76
|
-
declare const fromMysql2: (
|
|
86
|
+
declare const fromMysql2: (load: () => Promise<Mysql2Like> | Mysql2Like) => SqlClient;
|
|
77
87
|
/** How an external row maps to a Lunora document. */
|
|
78
88
|
interface ProjectOptions {
|
|
79
89
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHyperdrive as e,fromMysql2 as f,fromNodePg as m,fromPostgresJs as p}from"./packem_shared/createHyperdrive-
|
|
1
|
+
import{createHyperdrive as e,fromMysql2 as f,fromNodePg as m,fromPostgresJs as p}from"./packem_shared/createHyperdrive-Bw1Au7bE.mjs";import{projectSourceRow as t,pullSourceRows as c}from"./packem_shared/projectSourceRow-DN8ywPRl.mjs";export{e as createHyperdrive,f as fromMysql2,m as fromNodePg,p as fromPostgresJs,t as projectSourceRow,c as pullSourceRows};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LunoraError as l}from"@lunora/errors";import{t as i,l as d}from"./mysql-params-BYlr9fFZ.mjs";const u=2,c=new WeakSet,w=e=>{const a=e,r=a.config?.clientFlags;if(typeof r=="number")return r;const t=a.pool?.config?.connectionConfig?.clientFlags;return typeof t=="number"?t:void 0},y=e=>{const a=w(e);if(a===void 0){if(c.has(e))return;c.add(e),console.warn('@lunora/hyperdrive: could not determine whether this MySQL connection negotiated CLIENT_FOUND_ROWS (the driver exposes no flag introspection). If it was NOT created with the `CLIENT_FOUND_ROWS` flag (mysql2: `createPool({ flags: ["FOUND_ROWS"] })`), an idempotent patch/replace that rewrites identical values may report 0 affectedRows and raise a spurious OCC ConflictError.');return}if((a&u)===0)throw new l("INTERNAL",'@lunora/hyperdrive: this MySQL connection was not created with the `CLIENT_FOUND_ROWS` flag (mysql2: `createPool({ flags: ["FOUND_ROWS"] })`). Without it, `affectedRows` counts changed (not matched) rows, so an idempotent patch/replace that rewrites identical values reports 0 and the OCC guard raises a spurious conflict.')},p=async(e,a,r)=>{const t=await e.getConnection();let o;try{await t.beginTransaction(),o=await r(a(t)),await t.commit()}catch(n){try{await t.rollback(),t.release()}catch{t.destroy()}throw n}return t.release(),o},f=e=>{throw new l("GLOBAL_TRANSACTION_UNSUPPORTED",`@lunora/hyperdrive: a .global() write needs ${e} to commit its row and companions together; the supplied driver cannot open a transaction. Pass ${e}.`)},h=e=>({all:(a,r)=>e.query(a,r),batch:async a=>{await Promise.all(a.map(r=>e.query(r.sql,r.params)))},run:async(a,r)=>(await e.query(a,r),{rowsAffected:0}),...e.transaction===void 0?{}:{transaction:async a=>await e.transaction(async r=>await a(h(r)))}}),m=e=>{const a=d(async()=>{const t=await e();return y(t),t});return{transaction:async t=>{const o=await a(),{getConnection:n}=o;return typeof n=="function"?await p(o,s=>m(()=>s),t):f("a mysql2 pool (`createPool`)")},all:async(t,o)=>{const n=await a(),[s]=await n.query(t,i(o));return Array.isArray(s)?s:[]},batch:async t=>{const o=await a();await Promise.all(t.map(n=>o.query(n.sql,i(n.params))))},run:async(t,o)=>{const n=await a(),[s]=await n.query(t,i(o));return{rowsAffected:s.affectedRows??0}}}};export{m as buildMysqlExec,h as buildPgExec};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LunoraError as c}from"@lunora/errors";import{t as i,l as n}from"./mysql-params-BYlr9fFZ.mjs";const l=r=>({config:{database:r.database,host:r.host,password:r.password,port:r.port,user:r.user},connectionString:r.connectionString}),u=r=>{const t=n(r);return{dbSystem:"postgresql",query:async(s,o=[])=>await(await t()).unsafe(s,o,{prepare:!0}),transaction:async s=>{const{begin:o}=await t();if(o===void 0)throw new c("GLOBAL_TRANSACTION_UNSUPPORTED","@lunora/hyperdrive: the postgres.js client has no `begin()`, so a .global() write cannot commit its row and companions together. Pass a postgres.js client that has `begin()`.");return await o(async e=>await s(u(()=>e)))}}},m=r=>{const t=n(r);return{dbSystem:"postgresql",query:async(a,s=[])=>(await(await t()).query(a,s)).rows}},d=r=>{const t=n(r);return{dbSystem:"mysql",query:async(a,s=[])=>{const o=await t(),[e]=await o.query(a,i(s));return Array.isArray(e)?e:[]}}};export{l as createHyperdrive,d as fromMysql2,m as fromNodePg,u as fromPostgresJs};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const o=t=>{let r;return()=>{if(r!==void 0)return r;const n=(async()=>await t())().catch(e=>{throw r===n&&(r=void 0),e});return r=n,n}},i=t=>({toSqlString:()=>`'${t.replaceAll("\\","\\\\").replaceAll("'","''")}'`,toString:()=>t}),s=t=>t.map((r,n)=>{if(r===void 0)throw new TypeError(`@lunora/hyperdrive: MySQL bind parameter ${String(n+1)} is undefined`);return typeof r=="string"?i(r):r===null||typeof r!="object"||r instanceof Date||ArrayBuffer.isView(r)?r:r instanceof ArrayBuffer?new Uint8Array(r):i(JSON.stringify(r))});export{o as l,s as t};
|
|
@@ -98,8 +98,9 @@ interface SqlClient {
|
|
|
98
98
|
* transaction: committed when `work` resolves, rolled back when it throws.
|
|
99
99
|
* {@link import("./create-hyperdrive").fromPostgresJs | fromPostgresJs} provides it over postgres.js's `begin`;
|
|
100
100
|
* `@lunora/hyperdrive/global`'s `buildPgExec` uses it so a `.global()` row
|
|
101
|
-
* write and its aggregate/rank/CDC companions commit together.
|
|
102
|
-
*
|
|
101
|
+
* write and its aggregate/rank/CDC companions commit together. `fromPostgresJs`
|
|
102
|
+
* always exposes it and rejects with `GLOBAL_TRANSACTION_UNSUPPORTED` when the loaded client has no `begin`.
|
|
103
|
+
* Absent (`fromNodePg`), the companions commit one statement at a time.
|
|
103
104
|
*/
|
|
104
105
|
transaction?: <T>(work: (tx: SqlClient) => Promise<T>) => Promise<T>;
|
|
105
106
|
}
|
|
@@ -98,8 +98,9 @@ interface SqlClient {
|
|
|
98
98
|
* transaction: committed when `work` resolves, rolled back when it throws.
|
|
99
99
|
* {@link import("./create-hyperdrive").fromPostgresJs | fromPostgresJs} provides it over postgres.js's `begin`;
|
|
100
100
|
* `@lunora/hyperdrive/global`'s `buildPgExec` uses it so a `.global()` row
|
|
101
|
-
* write and its aggregate/rank/CDC companions commit together.
|
|
102
|
-
*
|
|
101
|
+
* write and its aggregate/rank/CDC companions commit together. `fromPostgresJs`
|
|
102
|
+
* always exposes it and rejects with `GLOBAL_TRANSACTION_UNSUPPORTED` when the loaded client has no `begin`.
|
|
103
|
+
* Absent (`fromNodePg`), the companions commit one statement at a time.
|
|
103
104
|
*/
|
|
104
105
|
transaction?: <T>(work: (tx: SqlClient) => Promise<T>) => Promise<T>;
|
|
105
106
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/hyperdrive",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.227",
|
|
4
4
|
"description": "Bring-your-own Postgres/MySQL for Lunora via Cloudflare Hyperdrive: a driver-agnostic, action-only ctx.sql",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@lunora/errors": ">=1.0.0-alpha.51 <2.0.0-0",
|
|
54
|
-
"@lunora/platform": "1.0.0-alpha.
|
|
55
|
-
"@lunora/shard-engine": "1.0.0-alpha.
|
|
56
|
-
"@lunora/sql-store": "1.0.0-alpha.
|
|
54
|
+
"@lunora/platform": "1.0.0-alpha.80",
|
|
55
|
+
"@lunora/shard-engine": "1.0.0-alpha.185",
|
|
56
|
+
"@lunora/sql-store": "1.0.0-alpha.232",
|
|
57
57
|
"drizzle-orm": "1.0.0-rc.5"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{LunoraError as c}from"@lunora/errors";import{t as n}from"./mysql-params-D4Ijlvo5.mjs";const l=2,i=new WeakSet,u=t=>{const a=t,e=a.config?.clientFlags;if(typeof e=="number")return e;const r=a.pool?.config?.connectionConfig?.clientFlags;return typeof r=="number"?r:void 0},d=t=>{const a=u(t);if(a===void 0){if(i.has(t))return;i.add(t),console.warn('@lunora/hyperdrive: could not determine whether this MySQL connection negotiated CLIENT_FOUND_ROWS (the driver exposes no flag introspection). If it was NOT created with the `CLIENT_FOUND_ROWS` flag (mysql2: `createPool({ flags: ["FOUND_ROWS"] })`), an idempotent patch/replace that rewrites identical values may report 0 affectedRows and raise a spurious OCC ConflictError.');return}if((a&l)===0)throw new c("INTERNAL",'@lunora/hyperdrive: this MySQL connection was not created with the `CLIENT_FOUND_ROWS` flag (mysql2: `createPool({ flags: ["FOUND_ROWS"] })`). Without it, `affectedRows` counts changed (not matched) rows, so an idempotent patch/replace that rewrites identical values reports 0 and the OCC guard raises a spurious conflict.')},w=async(t,a,e)=>{const r=await t.getConnection();let o;try{await r.beginTransaction(),o=await e(a(r)),await r.commit()}catch(s){try{await r.rollback(),r.release()}catch{r.destroy()}throw s}return r.release(),o},y=t=>({all:(a,e)=>t.query(a,e),batch:async a=>{await Promise.all(a.map(e=>t.query(e.sql,e.params)))},run:async(a,e)=>(await t.query(a,e),{rowsAffected:0}),...t.transaction===void 0?{}:{transaction:async a=>await t.transaction(async e=>await a(y(e)))}}),f=t=>{d(t);const a=t,{getConnection:e}=a;return{...typeof e=="function"?{transaction:async r=>await w(a,f,r)}:{},all:async(r,o)=>{const[s]=await t.query(r,n(o));return Array.isArray(s)?s:[]},batch:async r=>{await Promise.all(r.map(o=>t.query(o.sql,n(o.params))))},run:async(r,o)=>{const[s]=await t.query(r,n(o));return{rowsAffected:s.affectedRows??0}}}};export{f as buildMysqlExec,y as buildPgExec};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./mysql-params-D4Ijlvo5.mjs";const y=r=>({config:{database:r.database,host:r.host,password:r.password,port:r.port,user:r.user},connectionString:r.connectionString}),a=r=>{const{begin:s}=r;return{dbSystem:"postgresql",query:async(t,o=[])=>await r.unsafe(t,o,{prepare:!0}),...s===void 0?{}:{transaction:async t=>await s(async o=>await t(a(o)))}}},u=r=>({dbSystem:"postgresql",query:async(s,t=[])=>(await r.query(s,t)).rows}),p=r=>({dbSystem:"mysql",query:async(s,t=[])=>{const[o]=await r.query(s,e(t));return Array.isArray(o)?o:[]}});export{y as createHyperdrive,p as fromMysql2,u as fromNodePg,a as fromPostgresJs};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const n=t=>({toSqlString:()=>`'${t.replaceAll("\\","\\\\").replaceAll("'","''")}'`,toString:()=>t}),e=t=>t.map((r,i)=>{if(r===void 0)throw new TypeError(`@lunora/hyperdrive: MySQL bind parameter ${String(i+1)} is undefined`);return typeof r=="string"?n(r):r===null||typeof r!="object"||r instanceof Date||ArrayBuffer.isView(r)?r:r instanceof ArrayBuffer?new Uint8Array(r):n(JSON.stringify(r))});export{e as t};
|