@lunora/hyperdrive 1.0.0-alpha.24 → 1.0.0-alpha.26

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/dist/global.d.mts CHANGED
@@ -1,13 +1,18 @@
1
1
  import { DatabaseWriterLike } from '@lunora/do';
2
2
  import { SqlExec, SqlDialect, SqlCtxDbOptions } from '@lunora/sql-store';
3
- /** Minimal row-returning client (e.g. `@lunora/hyperdrive`'s `fromPostgresJs`/`fromNodePg` result). */
4
- interface RowClient {
5
- query: <Row = Record<string, unknown>>(text: string, params?: ReadonlyArray<unknown>) => Promise<Row[]>;
6
- }
7
- /** Minimal `mysql2/promise` connection/pool surface `execute` resolves to `[rows | ResultSetHeader, fields]`. */
8
- interface Mysql2Execute {
9
- execute: (text: string, params?: ReadonlyArray<unknown>) => Promise<[unknown, unknown]>;
10
- }
3
+ import { M as Mysql2Like, S as SqlClient } from "./packem_shared/types.d-C6SU6Aw3.mjs";
4
+ /**
5
+ * Minimal row-returning client (e.g. `@lunora/hyperdrive`'s `fromPostgresJs`/`fromNodePg`
6
+ * result). Aliases {@link SqlClient} — the exec-facing name is kept so call sites read
7
+ * intent, but the shape is the single source of truth in `./types` (no drift).
8
+ */
9
+ type RowClient = SqlClient;
10
+ /**
11
+ * Minimal `mysql2/promise` connection/pool surface — `execute` resolves to
12
+ * `[rows | ResultSetHeader, fields]`. Aliases {@link Mysql2Like} so the /global entry's
13
+ * driver surface can never drift from the main entry's.
14
+ */
15
+ type Mysql2Execute = Mysql2Like;
11
16
  /**
12
17
  * Wrap a Postgres row-client (from `@lunora/hyperdrive`'s `fromPostgresJs` /
13
18
  * `fromNodePg`) as a {@link SqlExec}. The core already renders `$N` placeholders
package/dist/global.d.ts CHANGED
@@ -1,13 +1,18 @@
1
1
  import { DatabaseWriterLike } from '@lunora/do';
2
2
  import { SqlExec, SqlDialect, SqlCtxDbOptions } from '@lunora/sql-store';
3
- /** Minimal row-returning client (e.g. `@lunora/hyperdrive`'s `fromPostgresJs`/`fromNodePg` result). */
4
- interface RowClient {
5
- query: <Row = Record<string, unknown>>(text: string, params?: ReadonlyArray<unknown>) => Promise<Row[]>;
6
- }
7
- /** Minimal `mysql2/promise` connection/pool surface `execute` resolves to `[rows | ResultSetHeader, fields]`. */
8
- interface Mysql2Execute {
9
- execute: (text: string, params?: ReadonlyArray<unknown>) => Promise<[unknown, unknown]>;
10
- }
3
+ import { M as Mysql2Like, S as SqlClient } from "./packem_shared/types.d-C6SU6Aw3.js";
4
+ /**
5
+ * Minimal row-returning client (e.g. `@lunora/hyperdrive`'s `fromPostgresJs`/`fromNodePg`
6
+ * result). Aliases {@link SqlClient} — the exec-facing name is kept so call sites read
7
+ * intent, but the shape is the single source of truth in `./types` (no drift).
8
+ */
9
+ type RowClient = SqlClient;
10
+ /**
11
+ * Minimal `mysql2/promise` connection/pool surface — `execute` resolves to
12
+ * `[rows | ResultSetHeader, fields]`. Aliases {@link Mysql2Like} so the /global entry's
13
+ * driver surface can never drift from the main entry's.
14
+ */
15
+ type Mysql2Execute = Mysql2Like;
11
16
  /**
12
17
  * Wrap a Postgres row-client (from `@lunora/hyperdrive`'s `fromPostgresJs` /
13
18
  * `fromNodePg`) as a {@link SqlExec}. The core already renders `$N` placeholders
package/dist/global.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createSqlCtxDb } from '@lunora/sql-store';
2
- import { postgresDialect, mysqlDialect } from './packem_shared/mysqlDialect-oNhZ58s8.mjs';
2
+ import { postgresDialect, mysqlDialect } from './packem_shared/mysqlDialect-BHz03Grz.mjs';
3
3
  import { buildMysqlExec, buildPgExec } from './packem_shared/buildMysqlExec-DBbCjyq3.mjs';
4
4
 
5
5
  const createHyperdriveGlobalCtxDb = ({ engine, exec, ...rest }) => createSqlCtxDb({ ...rest, dialect: engine === "postgres" ? postgresDialect : mysqlDialect, exec });
package/dist/index.d.mts CHANGED
@@ -1,115 +1,4 @@
1
- /**
2
- * Public types for `@lunora/hyperdrive`.
3
- *
4
- * Hyperdrive points at a database **Lunora does not own**. Everything here is
5
- * deliberately structural (no hard dependency on `@cloudflare/workers-types` or
6
- * any SQL driver) so unit tests can pass plain-object doubles, exactly like the
7
- * `D1DatabaseLike` projection in `@lunora/d1`.
8
- *
9
- * The hard constraint, restated wherever this surface is used: Hyperdrive
10
- * queries are **non-deterministic** (forbidden in `query`/`mutation`, allowed
11
- * only in `action`s — see the `hyperdrive_outside_action` advisor lint), and
12
- * external writes are **invisible to Lunora live queries** — a subscription will
13
- * NOT re-run when an external Postgres/MySQL row changes.
14
- */
15
- /**
16
- * Structural projection of the Cloudflare `Hyperdrive` binding (`env.HYPERDRIVE`).
17
- *
18
- * Mirrors the fields of the real `Hyperdrive` from `@cloudflare/workers-types`
19
- * but stays structural so a unit test can pass a plain object. At runtime only
20
- * `connectionString` is needed to construct a driver; the discrete connection
21
- * parts are surfaced for drivers that prefer a config object over a DSN.
22
- */
23
- interface HyperdriveLike {
24
- /** A connection string Hyperdrive routes through its pooled, cached edge connection. */
25
- connectionString: string;
26
- /** Database name component of the connection. */
27
- database: string;
28
- /** Host Hyperdrive presents to the driver (the local proxy, not your origin DB). */
29
- host: string;
30
- /** Password component of the connection. */
31
- password: string;
32
- /** Port Hyperdrive presents to the driver. */
33
- port: number;
34
- /** User component of the connection. */
35
- user: string;
36
- }
37
- /**
38
- * The connection config surfaced by {@link import("./create-hyperdrive").createHyperdrive | createHyperdrive}: the raw
39
- * `connectionString` plus the discrete parts, ready to hand to a driver.
40
- */
41
- interface HyperdriveConnection {
42
- /** Database name. */
43
- database: string;
44
- /** Host (Hyperdrive's local proxy). */
45
- host: string;
46
- /** Password. */
47
- password: string;
48
- /** Port. */
49
- port: number;
50
- /** User. */
51
- user: string;
52
- }
53
- /**
54
- * The driver-agnostic SQL surface bound to `ctx.sql` on **`ActionCtx` only**.
55
- *
56
- * This is the exact type the generated ctx imports as
57
- * `import("@lunora/hyperdrive").SqlClient`. Keep the name and shape stable — the
58
- * codegen ctx wiring (Phase 1) depends on it.
59
- *
60
- * It is intentionally minimal — a single parameterised `query` — so it maps onto
61
- * `postgres` (postgres.js), `pg` (node-postgres) and `mysql2` alike via the
62
- * {@link import("./create-hyperdrive").fromPostgresJs | fromPostgresJs} /
63
- * {@link import("./create-hyperdrive").fromNodePg | fromNodePg} /
64
- * {@link import("./create-hyperdrive").fromMysql2 | fromMysql2} adapters. Use
65
- * positional placeholders that match your driver (`$1, $2` for Postgres, `?` for
66
- * MySQL); the package does not rewrite SQL.
67
- *
68
- * Reminder (also on the emitted JSDoc): non-deterministic, action-only,
69
- * non-reactive — writes here are not tracked by Lunora live queries.
70
- */
71
- interface SqlClient {
72
- /**
73
- * Run a parameterised SQL statement and return the result rows.
74
- *
75
- * SECURITY: `text` is executed verbatim — the package never rewrites or
76
- * escapes it. NEVER interpolate untrusted/user input into `text`; put every
77
- * value in `params` and reference it with a positional placeholder (`$1`/`?`).
78
- * Building `text` by string-concatenating request data is a SQL-injection
79
- * sink against your own Postgres/MySQL. Identifiers (table/column names) can't
80
- * be parameterised — allowlist them against a fixed set, don't interpolate.
81
- * @param text SQL text with driver-native positional placeholders.
82
- * @param params Bound parameter values, positionally matched to `text`.
83
- * @returns The rows the statement produced (empty for non-`SELECT`s that
84
- * return no rows).
85
- */
86
- query: <Row = Record<string, unknown>>(text: string, params?: ReadonlyArray<unknown>) => Promise<Row[]>;
87
- }
88
- /**
89
- * Structural projection of a `pg` (node-postgres) `Client`/`Pool`. Only the
90
- * `query` method `fromNodePg` calls is required, kept structural for testing.
91
- */
92
- interface NodePgLike {
93
- query: (text: string, params?: ReadonlyArray<unknown>) => Promise<{
94
- rows: unknown[];
95
- }>;
96
- }
97
- /**
98
- * Structural projection of a `postgres` (postgres.js) tagged-template client.
99
- * The adapter uses the `.unsafe(text, params)` escape hatch so callers keep
100
- * full control of the parameter list.
101
- */
102
- interface PostgresJsLike {
103
- unsafe: (text: string, params?: ReadonlyArray<unknown>) => Promise<unknown>;
104
- }
105
- /**
106
- * Structural projection of a `mysql2/promise` connection/pool. `mysql2`'s
107
- * `execute` resolves to a `[rows, fields]` tuple; the adapter takes the first
108
- * element as the rows.
109
- */
110
- interface Mysql2Like {
111
- execute: (text: string, params?: ReadonlyArray<unknown>) => Promise<[unknown, unknown]>;
112
- }
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-C6SU6Aw3.mjs";
113
2
  /**
114
3
  * Surface a Cloudflare Hyperdrive binding as a connection ready to feed a
115
4
  * user-supplied SQL driver.
package/dist/index.d.ts CHANGED
@@ -1,115 +1,4 @@
1
- /**
2
- * Public types for `@lunora/hyperdrive`.
3
- *
4
- * Hyperdrive points at a database **Lunora does not own**. Everything here is
5
- * deliberately structural (no hard dependency on `@cloudflare/workers-types` or
6
- * any SQL driver) so unit tests can pass plain-object doubles, exactly like the
7
- * `D1DatabaseLike` projection in `@lunora/d1`.
8
- *
9
- * The hard constraint, restated wherever this surface is used: Hyperdrive
10
- * queries are **non-deterministic** (forbidden in `query`/`mutation`, allowed
11
- * only in `action`s — see the `hyperdrive_outside_action` advisor lint), and
12
- * external writes are **invisible to Lunora live queries** — a subscription will
13
- * NOT re-run when an external Postgres/MySQL row changes.
14
- */
15
- /**
16
- * Structural projection of the Cloudflare `Hyperdrive` binding (`env.HYPERDRIVE`).
17
- *
18
- * Mirrors the fields of the real `Hyperdrive` from `@cloudflare/workers-types`
19
- * but stays structural so a unit test can pass a plain object. At runtime only
20
- * `connectionString` is needed to construct a driver; the discrete connection
21
- * parts are surfaced for drivers that prefer a config object over a DSN.
22
- */
23
- interface HyperdriveLike {
24
- /** A connection string Hyperdrive routes through its pooled, cached edge connection. */
25
- connectionString: string;
26
- /** Database name component of the connection. */
27
- database: string;
28
- /** Host Hyperdrive presents to the driver (the local proxy, not your origin DB). */
29
- host: string;
30
- /** Password component of the connection. */
31
- password: string;
32
- /** Port Hyperdrive presents to the driver. */
33
- port: number;
34
- /** User component of the connection. */
35
- user: string;
36
- }
37
- /**
38
- * The connection config surfaced by {@link import("./create-hyperdrive").createHyperdrive | createHyperdrive}: the raw
39
- * `connectionString` plus the discrete parts, ready to hand to a driver.
40
- */
41
- interface HyperdriveConnection {
42
- /** Database name. */
43
- database: string;
44
- /** Host (Hyperdrive's local proxy). */
45
- host: string;
46
- /** Password. */
47
- password: string;
48
- /** Port. */
49
- port: number;
50
- /** User. */
51
- user: string;
52
- }
53
- /**
54
- * The driver-agnostic SQL surface bound to `ctx.sql` on **`ActionCtx` only**.
55
- *
56
- * This is the exact type the generated ctx imports as
57
- * `import("@lunora/hyperdrive").SqlClient`. Keep the name and shape stable — the
58
- * codegen ctx wiring (Phase 1) depends on it.
59
- *
60
- * It is intentionally minimal — a single parameterised `query` — so it maps onto
61
- * `postgres` (postgres.js), `pg` (node-postgres) and `mysql2` alike via the
62
- * {@link import("./create-hyperdrive").fromPostgresJs | fromPostgresJs} /
63
- * {@link import("./create-hyperdrive").fromNodePg | fromNodePg} /
64
- * {@link import("./create-hyperdrive").fromMysql2 | fromMysql2} adapters. Use
65
- * positional placeholders that match your driver (`$1, $2` for Postgres, `?` for
66
- * MySQL); the package does not rewrite SQL.
67
- *
68
- * Reminder (also on the emitted JSDoc): non-deterministic, action-only,
69
- * non-reactive — writes here are not tracked by Lunora live queries.
70
- */
71
- interface SqlClient {
72
- /**
73
- * Run a parameterised SQL statement and return the result rows.
74
- *
75
- * SECURITY: `text` is executed verbatim — the package never rewrites or
76
- * escapes it. NEVER interpolate untrusted/user input into `text`; put every
77
- * value in `params` and reference it with a positional placeholder (`$1`/`?`).
78
- * Building `text` by string-concatenating request data is a SQL-injection
79
- * sink against your own Postgres/MySQL. Identifiers (table/column names) can't
80
- * be parameterised — allowlist them against a fixed set, don't interpolate.
81
- * @param text SQL text with driver-native positional placeholders.
82
- * @param params Bound parameter values, positionally matched to `text`.
83
- * @returns The rows the statement produced (empty for non-`SELECT`s that
84
- * return no rows).
85
- */
86
- query: <Row = Record<string, unknown>>(text: string, params?: ReadonlyArray<unknown>) => Promise<Row[]>;
87
- }
88
- /**
89
- * Structural projection of a `pg` (node-postgres) `Client`/`Pool`. Only the
90
- * `query` method `fromNodePg` calls is required, kept structural for testing.
91
- */
92
- interface NodePgLike {
93
- query: (text: string, params?: ReadonlyArray<unknown>) => Promise<{
94
- rows: unknown[];
95
- }>;
96
- }
97
- /**
98
- * Structural projection of a `postgres` (postgres.js) tagged-template client.
99
- * The adapter uses the `.unsafe(text, params)` escape hatch so callers keep
100
- * full control of the parameter list.
101
- */
102
- interface PostgresJsLike {
103
- unsafe: (text: string, params?: ReadonlyArray<unknown>) => Promise<unknown>;
104
- }
105
- /**
106
- * Structural projection of a `mysql2/promise` connection/pool. `mysql2`'s
107
- * `execute` resolves to a `[rows, fields]` tuple; the adapter takes the first
108
- * element as the rows.
109
- */
110
- interface Mysql2Like {
111
- execute: (text: string, params?: ReadonlyArray<unknown>) => Promise<[unknown, unknown]>;
112
- }
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-C6SU6Aw3.js";
113
2
  /**
114
3
  * Surface a Cloudflare Hyperdrive binding as a connection ready to feed a
115
4
  * user-supplied SQL driver.
@@ -67,7 +67,12 @@ const postgresDialect = {
67
67
  },
68
68
  name: "postgres",
69
69
  supportsReturning: true,
70
- tableExists: (table) => sql`SELECT table_name FROM information_schema.tables WHERE table_name = ${table}`
70
+ // Restrict to schemas on the effective search_path (excluding the implicit
71
+ // pg_catalog with `false`) so an unqualified name resolves exactly as CREATE
72
+ // TABLE / SELECT would. Without this filter the probe sees same-named tables in
73
+ // OTHER schemas of the same database (a common multi-tenant/multi-env Hyperdrive
74
+ // setup), reporting a companion table that does not exist on the search_path.
75
+ tableExists: (table) => sql`SELECT table_name FROM information_schema.tables WHERE table_schema = ANY (current_schemas(false)) AND table_name = ${table}`
71
76
  };
72
77
  const mysqlDialect = {
73
78
  affectedRows: (result) => result.rowsAffected,
@@ -88,8 +93,13 @@ const mysqlDialect = {
88
93
  { name: "id", type: "VARCHAR(768) PRIMARY KEY" },
89
94
  { name: "_creationTime", type: "DOUBLE NOT NULL" }
90
95
  ],
91
- // InnoDB can't index a TEXT/LONGTEXT/BLOB column without a key prefix; bound it to 768 chars.
92
- indexKeyPrefix: (kind) => MYSQL_PREFIX_INDEX_RE.test(mysqlColumnType(kind)) ? 768 : void 0,
96
+ // InnoDB can't index a TEXT/LONGTEXT/BLOB column without a key prefix. Bound it
97
+ // to 191 chars (191 × 4 = 764 bytes under utf8mb4), matching the rank-companion
98
+ // convention: a flat 768-char prefix is 3072 bytes — exactly InnoDB's whole-index
99
+ // key limit — so ANY composite index containing a string field (e.g.
100
+ // `.index("by_project", ["projectId", "seq"])`) would exceed 3072 and fail CREATE
101
+ // INDEX with ER_TOO_LONG_KEY. 191 leaves room for several columns under the cap.
102
+ indexKeyPrefix: (kind) => MYSQL_PREFIX_INDEX_RE.test(mysqlColumnType(kind)) ? 191 : void 0,
93
103
  isUniqueViolation: (error) => {
94
104
  const candidate = error;
95
105
  return candidate.errno === 1062 || candidate.code === "ER_DUP_ENTRY";
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Public types for `@lunora/hyperdrive`.
3
+ *
4
+ * Hyperdrive points at a database **Lunora does not own**. Everything here is
5
+ * deliberately structural (no hard dependency on `@cloudflare/workers-types` or
6
+ * any SQL driver) so unit tests can pass plain-object doubles, exactly like the
7
+ * `D1DatabaseLike` projection in `@lunora/d1`.
8
+ *
9
+ * The hard constraint, restated wherever this surface is used: Hyperdrive
10
+ * queries are **non-deterministic** (forbidden in `query`/`mutation`, allowed
11
+ * only in `action`s — see the `hyperdrive_outside_action` advisor lint), and
12
+ * external writes are **invisible to Lunora live queries** — a subscription will
13
+ * NOT re-run when an external Postgres/MySQL row changes.
14
+ */
15
+ /**
16
+ * Structural projection of the Cloudflare `Hyperdrive` binding (`env.HYPERDRIVE`).
17
+ *
18
+ * Mirrors the fields of the real `Hyperdrive` from `@cloudflare/workers-types`
19
+ * but stays structural so a unit test can pass a plain object. At runtime only
20
+ * `connectionString` is needed to construct a driver; the discrete connection
21
+ * parts are surfaced for drivers that prefer a config object over a DSN.
22
+ */
23
+ interface HyperdriveLike {
24
+ /** A connection string Hyperdrive routes through its pooled, cached edge connection. */
25
+ connectionString: string;
26
+ /** Database name component of the connection. */
27
+ database: string;
28
+ /** Host Hyperdrive presents to the driver (the local proxy, not your origin DB). */
29
+ host: string;
30
+ /** Password component of the connection. */
31
+ password: string;
32
+ /** Port Hyperdrive presents to the driver. */
33
+ port: number;
34
+ /** User component of the connection. */
35
+ user: string;
36
+ }
37
+ /**
38
+ * The connection config surfaced by {@link import("./create-hyperdrive").createHyperdrive | createHyperdrive}: the raw
39
+ * `connectionString` plus the discrete parts, ready to hand to a driver.
40
+ */
41
+ interface HyperdriveConnection {
42
+ /** Database name. */
43
+ database: string;
44
+ /** Host (Hyperdrive's local proxy). */
45
+ host: string;
46
+ /** Password. */
47
+ password: string;
48
+ /** Port. */
49
+ port: number;
50
+ /** User. */
51
+ user: string;
52
+ }
53
+ /**
54
+ * The driver-agnostic SQL surface bound to `ctx.sql` on **`ActionCtx` only**.
55
+ *
56
+ * This is the exact type the generated ctx imports as
57
+ * `import("@lunora/hyperdrive").SqlClient`. Keep the name and shape stable — the
58
+ * codegen ctx wiring (Phase 1) depends on it.
59
+ *
60
+ * It is intentionally minimal — a single parameterised `query` — so it maps onto
61
+ * `postgres` (postgres.js), `pg` (node-postgres) and `mysql2` alike via the
62
+ * {@link import("./create-hyperdrive").fromPostgresJs | fromPostgresJs} /
63
+ * {@link import("./create-hyperdrive").fromNodePg | fromNodePg} /
64
+ * {@link import("./create-hyperdrive").fromMysql2 | fromMysql2} adapters. Use
65
+ * positional placeholders that match your driver (`$1, $2` for Postgres, `?` for
66
+ * MySQL); the package does not rewrite SQL.
67
+ *
68
+ * Reminder (also on the emitted JSDoc): non-deterministic, action-only,
69
+ * non-reactive — writes here are not tracked by Lunora live queries.
70
+ */
71
+ interface SqlClient {
72
+ /**
73
+ * Run a parameterised SQL statement and return the result rows.
74
+ *
75
+ * SECURITY: `text` is executed verbatim — the package never rewrites or
76
+ * escapes it. NEVER interpolate untrusted/user input into `text`; put every
77
+ * value in `params` and reference it with a positional placeholder (`$1`/`?`).
78
+ * Building `text` by string-concatenating request data is a SQL-injection
79
+ * sink against your own Postgres/MySQL. Identifiers (table/column names) can't
80
+ * be parameterised — allowlist them against a fixed set, don't interpolate.
81
+ * @param text SQL text with driver-native positional placeholders.
82
+ * @param params Bound parameter values, positionally matched to `text`.
83
+ * @returns The rows the statement produced (empty for non-`SELECT`s that
84
+ * return no rows).
85
+ */
86
+ query: <Row = Record<string, unknown>>(text: string, params?: ReadonlyArray<unknown>) => Promise<Row[]>;
87
+ }
88
+ /**
89
+ * Structural projection of a `pg` (node-postgres) `Client`/`Pool`. Only the
90
+ * `query` method `fromNodePg` calls is required, kept structural for testing.
91
+ */
92
+ interface NodePgLike {
93
+ query: (text: string, params?: ReadonlyArray<unknown>) => Promise<{
94
+ rows: unknown[];
95
+ }>;
96
+ }
97
+ /**
98
+ * Structural projection of a `postgres` (postgres.js) tagged-template client.
99
+ * The adapter uses the `.unsafe(text, params)` escape hatch so callers keep
100
+ * full control of the parameter list.
101
+ */
102
+ interface PostgresJsLike {
103
+ unsafe: (text: string, params?: ReadonlyArray<unknown>) => Promise<unknown>;
104
+ }
105
+ /**
106
+ * Structural projection of a `mysql2/promise` connection/pool. `mysql2`'s
107
+ * `execute` resolves to a `[rows, fields]` tuple; the adapter takes the first
108
+ * element as the rows.
109
+ */
110
+ interface Mysql2Like {
111
+ execute: (text: string, params?: ReadonlyArray<unknown>) => Promise<[unknown, unknown]>;
112
+ }
113
+ export { HyperdriveLike as H, Mysql2Like as M, NodePgLike as N, PostgresJsLike as P, SqlClient as S, HyperdriveConnection as a };
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Public types for `@lunora/hyperdrive`.
3
+ *
4
+ * Hyperdrive points at a database **Lunora does not own**. Everything here is
5
+ * deliberately structural (no hard dependency on `@cloudflare/workers-types` or
6
+ * any SQL driver) so unit tests can pass plain-object doubles, exactly like the
7
+ * `D1DatabaseLike` projection in `@lunora/d1`.
8
+ *
9
+ * The hard constraint, restated wherever this surface is used: Hyperdrive
10
+ * queries are **non-deterministic** (forbidden in `query`/`mutation`, allowed
11
+ * only in `action`s — see the `hyperdrive_outside_action` advisor lint), and
12
+ * external writes are **invisible to Lunora live queries** — a subscription will
13
+ * NOT re-run when an external Postgres/MySQL row changes.
14
+ */
15
+ /**
16
+ * Structural projection of the Cloudflare `Hyperdrive` binding (`env.HYPERDRIVE`).
17
+ *
18
+ * Mirrors the fields of the real `Hyperdrive` from `@cloudflare/workers-types`
19
+ * but stays structural so a unit test can pass a plain object. At runtime only
20
+ * `connectionString` is needed to construct a driver; the discrete connection
21
+ * parts are surfaced for drivers that prefer a config object over a DSN.
22
+ */
23
+ interface HyperdriveLike {
24
+ /** A connection string Hyperdrive routes through its pooled, cached edge connection. */
25
+ connectionString: string;
26
+ /** Database name component of the connection. */
27
+ database: string;
28
+ /** Host Hyperdrive presents to the driver (the local proxy, not your origin DB). */
29
+ host: string;
30
+ /** Password component of the connection. */
31
+ password: string;
32
+ /** Port Hyperdrive presents to the driver. */
33
+ port: number;
34
+ /** User component of the connection. */
35
+ user: string;
36
+ }
37
+ /**
38
+ * The connection config surfaced by {@link import("./create-hyperdrive").createHyperdrive | createHyperdrive}: the raw
39
+ * `connectionString` plus the discrete parts, ready to hand to a driver.
40
+ */
41
+ interface HyperdriveConnection {
42
+ /** Database name. */
43
+ database: string;
44
+ /** Host (Hyperdrive's local proxy). */
45
+ host: string;
46
+ /** Password. */
47
+ password: string;
48
+ /** Port. */
49
+ port: number;
50
+ /** User. */
51
+ user: string;
52
+ }
53
+ /**
54
+ * The driver-agnostic SQL surface bound to `ctx.sql` on **`ActionCtx` only**.
55
+ *
56
+ * This is the exact type the generated ctx imports as
57
+ * `import("@lunora/hyperdrive").SqlClient`. Keep the name and shape stable — the
58
+ * codegen ctx wiring (Phase 1) depends on it.
59
+ *
60
+ * It is intentionally minimal — a single parameterised `query` — so it maps onto
61
+ * `postgres` (postgres.js), `pg` (node-postgres) and `mysql2` alike via the
62
+ * {@link import("./create-hyperdrive").fromPostgresJs | fromPostgresJs} /
63
+ * {@link import("./create-hyperdrive").fromNodePg | fromNodePg} /
64
+ * {@link import("./create-hyperdrive").fromMysql2 | fromMysql2} adapters. Use
65
+ * positional placeholders that match your driver (`$1, $2` for Postgres, `?` for
66
+ * MySQL); the package does not rewrite SQL.
67
+ *
68
+ * Reminder (also on the emitted JSDoc): non-deterministic, action-only,
69
+ * non-reactive — writes here are not tracked by Lunora live queries.
70
+ */
71
+ interface SqlClient {
72
+ /**
73
+ * Run a parameterised SQL statement and return the result rows.
74
+ *
75
+ * SECURITY: `text` is executed verbatim — the package never rewrites or
76
+ * escapes it. NEVER interpolate untrusted/user input into `text`; put every
77
+ * value in `params` and reference it with a positional placeholder (`$1`/`?`).
78
+ * Building `text` by string-concatenating request data is a SQL-injection
79
+ * sink against your own Postgres/MySQL. Identifiers (table/column names) can't
80
+ * be parameterised — allowlist them against a fixed set, don't interpolate.
81
+ * @param text SQL text with driver-native positional placeholders.
82
+ * @param params Bound parameter values, positionally matched to `text`.
83
+ * @returns The rows the statement produced (empty for non-`SELECT`s that
84
+ * return no rows).
85
+ */
86
+ query: <Row = Record<string, unknown>>(text: string, params?: ReadonlyArray<unknown>) => Promise<Row[]>;
87
+ }
88
+ /**
89
+ * Structural projection of a `pg` (node-postgres) `Client`/`Pool`. Only the
90
+ * `query` method `fromNodePg` calls is required, kept structural for testing.
91
+ */
92
+ interface NodePgLike {
93
+ query: (text: string, params?: ReadonlyArray<unknown>) => Promise<{
94
+ rows: unknown[];
95
+ }>;
96
+ }
97
+ /**
98
+ * Structural projection of a `postgres` (postgres.js) tagged-template client.
99
+ * The adapter uses the `.unsafe(text, params)` escape hatch so callers keep
100
+ * full control of the parameter list.
101
+ */
102
+ interface PostgresJsLike {
103
+ unsafe: (text: string, params?: ReadonlyArray<unknown>) => Promise<unknown>;
104
+ }
105
+ /**
106
+ * Structural projection of a `mysql2/promise` connection/pool. `mysql2`'s
107
+ * `execute` resolves to a `[rows, fields]` tuple; the adapter takes the first
108
+ * element as the rows.
109
+ */
110
+ interface Mysql2Like {
111
+ execute: (text: string, params?: ReadonlyArray<unknown>) => Promise<[unknown, unknown]>;
112
+ }
113
+ export { HyperdriveLike as H, Mysql2Like as M, NodePgLike as N, PostgresJsLike as P, SqlClient as S, HyperdriveConnection as a };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/hyperdrive",
3
- "version": "1.0.0-alpha.24",
3
+ "version": "1.0.0-alpha.26",
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",
@@ -50,8 +50,9 @@
50
50
  "access": "public"
51
51
  },
52
52
  "dependencies": {
53
- "@lunora/do": "1.0.0-alpha.24",
54
- "@lunora/sql-store": "1.0.0-alpha.24",
53
+ "@lunora/do": "1.0.0-alpha.27",
54
+ "@lunora/errors": "1.0.0-alpha.4",
55
+ "@lunora/sql-store": "1.0.0-alpha.27",
55
56
  "drizzle-orm": "^0.45.2"
56
57
  },
57
58
  "peerDependencies": {