@shaferllc/keel 0.83.2 → 0.83.4
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 +7 -24
- package/dist/billing/billable.d.ts +1 -0
- package/dist/billing/billable.js +8 -0
- package/dist/billing/drivers/fake.d.ts +4 -0
- package/dist/billing/drivers/fake.js +5 -0
- package/dist/billing/drivers/stripe.d.ts +1 -0
- package/dist/billing/drivers/stripe.js +7 -0
- package/dist/billing/gateway.d.ts +7 -0
- package/dist/billing/index.d.ts +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/tokens.d.ts +2 -0
- package/dist/core/tokens.js +24 -0
- package/dist/gates/index.d.ts +10 -0
- package/dist/gates/index.js +9 -0
- package/dist/gates/models.d.ts +42 -0
- package/dist/gates/models.js +76 -0
- package/dist/gates/provider.d.ts +10 -0
- package/dist/gates/provider.js +13 -0
- package/dist/hosting/cloudflare.d.ts +43 -0
- package/dist/hosting/cloudflare.js +66 -0
- package/dist/hosting/dump.d.ts +7 -0
- package/dist/hosting/dump.js +58 -0
- package/dist/hosting/hostname.d.ts +7 -0
- package/dist/hosting/hostname.js +25 -0
- package/dist/hosting/index.d.ts +14 -0
- package/dist/hosting/index.js +12 -0
- package/dist/hosting/secrets.d.ts +15 -0
- package/dist/hosting/secrets.js +27 -0
- package/dist/mcp/cloud.d.ts +9 -0
- package/dist/mcp/cloud.js +179 -0
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.js +20 -1
- package/docs/ai-manifest.json +20 -1
- package/docs/ai.md +36 -0
- package/docs/billing.md +10 -1
- package/docs/changelog.md +30 -0
- package/docs/examples/gates.ts +30 -0
- package/docs/examples/hosting.ts +37 -0
- package/docs/gates.md +75 -0
- package/docs/hosting.md +97 -0
- package/llms-full.txt +232 -1
- package/llms.txt +4 -0
- package/package.json +9 -1
package/docs/hosting.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Hosting
|
|
2
|
+
|
|
3
|
+
Keel Hosting is a small toolkit for **hosted Workers / D1 apps**: a Cloudflare
|
|
4
|
+
REST client, hostname helpers, a SQLite-compatible SQL dump, and purpose-scoped
|
|
5
|
+
secret encryption. It ships as `@shaferllc/keel/hosting`.
|
|
6
|
+
|
|
7
|
+
This is infrastructure — not a control plane. Site orchestration, plans, and
|
|
8
|
+
deploy loops live in your app (for example Keel Cloud).
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import {
|
|
14
|
+
CloudflareClient,
|
|
15
|
+
cloudflareConfigured,
|
|
16
|
+
normalizeHostname,
|
|
17
|
+
isValidHostname,
|
|
18
|
+
zoneCandidates,
|
|
19
|
+
dumpConnection,
|
|
20
|
+
normalizeSecretKey,
|
|
21
|
+
encryptSecretValue,
|
|
22
|
+
decryptSecretValue,
|
|
23
|
+
resolveSecretRows,
|
|
24
|
+
} from "@shaferllc/keel/hosting";
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
No service provider — import what you need.
|
|
28
|
+
|
|
29
|
+
## Cloudflare
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
const creds = {
|
|
33
|
+
accountId: process.env.CF_ACCOUNT_ID!,
|
|
34
|
+
apiToken: process.env.CF_API_TOKEN!,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
if (!cloudflareConfigured(creds)) {
|
|
38
|
+
throw new Error("Cloudflare credentials missing");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const cf = new CloudflareClient(creds);
|
|
42
|
+
const db = await cf.createD1Database("kc-acme");
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Credentials are constructor args — no app config coupling. Optional
|
|
46
|
+
`pinnedZoneId` / `pinnedZoneName` skip a zone lookup when you already know the
|
|
47
|
+
primary zone.
|
|
48
|
+
|
|
49
|
+
## Hostnames
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
const host = normalizeHostname("https://App.Example.com/"); // "app.example.com"
|
|
53
|
+
isValidHostname(host); // true
|
|
54
|
+
zoneCandidates(host); // ["app.example.com", "example.com"]
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`zoneCandidates` walks from most-specific to apex — useful when attaching a
|
|
58
|
+
Workers Custom Domain and you need to find which zone owns the name.
|
|
59
|
+
|
|
60
|
+
## SQL dump
|
|
61
|
+
|
|
62
|
+
Dump any SQLite-compatible `Connection` to a portable `.sql` script (schema +
|
|
63
|
+
data). Useful for export / escape hatches:
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { db } from "@shaferllc/keel/core";
|
|
67
|
+
import { dumpConnection } from "@shaferllc/keel/hosting";
|
|
68
|
+
|
|
69
|
+
const sql = await dumpConnection(db(), "Acme local D1", { generatedBy: "Keel Cloud" });
|
|
70
|
+
// write sql to a .sql file; restore with sqlite3 / D1 import
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Secrets
|
|
74
|
+
|
|
75
|
+
Encrypt vault values with Keel's purpose-scoped encryption (`config('app.key')`
|
|
76
|
+
must be set). Keys are normalized to `ENV_STYLE` identifiers:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
const key = normalizeSecretKey("stripe-secret-key"); // "STRIPE_SECRET_KEY"
|
|
80
|
+
const encrypted = await encryptSecretValue(secret, "app-secret");
|
|
81
|
+
const plain = await decryptSecretValue(encrypted, "app-secret");
|
|
82
|
+
|
|
83
|
+
const env = await resolveSecretRows(
|
|
84
|
+
[{ key: "STRIPE_SECRET_KEY", value_encrypted: encrypted }],
|
|
85
|
+
"app-secret",
|
|
86
|
+
);
|
|
87
|
+
// { STRIPE_SECRET_KEY: "…" }
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Your app owns the table of rows (`owner_id`, `key`, `value_encrypted`); hosting
|
|
91
|
+
only encrypts and decrypts.
|
|
92
|
+
|
|
93
|
+
## Related
|
|
94
|
+
|
|
95
|
+
- [Gates](./gates.md) — private-alpha signup gating used by hosted control planes
|
|
96
|
+
- [Starter kits](./starter-kits.md) — presets Cloud scaffolds from
|
|
97
|
+
- [Building with AI](./ai.md) — MCP Cloud tools (`keel_cloud_*`) that drive hosting
|
package/llms-full.txt
CHANGED
|
@@ -4725,6 +4725,35 @@ package, so it always matches your installed version.
|
|
|
4725
4725
|
| `keel_list_generators` | The `keel make:*` generators, what they produce, and their flags. |
|
|
4726
4726
|
| `keel_scaffold` | Generate a controller/provider/middleware/factory/seeder/job/notification/transformer stub. Returns code + target path — it does **not** write to disk. |
|
|
4727
4727
|
|
|
4728
|
+
When `KEEL_CLOUD_TOKEN` (and optional `KEEL_CLOUD_URL`) is set, Cloud tools are
|
|
4729
|
+
also registered:
|
|
4730
|
+
|
|
4731
|
+
| Tool | What it does |
|
|
4732
|
+
|------|--------------|
|
|
4733
|
+
| `keel_cloud_me` | Authenticated Cloud user |
|
|
4734
|
+
| `keel_cloud_list_sites` / `keel_cloud_get_site` | List or fetch a site (includes `storage_path`) |
|
|
4735
|
+
| `keel_cloud_create_site` | Create from preset (`minimal` \| `api` \| `app` \| `saas`) |
|
|
4736
|
+
| `keel_cloud_preview` | Deploy preview Worker |
|
|
4737
|
+
| `keel_cloud_publish` | Publish production — requires `confirm: true` |
|
|
4738
|
+
| `keel_cloud_set_secret` | Vault a secret (injected on next deploy) |
|
|
4739
|
+
| `keel_cloud_deploys` / `keel_cloud_export` | Deploy history and export manifest |
|
|
4740
|
+
| `keel_cloud_export_sql` | Portable `.sql` dump (`local` \| `preview` \| `production`) |
|
|
4741
|
+
|
|
4742
|
+
```json
|
|
4743
|
+
{
|
|
4744
|
+
"mcpServers": {
|
|
4745
|
+
"keel": {
|
|
4746
|
+
"command": "npx",
|
|
4747
|
+
"args": ["-y", "keel-mcp"],
|
|
4748
|
+
"env": {
|
|
4749
|
+
"KEEL_CLOUD_TOKEN": "kc_…",
|
|
4750
|
+
"KEEL_CLOUD_URL": "https://app.keeljs.cloud"
|
|
4751
|
+
}
|
|
4752
|
+
}
|
|
4753
|
+
}
|
|
4754
|
+
}
|
|
4755
|
+
```
|
|
4756
|
+
|
|
4728
4757
|
### Resources
|
|
4729
4758
|
|
|
4730
4759
|
- `keel://overview` — the same orientation text as `keel_overview`
|
|
@@ -4739,6 +4768,13 @@ package, so it always matches your installed version.
|
|
|
4739
4768
|
4. `keel_scaffold { kind: "controller", name: "Post", resource: true }` → get the stub.
|
|
4740
4769
|
5. Write the file, add the route, run `npm run typecheck`.
|
|
4741
4770
|
|
|
4771
|
+
### A typical Keel Cloud loop
|
|
4772
|
+
|
|
4773
|
+
1. `keel_cloud_create_site { name: "Acme", preset: "app" }`
|
|
4774
|
+
2. Edit the returned `storage_path` (real Keel app + git)
|
|
4775
|
+
3. `keel_cloud_preview { site_id }`
|
|
4776
|
+
4. `keel_cloud_publish { site_id, confirm: true }` after the user approves
|
|
4777
|
+
|
|
4742
4778
|
## `llms.txt` and `llms-full.txt`
|
|
4743
4779
|
|
|
4744
4780
|
At the package root:
|
|
@@ -5716,6 +5752,15 @@ const intent = await user.createSetupIntent(); // return intent.clientSecret to
|
|
|
5716
5752
|
const methods = await user.paymentMethods();
|
|
5717
5753
|
```
|
|
5718
5754
|
|
|
5755
|
+
### Customer portal (Stripe)
|
|
5756
|
+
|
|
5757
|
+
Send the customer to Stripe's hosted portal to update their card or cancel:
|
|
5758
|
+
|
|
5759
|
+
```ts
|
|
5760
|
+
const portal = await user.billingPortal("https://app.example.com/billing");
|
|
5761
|
+
// redirect to portal.url
|
|
5762
|
+
```
|
|
5763
|
+
|
|
5719
5764
|
These are Stripe-only capabilities; calling them on the Paddle gateway throws a
|
|
5720
5765
|
`BillingError` (Paddle collects cards in its own hosted checkout).
|
|
5721
5766
|
|
|
@@ -5810,7 +5855,7 @@ real gateway from `config/billing.ts` and `.env`.
|
|
|
5810
5855
|
|---------|--------|--------|
|
|
5811
5856
|
| Create a subscription server-side | `create(pmId)` | Not supported — use `checkout()`; the webhook creates the local row |
|
|
5812
5857
|
| One-off `charge()` | Confirms a PaymentIntent | Not supported — use `checkout({ mode })` / transactions |
|
|
5813
|
-
| SetupIntent / `paymentMethods()` | Supported | Throws `BillingError` (hosted checkout) |
|
|
5858
|
+
| SetupIntent / `paymentMethods()` / `billingPortal()` | Supported | Throws `BillingError` (hosted checkout) |
|
|
5814
5859
|
| Checkout handle | `session.url` (redirect) | `session.clientToken` (overlay/inline) |
|
|
5815
5860
|
| Webhook signature | `Stripe-Signature: t=…,v1=…` | `Paddle-Signature: ts=…;h1=…` |
|
|
5816
5861
|
|
|
@@ -9429,6 +9474,88 @@ definition function.
|
|
|
9429
9474
|
|
|
9430
9475
|
|
|
9431
9476
|
|
|
9477
|
+
---
|
|
9478
|
+
|
|
9479
|
+
<!-- source: docs/gates.md -->
|
|
9480
|
+
|
|
9481
|
+
# Gates
|
|
9482
|
+
|
|
9483
|
+
Keel Gates is a **signup gate** for private alpha / waitlist apps: an email
|
|
9484
|
+
allowlist, invite codes with use limits and expiry, and a single check that
|
|
9485
|
+
answers "may this person register?". It ships as `@shaferllc/keel/gates`.
|
|
9486
|
+
|
|
9487
|
+
This is **not** authorization (`can` / policies in [authorization](./authorization.md))
|
|
9488
|
+
and **not** team invitations ([teams](./teams.md)). Those answer different
|
|
9489
|
+
questions. Gates answers only: *is this email allowed to create an account?*
|
|
9490
|
+
|
|
9491
|
+
## Install
|
|
9492
|
+
|
|
9493
|
+
```ts
|
|
9494
|
+
// bootstrap/providers.ts
|
|
9495
|
+
import { GatesServiceProvider } from "@shaferllc/keel/gates";
|
|
9496
|
+
|
|
9497
|
+
export const providers = [AppServiceProvider, GatesServiceProvider];
|
|
9498
|
+
```
|
|
9499
|
+
|
|
9500
|
+
Then migrate — the provider contributes `invite_codes` and `email_allowlist`
|
|
9501
|
+
tables (`CREATE TABLE IF NOT EXISTS`, so existing apps stay safe):
|
|
9502
|
+
|
|
9503
|
+
```bash
|
|
9504
|
+
keel migrate
|
|
9505
|
+
```
|
|
9506
|
+
|
|
9507
|
+
## Checking registration
|
|
9508
|
+
|
|
9509
|
+
```ts
|
|
9510
|
+
import { canRegister, redeemInvite } from "@shaferllc/keel/gates";
|
|
9511
|
+
|
|
9512
|
+
const gate = await canRegister(email, inviteCode);
|
|
9513
|
+
if (!gate.ok) {
|
|
9514
|
+
return json({ error: gate.reason }, 403);
|
|
9515
|
+
}
|
|
9516
|
+
|
|
9517
|
+
// …create the user…
|
|
9518
|
+
|
|
9519
|
+
if (gate.via === "code" && gate.invite) {
|
|
9520
|
+
await redeemInvite(gate.invite); // increments uses
|
|
9521
|
+
}
|
|
9522
|
+
```
|
|
9523
|
+
|
|
9524
|
+
`canRegister` returns:
|
|
9525
|
+
|
|
9526
|
+
| Result | Meaning |
|
|
9527
|
+
|--------|---------|
|
|
9528
|
+
| `{ ok: true, via: "allowlist" }` | Email is on `email_allowlist` |
|
|
9529
|
+
| `{ ok: true, via: "code", invite }` | Valid invite code (not expired, uses left) |
|
|
9530
|
+
| `{ ok: false, reason }` | Rejected — show `reason` to the user |
|
|
9531
|
+
|
|
9532
|
+
Allowlist wins over codes: if the email is allowlisted, the code is ignored.
|
|
9533
|
+
|
|
9534
|
+
## Managing codes and allowlist
|
|
9535
|
+
|
|
9536
|
+
The models are ordinary Keel models — create rows from an admin UI or a seeder:
|
|
9537
|
+
|
|
9538
|
+
```ts
|
|
9539
|
+
import { InviteCode, EmailAllowlist } from "@shaferllc/keel/gates";
|
|
9540
|
+
|
|
9541
|
+
await InviteCode.create({
|
|
9542
|
+
code: "ALPHA-42",
|
|
9543
|
+
max_uses: 10,
|
|
9544
|
+
uses: 0,
|
|
9545
|
+
expires_at: null,
|
|
9546
|
+
});
|
|
9547
|
+
|
|
9548
|
+
await EmailAllowlist.create({ email: "ada@example.com" });
|
|
9549
|
+
```
|
|
9550
|
+
|
|
9551
|
+
## Related
|
|
9552
|
+
|
|
9553
|
+
- [Accounts](./accounts.md) — register / login flows that call `canRegister` first
|
|
9554
|
+
- [Teams](./teams.md) — invitations *into* a team, after the user already exists
|
|
9555
|
+
- [Authorization](./authorization.md) — ability checks once they're signed in
|
|
9556
|
+
|
|
9557
|
+
|
|
9558
|
+
|
|
9432
9559
|
---
|
|
9433
9560
|
|
|
9434
9561
|
<!-- source: docs/hashing.md -->
|
|
@@ -10597,6 +10724,110 @@ The signature of `onReady` / `onShutdown` hooks.
|
|
|
10597
10724
|
|
|
10598
10725
|
|
|
10599
10726
|
|
|
10727
|
+
---
|
|
10728
|
+
|
|
10729
|
+
<!-- source: docs/hosting.md -->
|
|
10730
|
+
|
|
10731
|
+
# Hosting
|
|
10732
|
+
|
|
10733
|
+
Keel Hosting is a small toolkit for **hosted Workers / D1 apps**: a Cloudflare
|
|
10734
|
+
REST client, hostname helpers, a SQLite-compatible SQL dump, and purpose-scoped
|
|
10735
|
+
secret encryption. It ships as `@shaferllc/keel/hosting`.
|
|
10736
|
+
|
|
10737
|
+
This is infrastructure — not a control plane. Site orchestration, plans, and
|
|
10738
|
+
deploy loops live in your app (for example Keel Cloud).
|
|
10739
|
+
|
|
10740
|
+
## Install
|
|
10741
|
+
|
|
10742
|
+
```ts
|
|
10743
|
+
import {
|
|
10744
|
+
CloudflareClient,
|
|
10745
|
+
cloudflareConfigured,
|
|
10746
|
+
normalizeHostname,
|
|
10747
|
+
isValidHostname,
|
|
10748
|
+
zoneCandidates,
|
|
10749
|
+
dumpConnection,
|
|
10750
|
+
normalizeSecretKey,
|
|
10751
|
+
encryptSecretValue,
|
|
10752
|
+
decryptSecretValue,
|
|
10753
|
+
resolveSecretRows,
|
|
10754
|
+
} from "@shaferllc/keel/hosting";
|
|
10755
|
+
```
|
|
10756
|
+
|
|
10757
|
+
No service provider — import what you need.
|
|
10758
|
+
|
|
10759
|
+
## Cloudflare
|
|
10760
|
+
|
|
10761
|
+
```ts
|
|
10762
|
+
const creds = {
|
|
10763
|
+
accountId: process.env.CF_ACCOUNT_ID!,
|
|
10764
|
+
apiToken: process.env.CF_API_TOKEN!,
|
|
10765
|
+
};
|
|
10766
|
+
|
|
10767
|
+
if (!cloudflareConfigured(creds)) {
|
|
10768
|
+
throw new Error("Cloudflare credentials missing");
|
|
10769
|
+
}
|
|
10770
|
+
|
|
10771
|
+
const cf = new CloudflareClient(creds);
|
|
10772
|
+
const db = await cf.createD1Database("kc-acme");
|
|
10773
|
+
```
|
|
10774
|
+
|
|
10775
|
+
Credentials are constructor args — no app config coupling. Optional
|
|
10776
|
+
`pinnedZoneId` / `pinnedZoneName` skip a zone lookup when you already know the
|
|
10777
|
+
primary zone.
|
|
10778
|
+
|
|
10779
|
+
## Hostnames
|
|
10780
|
+
|
|
10781
|
+
```ts
|
|
10782
|
+
const host = normalizeHostname("https://App.Example.com/"); // "app.example.com"
|
|
10783
|
+
isValidHostname(host); // true
|
|
10784
|
+
zoneCandidates(host); // ["app.example.com", "example.com"]
|
|
10785
|
+
```
|
|
10786
|
+
|
|
10787
|
+
`zoneCandidates` walks from most-specific to apex — useful when attaching a
|
|
10788
|
+
Workers Custom Domain and you need to find which zone owns the name.
|
|
10789
|
+
|
|
10790
|
+
## SQL dump
|
|
10791
|
+
|
|
10792
|
+
Dump any SQLite-compatible `Connection` to a portable `.sql` script (schema +
|
|
10793
|
+
data). Useful for export / escape hatches:
|
|
10794
|
+
|
|
10795
|
+
```ts
|
|
10796
|
+
import { db } from "@shaferllc/keel/core";
|
|
10797
|
+
import { dumpConnection } from "@shaferllc/keel/hosting";
|
|
10798
|
+
|
|
10799
|
+
const sql = await dumpConnection(db(), "Acme local D1", { generatedBy: "Keel Cloud" });
|
|
10800
|
+
// write sql to a .sql file; restore with sqlite3 / D1 import
|
|
10801
|
+
```
|
|
10802
|
+
|
|
10803
|
+
## Secrets
|
|
10804
|
+
|
|
10805
|
+
Encrypt vault values with Keel's purpose-scoped encryption (`config('app.key')`
|
|
10806
|
+
must be set). Keys are normalized to `ENV_STYLE` identifiers:
|
|
10807
|
+
|
|
10808
|
+
```ts
|
|
10809
|
+
const key = normalizeSecretKey("stripe-secret-key"); // "STRIPE_SECRET_KEY"
|
|
10810
|
+
const encrypted = await encryptSecretValue(secret, "app-secret");
|
|
10811
|
+
const plain = await decryptSecretValue(encrypted, "app-secret");
|
|
10812
|
+
|
|
10813
|
+
const env = await resolveSecretRows(
|
|
10814
|
+
[{ key: "STRIPE_SECRET_KEY", value_encrypted: encrypted }],
|
|
10815
|
+
"app-secret",
|
|
10816
|
+
);
|
|
10817
|
+
// { STRIPE_SECRET_KEY: "…" }
|
|
10818
|
+
```
|
|
10819
|
+
|
|
10820
|
+
Your app owns the table of rows (`owner_id`, `key`, `value_encrypted`); hosting
|
|
10821
|
+
only encrypts and decrypts.
|
|
10822
|
+
|
|
10823
|
+
## Related
|
|
10824
|
+
|
|
10825
|
+
- [Gates](./gates.md) — private-alpha signup gating used by hosted control planes
|
|
10826
|
+
- [Starter kits](./starter-kits.md) — presets Cloud scaffolds from
|
|
10827
|
+
- [Building with AI](./ai.md) — MCP Cloud tools (`keel_cloud_*`) that drive hosting
|
|
10828
|
+
|
|
10829
|
+
|
|
10830
|
+
|
|
10600
10831
|
---
|
|
10601
10832
|
|
|
10602
10833
|
<!-- source: docs/i18n.md -->
|
package/llms.txt
CHANGED
|
@@ -30,12 +30,14 @@ Userland imports everything from `@shaferllc/keel/core`.
|
|
|
30
30
|
- [Errors & Exceptions](https://github.com/shaferllc/keel/blob/main/docs/errors.md): Throw an exception anywhere — a handler, middleware, or a service deep in the container — and Keel's HTTP kernel turns it into the right response.
|
|
31
31
|
- [Events](https://github.com/shaferllc/keel/blob/main/docs/events.md): A tiny event emitter for decoupling — fire an event in one place, handle it in another.
|
|
32
32
|
- [Factories & Seeders](https://github.com/shaferllc/keel/blob/main/docs/factories.md): Populate the database with realistic fixtures for tests and demos.
|
|
33
|
+
- [Gates](https://github.com/shaferllc/keel/blob/main/docs/gates.md): Keel Gates is a signup gate for private alpha / waitlist apps: an email allowlist, invite codes with use limits and expiry, and a single check that answers "may this person register?".
|
|
33
34
|
- [Getting Started](https://github.com/shaferllc/keel/blob/main/docs/getting-started.md): Keel is a house framework for Node.js — a small, legible MVC layer over Hono.
|
|
34
35
|
- [Hashing & Encryption](https://github.com/shaferllc/keel/blob/main/docs/hashing.md): Password hashing and value encryption, both built on the Web Crypto API — so they run identically on Node and the edge, with no native bindings (no bcrypt to compile).
|
|
35
36
|
- [Health Checks](https://github.com/shaferllc/keel/blob/main/docs/health.md): Two endpoints, answering the two questions an orchestrator — Kubernetes, Fly, Railway, a load balancer — actually asks:
|
|
36
37
|
- [Helpers](https://github.com/shaferllc/keel/blob/main/docs/helpers.md): Keel gives you a handful of global helper functions so you can reach the running application from anywhere — a route handler, a model, a plain function — without threading a container reference through every call.
|
|
37
38
|
- [Built on Hono](https://github.com/shaferllc/keel/blob/main/docs/hono.md): Keel's HTTP layer is Hono — an ultrafast, web-standard router that runs on Node, Cloudflare Workers, Deno, Bun, and more.
|
|
38
39
|
- [Lifecycle Hooks](https://github.com/shaferllc/keel/blob/main/docs/hooks.md): Tap into the application lifecycle — run code once the app is ready, clean up on shutdown, and observe route registration.
|
|
40
|
+
- [Hosting](https://github.com/shaferllc/keel/blob/main/docs/hosting.md): Keel Hosting is a small toolkit for hosted Workers / D1 apps: a Cloudflare REST client, hostname helpers, a SQLite-compatible SQL dump, and purpose-scoped secret encryption.
|
|
39
41
|
- [Internationalization](https://github.com/shaferllc/keel/blob/main/docs/i18n.md): Translations with ICU message formatting, plus the Intl formatters that go with them.
|
|
40
42
|
- [Inertia](https://github.com/shaferllc/keel/blob/main/docs/inertia.md): Keel ships a server-side Inertia.js adapter.
|
|
41
43
|
- [Locks](https://github.com/shaferllc/keel/blob/main/docs/locks.md): "Only one of you may do this at a time" — across processes, across nodes.
|
|
@@ -97,11 +99,13 @@ Every topic has a runnable, type-checked example:
|
|
|
97
99
|
- [Errors & Exceptions example](https://github.com/shaferllc/keel/blob/main/docs/examples/errors.ts)
|
|
98
100
|
- [Events example](https://github.com/shaferllc/keel/blob/main/docs/examples/events.ts)
|
|
99
101
|
- [Factories & Seeders example](https://github.com/shaferllc/keel/blob/main/docs/examples/factories.ts)
|
|
102
|
+
- [Gates example](https://github.com/shaferllc/keel/blob/main/docs/examples/gates.ts)
|
|
100
103
|
- [Hashing & Encryption example](https://github.com/shaferllc/keel/blob/main/docs/examples/hashing.ts)
|
|
101
104
|
- [Health Checks example](https://github.com/shaferllc/keel/blob/main/docs/examples/health.ts)
|
|
102
105
|
- [Helpers example](https://github.com/shaferllc/keel/blob/main/docs/examples/helpers.ts)
|
|
103
106
|
- [Built on Hono example](https://github.com/shaferllc/keel/blob/main/docs/examples/hono.ts)
|
|
104
107
|
- [Lifecycle Hooks example](https://github.com/shaferllc/keel/blob/main/docs/examples/hooks.ts)
|
|
108
|
+
- [Hosting example](https://github.com/shaferllc/keel/blob/main/docs/examples/hosting.ts)
|
|
105
109
|
- [Internationalization example](https://github.com/shaferllc/keel/blob/main/docs/examples/i18n.ts)
|
|
106
110
|
- [Inertia example](https://github.com/shaferllc/keel/blob/main/docs/examples/inertia.ts)
|
|
107
111
|
- [Locks example](https://github.com/shaferllc/keel/blob/main/docs/examples/locks.ts)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shaferllc/keel",
|
|
3
|
-
"version": "0.83.
|
|
3
|
+
"version": "0.83.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The house framework for Node.js — a service container, providers, routing, JSX views, and a code-generating console.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -77,6 +77,14 @@
|
|
|
77
77
|
"types": "./dist/billing/index.d.ts",
|
|
78
78
|
"import": "./dist/billing/index.js"
|
|
79
79
|
},
|
|
80
|
+
"./gates": {
|
|
81
|
+
"types": "./dist/gates/index.d.ts",
|
|
82
|
+
"import": "./dist/gates/index.js"
|
|
83
|
+
},
|
|
84
|
+
"./hosting": {
|
|
85
|
+
"types": "./dist/hosting/index.d.ts",
|
|
86
|
+
"import": "./dist/hosting/index.js"
|
|
87
|
+
},
|
|
80
88
|
"./cli": {
|
|
81
89
|
"types": "./dist/core/cli/index.d.ts",
|
|
82
90
|
"import": "./dist/core/cli/index.js"
|