@lunora/hyperdrive 0.0.0 → 1.0.0-alpha.10
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/LICENSE.md +105 -0
- package/README.md +171 -9
- package/__assets__/package-og.svg +14 -0
- package/dist/global.d.mts +69 -0
- package/dist/global.d.ts +69 -0
- package/dist/global.mjs +9 -0
- package/dist/index.d.mts +165 -0
- package/dist/index.d.ts +165 -0
- package/dist/index.mjs +1 -0
- package/dist/packem_shared/buildMysqlExec-DBbCjyq3.mjs +23 -0
- package/dist/packem_shared/createHyperdrive-DD8GoDZo.mjs +36 -0
- package/dist/packem_shared/mysqlDialect-oNhZ58s8.mjs +102 -0
- package/package.json +62 -17
package/LICENSE.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Functional Source License, Version 1.1, Apache 2.0 Future License
|
|
2
|
+
|
|
3
|
+
## Abbreviation
|
|
4
|
+
|
|
5
|
+
FSL-1.1-Apache-2.0
|
|
6
|
+
|
|
7
|
+
## Notice
|
|
8
|
+
|
|
9
|
+
Copyright 2026 anolilab and contributors
|
|
10
|
+
|
|
11
|
+
## Terms and Conditions
|
|
12
|
+
|
|
13
|
+
### Licensor ("We")
|
|
14
|
+
|
|
15
|
+
The party offering the Software under these Terms and Conditions.
|
|
16
|
+
|
|
17
|
+
### The Software
|
|
18
|
+
|
|
19
|
+
The "Software" is each version of the software that we make available under
|
|
20
|
+
these Terms and Conditions, as indicated by our inclusion of these Terms and
|
|
21
|
+
Conditions with the Software.
|
|
22
|
+
|
|
23
|
+
### License Grant
|
|
24
|
+
|
|
25
|
+
Subject to your compliance with this License Grant and the Patents,
|
|
26
|
+
Redistribution and Trademark clauses below, we hereby grant you the right to
|
|
27
|
+
use, copy, modify, create derivative works, publicly perform, publicly display
|
|
28
|
+
and redistribute the Software for any Permitted Purpose identified below.
|
|
29
|
+
|
|
30
|
+
### Permitted Purpose
|
|
31
|
+
|
|
32
|
+
A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
|
|
33
|
+
means making the Software available to others in a commercial product or service
|
|
34
|
+
that:
|
|
35
|
+
|
|
36
|
+
1. substitutes for the Software;
|
|
37
|
+
|
|
38
|
+
2. substitutes for any other product or service we offer using the Software that
|
|
39
|
+
exists as of the date we make the Software available; or
|
|
40
|
+
|
|
41
|
+
3. offers the same or substantially similar functionality as the Software.
|
|
42
|
+
|
|
43
|
+
Permitted Purposes specifically include using the Software:
|
|
44
|
+
|
|
45
|
+
1. for your internal use and access;
|
|
46
|
+
|
|
47
|
+
2. for non-commercial education;
|
|
48
|
+
|
|
49
|
+
3. for non-commercial research; and
|
|
50
|
+
|
|
51
|
+
4. in connection with professional services that you provide to a licensee using
|
|
52
|
+
the Software in accordance with these Terms and Conditions.
|
|
53
|
+
|
|
54
|
+
### Patents
|
|
55
|
+
|
|
56
|
+
To the extent your use for a Permitted Purpose would necessarily infringe our
|
|
57
|
+
patents, the license grant above includes a license under our patents. If you
|
|
58
|
+
make a claim against any party that the Software infringes or contributes to the
|
|
59
|
+
infringement of any patent, then your patent license to the Software ends
|
|
60
|
+
immediately.
|
|
61
|
+
|
|
62
|
+
### Redistribution
|
|
63
|
+
|
|
64
|
+
The Terms and Conditions apply to all copies, modifications and derivatives of
|
|
65
|
+
the Software.
|
|
66
|
+
|
|
67
|
+
If you redistribute any copies, modifications or derivatives of the Software,
|
|
68
|
+
you must include a copy of or a link to these Terms and Conditions and not
|
|
69
|
+
remove any copyright notices provided in or with the Software.
|
|
70
|
+
|
|
71
|
+
### Disclaimer
|
|
72
|
+
|
|
73
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
|
|
74
|
+
IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
|
|
75
|
+
PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
|
|
76
|
+
|
|
77
|
+
IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
|
|
78
|
+
SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, EVEN
|
|
79
|
+
IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
|
|
80
|
+
|
|
81
|
+
### Trademarks
|
|
82
|
+
|
|
83
|
+
Except for displaying the License Details and identifying us as the origin of
|
|
84
|
+
the Software, you have no right under these Terms and Conditions to use our
|
|
85
|
+
trademarks, trade names, service marks or product names.
|
|
86
|
+
|
|
87
|
+
## Grant of Future License
|
|
88
|
+
|
|
89
|
+
We hereby irrevocably grant you an additional license to use the Software under
|
|
90
|
+
the Apache License, Version 2.0 that is effective on the second anniversary of
|
|
91
|
+
the date we make the Software available. On or after that date, you may use the
|
|
92
|
+
Software under the Apache License, Version 2.0, in which case the following will
|
|
93
|
+
apply:
|
|
94
|
+
|
|
95
|
+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
|
96
|
+
this file except in compliance with the License.
|
|
97
|
+
|
|
98
|
+
You may obtain a copy of the License at
|
|
99
|
+
|
|
100
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
101
|
+
|
|
102
|
+
Unless required by applicable law or agreed to in writing, software distributed
|
|
103
|
+
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
104
|
+
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
105
|
+
specific language governing permissions and limitations under the License.
|
package/README.md
CHANGED
|
@@ -1,18 +1,180 @@
|
|
|
1
|
-
|
|
1
|
+
<!-- START_PACKAGE_OG_IMAGE_PLACEHOLDER -->
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<a href="https://www.anolilab.com/open-source" align="center">
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
<img src="__assets__/package-og.svg" alt="hyperdrive" />
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
</a>
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
- Repository: https://github.com/anolilab/lunora
|
|
9
|
+
<h3 align="center">Bring-your-own Postgres/MySQL for Lunora via Cloudflare Hyperdrive: a driver-agnostic, action-only ctx.sql</h3>
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
<!-- END_PACKAGE_OG_IMAGE_PLACEHOLDER -->
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
<br />
|
|
14
|
+
|
|
15
|
+
<div align="center">
|
|
16
|
+
|
|
17
|
+
[![typescript-image][typescript-badge]][typescript-url]
|
|
18
|
+
[![FSL-1.1-Apache-2.0 licence][license-badge]][license]
|
|
19
|
+
[![npm version][npm-version-badge]][npm-version]
|
|
20
|
+
[![npm downloads][npm-downloads-badge]][npm-downloads]
|
|
21
|
+
[![PRs Welcome][prs-welcome-badge]][prs-welcome]
|
|
22
|
+
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
<div align="center">
|
|
28
|
+
<p>
|
|
29
|
+
<sup>
|
|
30
|
+
Daniel Bannert's open source work is supported by the community on <a href="https://github.com/sponsors/prisis">GitHub Sponsors</a>
|
|
31
|
+
</sup>
|
|
32
|
+
</p>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
Integrate an existing Postgres or MySQL database into Lunora from **actions**, through [Cloudflare Hyperdrive](https://developers.cloudflare.com/hyperdrive/). `@lunora/hyperdrive` surfaces the binding's connection string and a driver-agnostic `SqlClient` bound to `ctx.sql` — **on `ActionCtx` only**.
|
|
38
|
+
|
|
39
|
+
Part of the [Lunora](https://github.com/anolilab/lunora) framework — a type-safe, real-time backend on Cloudflare Workers + Durable Objects with a Vite-first DX.
|
|
40
|
+
|
|
41
|
+
> ### ⚠️ Integrate, don't replace — read this first
|
|
42
|
+
>
|
|
43
|
+
> Hyperdrive talks to a database **Lunora does not own**. That breaks two invariants the rest of Lunora relies on:
|
|
44
|
+
>
|
|
45
|
+
> 1. **Non-deterministic (action-only).** A SQL query over Hyperdrive is a network call with an external, mutable result — exactly like `fetch`. It is **forbidden in `query`/`mutation`** (which must be deterministic so the coordinator can re-run them on OCC retry / subscription re-evaluation) and allowed **only in `action`s**. The `hyperdrive_outside_action` advisor lint flags `ctx.sql` used in a query/mutation.
|
|
46
|
+
> 2. **Non-reactive.** External writes do **not** flow through the Durable-Object / SQLite change-feed, so **Lunora live queries and subscriptions will NOT re-run** when an external Postgres/MySQL row changes. There is no honest way to make external writes reactive here.
|
|
47
|
+
>
|
|
48
|
+
> Use Hyperdrive to _read/write your existing DB from an action_. It is the **wrong** tool for "make my Postgres reactive". If you want external data to be reactive, write a **projection** of it into a `defineSchema` DO/D1 table from the action — that write _is_ tracked.
|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
npm install @lunora/hyperdrive
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
pnpm add @lunora/hyperdrive
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
You bring your own driver — `@lunora/hyperdrive` bundles none (they are `optional` peer deps). Install exactly one of:
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
pnpm add postgres # postgres.js → fromPostgresJs
|
|
64
|
+
pnpm add pg # node-postgres → fromNodePg
|
|
65
|
+
pnpm add mysql2 # mysql2 → fromMysql2
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Setup
|
|
69
|
+
|
|
70
|
+
1. Create the Hyperdrive config and mint its id (Lunora can't fabricate the remote id):
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
wrangler hyperdrive create my-db --connection-string="postgres://user:pass@host:5432/db" # gitleaks:allow -- placeholder, not a real secret
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
2. Add the binding to `wrangler.jsonc` (use `localConnectionString` for local dev):
|
|
77
|
+
|
|
78
|
+
```jsonc
|
|
79
|
+
{
|
|
80
|
+
"hyperdrive": [{ "binding": "HYPERDRIVE", "id": "<id from step 1>", "localConnectionString": "postgres://user:pass@localhost:5432/db" }], // gitleaks:allow -- placeholder, not a real secret
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Usage
|
|
85
|
+
|
|
86
|
+
`ctx.sql` is wired by codegen onto `ActionCtx` only — never `QueryCtx`/`MutationCtx`. The procedure builders (`action`, `v`) and `api` come from your app-local generated modules:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { createHyperdrive, fromPostgresJs } from "@lunora/hyperdrive";
|
|
90
|
+
import postgres from "postgres";
|
|
91
|
+
|
|
92
|
+
import { api } from "@/lunora/_generated/api";
|
|
93
|
+
import { action, v } from "@/lunora/_generated/server";
|
|
94
|
+
|
|
95
|
+
export const syncCustomer = action.input({ orgId: v.string() }).action(async ({ args: { orgId }, ctx }) => {
|
|
96
|
+
const { connectionString } = createHyperdrive(ctx.env.HYPERDRIVE);
|
|
97
|
+
ctx.sql = fromPostgresJs(postgres(connectionString));
|
|
98
|
+
|
|
99
|
+
const rows = await ctx.sql.query<{ id: string; name: string }>("select id, name from customers where org = $1", [orgId]);
|
|
100
|
+
|
|
101
|
+
// Want it reactive? Project it into a Lunora table — THIS write is tracked.
|
|
102
|
+
await ctx.runMutation(api.customers.upsertMany, { rows });
|
|
103
|
+
|
|
104
|
+
return rows;
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`SqlClient` is intentionally minimal — one parameterised `query<Row>(text, params)` — mapping cleanly onto postgres.js, node-postgres and mysql2. The package does not rewrite SQL: use `$1, $2` for Postgres and `?` for MySQL, matching your driver.
|
|
109
|
+
|
|
110
|
+
| Driver | Adapter | Placeholders |
|
|
111
|
+
| ------------------------ | ---------------- | ------------ |
|
|
112
|
+
| `postgres` (postgres.js) | `fromPostgresJs` | `$1, $2, …` |
|
|
113
|
+
| `pg` (node-postgres) | `fromNodePg` | `$1, $2, …` |
|
|
114
|
+
| `mysql2/promise` | `fromMysql2` | `?` |
|
|
115
|
+
|
|
116
|
+
## Reactive `.global()` over Hyperdrive
|
|
117
|
+
|
|
118
|
+
The `@lunora/hyperdrive/global` subpath is the opposite trade-off: Lunora **owns** the schema and a `.global()` table gets a real column-per-field layout on your Postgres/MySQL, with every write routed through the shared store core. Live queries stay reactive — identical to D1 — because the writer drives the same broadcast hook. Build the writer inside the Durable Object that hosts the `.global()` store and inject it as `globalDb`:
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
import { createPostgresGlobalCtxDb } from "@lunora/hyperdrive/global";
|
|
122
|
+
import postgres from "postgres";
|
|
123
|
+
|
|
124
|
+
// `sql` is a postgres.js client built from the HYPERDRIVE binding's connection string.
|
|
125
|
+
const globalDb = createPostgresGlobalCtxDb({ query: (text, params) => sql.unsafe(text, params) }, { schema });
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
For MySQL use `createMysqlGlobalCtxDb` with a `mysql2/promise` pool created with `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.
|
|
129
|
+
|
|
130
|
+
> This README covers the basics. For the full API and the determinism/realtime rationale, see the **[documentation](https://lunora.sh/docs/addons/hyperdrive)**.
|
|
131
|
+
|
|
132
|
+
## Non-goals
|
|
133
|
+
|
|
134
|
+
- No logical-replication / CDC ingestion of external Postgres into Lunora tables (the only honest path to a "reactive external DB"; a large, separate effort — out of scope).
|
|
135
|
+
- No `ctx.sql` in `query`/`mutation` (forbidden by design; lint-enforced).
|
|
136
|
+
- No bundled driver and no opinionated ORM — you own driver choice and lifecycle.
|
|
137
|
+
|
|
138
|
+
## Related
|
|
139
|
+
|
|
140
|
+
- [`@lunora/server`](https://www.npmjs.com/package/@lunora/server) — call `ctx.sql` from actions.
|
|
141
|
+
- [`@lunora/d1`](https://www.npmjs.com/package/@lunora/d1) — Lunora-owned, reactive D1 for `.global()` tables.
|
|
142
|
+
- [`@lunora/sql-store`](https://www.npmjs.com/package/@lunora/sql-store) — the shared store core behind the reactive `@lunora/hyperdrive/global` backend.
|
|
143
|
+
- [`@lunora/advisor`](https://www.npmjs.com/package/@lunora/advisor) — ships the `hyperdrive_outside_action` lint.
|
|
144
|
+
|
|
145
|
+
## Supported Node.js Versions
|
|
146
|
+
|
|
147
|
+
Libraries in this ecosystem make the best effort to track [Node.js' release schedule](https://github.com/nodejs/release#release-schedule).
|
|
148
|
+
Here's [a post on why we think this is important](https://medium.com/the-node-js-collection/maintainers-should-consider-following-node-js-release-schedule-ab08ed4de71a).
|
|
149
|
+
|
|
150
|
+
## Contributing
|
|
151
|
+
|
|
152
|
+
If you would like to help take a look at the [list of issues](https://github.com/anolilab/lunora/issues) and check our [Contributing](https://github.com/anolilab/lunora/blob/alpha/.github/CONTRIBUTING.md) guidelines.
|
|
153
|
+
|
|
154
|
+
> **Note:** please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.
|
|
155
|
+
|
|
156
|
+
## Credits
|
|
157
|
+
|
|
158
|
+
- [Daniel Bannert](https://github.com/prisis)
|
|
159
|
+
- [All Contributors](https://github.com/anolilab/lunora/graphs/contributors)
|
|
160
|
+
|
|
161
|
+
## Made with ❤️ at Anolilab
|
|
162
|
+
|
|
163
|
+
This is an open source project and will always remain free to use. If you think it's cool, please star it 🌟. [Anolilab](https://www.anolilab.com/open-source) is a Development and AI Studio. Contact us at [hello@anolilab.com](mailto:hello@anolilab.com) if you need any help with these technologies or just want to say hi!
|
|
15
164
|
|
|
16
165
|
## License
|
|
17
166
|
|
|
18
|
-
FSL-1.1-Apache-2.0
|
|
167
|
+
The Lunora hyperdrive package is open-sourced software licensed under the [FSL-1.1-Apache-2.0][license].
|
|
168
|
+
|
|
169
|
+
<!-- badges -->
|
|
170
|
+
|
|
171
|
+
[license-badge]: https://img.shields.io/badge/license-FSL--1.1--Apache--2.0-blue.svg?style=for-the-badge
|
|
172
|
+
[license]: https://github.com/anolilab/lunora/blob/alpha/LICENSE.md
|
|
173
|
+
[npm-version-badge]: https://img.shields.io/npm/v/@lunora/hyperdrive?style=for-the-badge
|
|
174
|
+
[npm-version]: https://www.npmjs.com/package/@lunora/hyperdrive
|
|
175
|
+
[npm-downloads-badge]: https://img.shields.io/npm/dm/@lunora/hyperdrive?style=for-the-badge
|
|
176
|
+
[npm-downloads]: https://www.npmjs.com/package/@lunora/hyperdrive
|
|
177
|
+
[prs-welcome-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=for-the-badge
|
|
178
|
+
[prs-welcome]: https://github.com/anolilab/lunora/blob/alpha/.github/CONTRIBUTING.md
|
|
179
|
+
[typescript-badge]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript
|
|
180
|
+
[typescript-url]: https://www.typescriptlang.org/
|