okengine 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/AGENTS.md +1 -1
  2. package/manifest.v1.schema.json +9 -1
  3. package/package.json +3 -3
  4. package/site/content/docs/console/runs.mdx +10 -0
  5. package/site/content/docs/console/traces.mdx +4 -0
  6. package/site/content/docs/elements/ai.mdx +54 -32
  7. package/site/content/docs/elements/channel.mdx +105 -14
  8. package/site/content/docs/elements/clock.mdx +1 -0
  9. package/site/content/docs/elements/flow.mdx +42 -8
  10. package/site/content/docs/get-started/basic-usage.mdx +5 -1
  11. package/site/content/docs/get-started/installation.mdx +9 -5
  12. package/site/content/docs/meta.json +2 -0
  13. package/site/content/docs/plugins/otp.mdx +58 -46
  14. package/site/content/docs/providers/azure-redis.mdx +85 -0
  15. package/site/content/docs/providers/cockroachdb.mdx +86 -0
  16. package/site/content/docs/providers/digitalocean-caching.mdx +88 -0
  17. package/site/content/docs/providers/dragonfly-cloud.mdx +82 -0
  18. package/site/content/docs/providers/elasticache.mdx +92 -0
  19. package/site/content/docs/providers/index.mdx +101 -0
  20. package/site/content/docs/providers/memorystore.mdx +89 -0
  21. package/site/content/docs/providers/meta.json +20 -0
  22. package/site/content/docs/providers/neon.mdx +115 -0
  23. package/site/content/docs/providers/redis-cloud.mdx +93 -0
  24. package/site/content/docs/providers/supabase.mdx +117 -0
  25. package/site/content/docs/providers/upstash.mdx +91 -0
  26. package/site/content/docs/providers/yugabytedb.mdx +95 -0
  27. package/site/content/docs/recipes/caddy.mdx +128 -0
  28. package/site/content/docs/recipes/cockroachdb.mdx +127 -0
  29. package/site/content/docs/recipes/dragonfly.mdx +125 -0
  30. package/site/content/docs/recipes/index.mdx +146 -0
  31. package/site/content/docs/recipes/llama-cpp.mdx +153 -0
  32. package/site/content/docs/recipes/mailpit.mdx +136 -0
  33. package/site/content/docs/recipes/meilisearch.mdx +139 -0
  34. package/site/content/docs/recipes/meta.json +31 -0
  35. package/site/content/docs/recipes/ollama.mdx +142 -0
  36. package/site/content/docs/recipes/openbao.mdx +141 -0
  37. package/site/content/docs/recipes/pgdog.mdx +137 -0
  38. package/site/content/docs/recipes/postgres.mdx +136 -0
  39. package/site/content/docs/recipes/redis.mdx +130 -0
  40. package/site/content/docs/recipes/rustfs.mdx +148 -0
  41. package/site/content/docs/recipes/sglang.mdx +105 -0
  42. package/site/content/docs/recipes/supabase-docker.mdx +145 -0
  43. package/site/content/docs/recipes/timescale.mdx +129 -0
  44. package/site/content/docs/recipes/traefik.mdx +136 -0
  45. package/site/content/docs/recipes/valkey.mdx +121 -0
  46. package/site/content/docs/recipes/vllm.mdx +106 -0
  47. package/site/content/docs/recipes/yugabytedb.mdx +135 -0
  48. package/site/content/docs/reference/cli.md +42 -6
  49. package/site/content/docs/reference/configuration.mdx +5 -3
  50. package/site/content/docs/reference/environment-variables.mdx +12 -12
  51. package/site/content/docs/reference/fx.mdx +38 -4
  52. package/src/auth/otp-capability.ts +14 -14
  53. package/src/cli/ai-setup/ai-setup.test.ts +32 -12
  54. package/src/cli/ai-setup/apply.ts +65 -23
  55. package/src/cli/ai-setup/catalog.ts +1316 -35
  56. package/src/cli/ai-setup/detect-ollama.ts +47 -0
  57. package/src/cli/ai-setup/index.ts +44 -7
  58. package/src/cli/ai-setup/prompts.ts +430 -486
  59. package/src/cli/ai-setup/recommend.test.ts +150 -50
  60. package/src/cli/ai-setup/recommend.ts +118 -101
  61. package/src/cli/ask-seed.test.ts +68 -0
  62. package/src/cli/ask-seed.ts +79 -0
  63. package/src/cli/db-seed-redact.test.ts +25 -0
  64. package/src/cli/db-seed.ts +36 -7
  65. package/src/cli/db.test.ts +1 -1
  66. package/src/cli/db.ts +2 -2
  67. package/src/cli/dev-controls.test.ts +107 -0
  68. package/src/cli/dev-controls.ts +354 -0
  69. package/src/cli/dev-schema-sync.ts +12 -4
  70. package/src/cli/dev.test.ts +50 -30
  71. package/src/cli/dev.ts +607 -66
  72. package/src/cli/drizzle-env.test.ts +40 -6
  73. package/src/cli/drizzle-env.ts +22 -1
  74. package/src/cli/ensure-drizzle-config.ts +6 -4
  75. package/src/cli/hero-meta.test.ts +13 -1
  76. package/src/cli/hero-meta.ts +28 -6
  77. package/src/cli/index.ts +5 -0
  78. package/src/cli/registry.ts +24 -0
  79. package/src/cli/replay.test.ts +105 -0
  80. package/src/cli/replay.ts +206 -0
  81. package/src/compiler/extract.ts +3 -3
  82. package/src/config/index.ts +3 -3
  83. package/src/console/server/claim.ts +3 -1
  84. package/src/console/ui/dist/assets/{index-ClX0ZCe5.js → index-D-9KFce5.js} +2 -2
  85. package/src/console/ui/dist/assets/panel-overview-CW0CQEc2.js +1 -0
  86. package/src/console/ui/dist/assets/panel-runs-BxuyDI3x.js +1 -0
  87. package/src/console/ui/dist/assets/{panel-signals-Dsxdu_AR.js → panel-signals-BXofbj7v.js} +1 -1
  88. package/src/console/ui/dist/assets/{panel-store-hy7O8HOs.js → panel-store-B8mH-arU.js} +1 -1
  89. package/src/console/ui/dist/assets/{panel-traces-CBiAe5go.js → panel-traces-DSA-ZWnf.js} +1 -1
  90. package/src/console/ui/dist/index.html +1 -1
  91. package/src/console/ui/overview/slo.ts +31 -3
  92. package/src/console/ui/overview/types.ts +6 -0
  93. package/src/console/ui/runs/errors.test.ts +53 -0
  94. package/src/console/ui/runs/errors.ts +88 -0
  95. package/src/console/ui/runs/index.ts +8 -0
  96. package/src/console/ui/runs/search.ts +16 -0
  97. package/src/console/ui/shell/panels/runs/RunsPanel.tsx +72 -1
  98. package/src/docker/ai-model-status.test.ts +101 -0
  99. package/src/docker/ai-model-status.ts +276 -0
  100. package/src/docker/compose-health.test.ts +115 -0
  101. package/src/docker/compose-health.ts +234 -0
  102. package/src/docker/compose.ts +24 -8
  103. package/src/docker/derive.ts +35 -9
  104. package/src/docker/docker.test.ts +304 -12
  105. package/src/docker/helpers.ts +56 -0
  106. package/src/docker/index.ts +52 -0
  107. package/src/docker/ollama-pull.ts +232 -0
  108. package/src/docker/recipes/cockroach.ts +24 -0
  109. package/src/docker/recipes/index.ts +32 -0
  110. package/src/docker/recipes/llama-cpp.ts +273 -0
  111. package/src/docker/recipes/ollama.ts +19 -23
  112. package/src/docker/recipes/pgdog.ts +4 -1
  113. package/src/docker/recipes/postgres.ts +5 -18
  114. package/src/docker/recipes/sglang.ts +55 -0
  115. package/src/docker/recipes/supabase.ts +21 -0
  116. package/src/docker/recipes/timescale.ts +18 -0
  117. package/src/docker/recipes/vllm.ts +44 -0
  118. package/src/docker/recipes/yugabyte.ts +23 -0
  119. package/src/docker/stack-id.test.ts +22 -0
  120. package/src/docker/stack-id.ts +38 -4
  121. package/src/docker/types.ts +15 -0
  122. package/src/drivers/ai-ollama.integration.test.ts +7 -4
  123. package/src/drivers/signal-engine.ts +10 -0
  124. package/src/drivers/signal-postgres.ts +24 -2
  125. package/src/drivers/signal-types.ts +10 -0
  126. package/src/elements/channel/fallback.test.ts +91 -0
  127. package/src/elements/channel/hard-bounce.test.ts +82 -0
  128. package/src/elements/channel/injection.test.ts +153 -0
  129. package/src/elements/channel/locale-ar.test.ts +102 -0
  130. package/src/elements/channel/otp-delivery.ts +5 -2
  131. package/src/elements/channel/receipts-ledger.test.ts +100 -0
  132. package/src/elements/channel/runtime.ts +24 -1
  133. package/src/elements/channel/test-helpers.ts +60 -0
  134. package/src/elements/channel/whatsapp-compliance.test.ts +124 -0
  135. package/src/elements/store/cache.ts +1 -1
  136. package/src/elements/store/emit-drizzle.ts +43 -9
  137. package/src/elements/store/runtime.ts +1 -1
  138. package/src/elements/store/schema-decl.test.ts +2 -0
  139. package/src/elements/store/schema-decl.ts +15 -0
  140. package/src/elements/store/seed.ts +1 -1
  141. package/src/index.ts +1 -0
  142. package/src/kernel/app.ts +118 -11
  143. package/src/kernel/boot-bind/signal.ts +6 -2
  144. package/src/kernel/boot-bind/store.ts +2 -1
  145. package/src/kernel/boot.test.ts +6 -5
  146. package/src/kernel/boot.ts +8 -3
  147. package/src/kernel/compensate.test.ts +131 -0
  148. package/src/kernel/correlation.test.ts +108 -0
  149. package/src/kernel/effect-timing.test.ts +82 -0
  150. package/src/kernel/flow.ts +38 -0
  151. package/src/kernel/fx-runs.test.ts +49 -0
  152. package/src/kernel/fx.test.ts +14 -0
  153. package/src/kernel/fx.ts +111 -1
  154. package/src/manifest/types.ts +8 -2
  155. package/src/plugins/auth-delivery.mailpit.integration.test.ts +1 -1
  156. package/src/plugins/auth-methods.security.test.ts +3 -3
  157. package/src/plugins/auth-methods.test.ts +1 -1
  158. package/src/plugins/index.ts +2 -2
  159. package/src/plugins/otp.test.ts +21 -19
  160. package/src/plugins/otp.ts +36 -34
  161. package/src/plugins/taqnyat.live.test.ts +3 -3
  162. package/src/runs/collect.ts +3 -0
  163. package/src/runs/export-otlp.ts +64 -0
  164. package/src/runs/index.ts +16 -0
  165. package/src/runs/parquet.ts +9 -0
  166. package/src/runs/types.ts +5 -0
  167. package/src/runs/window.test.ts +68 -0
  168. package/src/runs/window.ts +148 -0
  169. package/src/runtime/boot-warn.test.ts +45 -0
  170. package/src/runtime/boot-warn.ts +17 -0
  171. package/src/runtime/dev-request-log.ts +5 -5
  172. package/src/term.test.ts +95 -10
  173. package/src/term.ts +369 -14
  174. package/src/console/ui/dist/assets/panel-overview-DONDzBd2.js +0 -1
  175. package/src/console/ui/dist/assets/panel-runs-D5zf-D9c.js +0 -1
@@ -1,18 +1,30 @@
1
1
  ---
2
2
  title: "OTP"
3
- description: "Official plugin — one-time codes over SMS, WhatsApp, or email under /auth, with explicit Tier 1 or Tier 2 delivery."
3
+ description: "Official plugin — one-time codes over SMS, WhatsApp, or email under /auth, with explicit provider or app mode."
4
4
  icon: "KeyRound"
5
5
  source: "docs/spec/unified-theory.md"
6
6
  ---
7
7
 
8
- `otp()` signs people in with a one-time code. You must set `tier` — there is no
9
- auto-detect. Tier 1 is provider-owned SMS Verify; Tier 2 is app-owned delivery
10
- across the channels you declare.
8
+ `otp()` signs people in with a one-time code. You must set `mode` — there is no
9
+ auto-detect. Provider mode is SMS Verify via the bound driver; app mode is
10
+ app-owned delivery across the channels you declare.
11
11
 
12
12
  <Callout title="The one rule">
13
- Enable `gate.auth`, then `.plug(otp({ tier: 1 }))` or
14
- `.plug(otp({ tier: 2, channels: [...] }))`. Never omit `tier`. Never log raw
15
- OTPs.
13
+ Enable `gate.auth`, then `.plug(otp({ mode: "provider" }))` or
14
+ `.plug(otp({ mode: "app", channels: [...] }))`. Never omit `mode`. Never log
15
+ raw OTPs.
16
+ </Callout>
17
+
18
+ <Callout type="info" title="One otp() per app">
19
+ Provider and app mode cannot both be active — they claim the same fixed `/auth/otp/*` routes. Need
20
+ two OTP-like mechanisms? Combine `otp()` with a different plugin (e.g. `magicLink()`), not a
21
+ second `otp()`.
22
+ </Callout>
23
+
24
+ <Callout type="info" title="fx.sendOtp vs otp()">
25
+ `fx.sendOtp` / `fx.verifyOtp` are raw Channel capabilities — no `.plug()`. Direct use means you
26
+ build routes, sessions, rates, and storage yourself. `otp()` provider mode wraps that path; skip
27
+ it and call the raw methods in your own flow without losing the provider connection.
16
28
  </Callout>
17
29
 
18
30
  ## Quick start
@@ -20,7 +32,7 @@ across the channels you declare.
20
32
  <Steps>
21
33
 
22
34
  <Step>
23
- ### Plug Tier 2 (multi-channel)
35
+ ### Plug app mode (multi-channel)
24
36
 
25
37
  ```typescript title="src/app.ts"
26
38
  import { oke } from "okengine";
@@ -32,7 +44,7 @@ export const app = oke({
32
44
  gate: { auth: {} },
33
45
  }).plug(
34
46
  otp({
35
- tier: 2,
47
+ mode: "app",
36
48
  channels: ["sms", "whatsapp", "email"],
37
49
  exposeDevOtp: true, // local DX only
38
50
  }),
@@ -57,7 +69,7 @@ invalidated. Delivery follows `channels` order for addresses you pass.
57
69
  </Step>
58
70
 
59
71
  <Step>
60
- ### Resend on another channel (Tier 2 only)
72
+ ### Resend on another channel (app mode only)
61
73
 
62
74
  ```typescript
63
75
  const { data } = await api.auth.resendOtp({
@@ -67,8 +79,8 @@ const { data } = await api.auth.resendOtp({
67
79
  });
68
80
  ```
69
81
 
70
- Same code, same TTL. Default cooldown is 60 seconds. Tier 1 has no resend
71
- surface — the provider owns the code.
82
+ Same code, same TTL. Default cooldown is 60 seconds. Provider mode has no
83
+ resend surface — the provider owns the code.
72
84
 
73
85
  </Step>
74
86
 
@@ -88,23 +100,23 @@ const { data } = await api.auth.verifyOtp({
88
100
 
89
101
  </Steps>
90
102
 
91
- ## Tiers
103
+ ## Modes
92
104
 
93
- | | Tier 1 | Tier 2 |
105
+ | | Provider mode | App mode |
94
106
  | -------------------- | ----------------------------- | --------------------------------------------- |
95
- | Config | `otp({ tier: 1 })` | `otp({ tier: 2, channels: [...] })` |
107
+ | Config | `otp({ mode: "provider" })` | `otp({ mode: "app", channels: [...] })` |
96
108
  | Who owns the code | Provider (Verify API) | Your app |
97
109
  | Delivery | `fx.sendOtp` / `fx.verifyOtp` | `fx.deliverOtp` (Channel templates) |
98
110
  | Channels | SMS only | `sms` · `whatsapp` · `email` (declared order) |
99
111
  | Resend other channel | Impossible | `POST /auth/otp/resend` |
100
112
  | `exposeDevOtp` | Forbidden | Optional (default off) |
101
113
 
102
- <Callout type="warn" title="Tier 1 limitation">
103
- Resend-via-different-channel is impossible on Tier 1 — the code value is never visible to OKE. Use
104
- Tier 2 when you need SMS → email fallback for the same code.
114
+ <Callout type="warn" title="Provider mode limitation">
115
+ Resend-via-different-channel is impossible in provider mode — the code value is never visible to
116
+ OKE. Use app mode when you need SMS → email fallback for the same code.
105
117
  </Callout>
106
118
 
107
- ### Tier 1 setup
119
+ ### Provider mode setup
108
120
 
109
121
  ```typescript title="oke.config.ts"
110
122
  export default {
@@ -117,9 +129,9 @@ export default {
117
129
  ```
118
130
 
119
131
  Boot fails loudly if no SMS driver exposes `sendOtp` / `verifyOtp`. Switch to
120
- Tier 2, or bind a Verify-capable driver (for example `taqnyat`).
132
+ app mode, or bind a Verify-capable driver (for example `taqnyat`).
121
133
 
122
- ### Tier 2 delivery
134
+ ### App mode delivery
123
135
 
124
136
  | Concern | Behavior |
125
137
  | --------------- | --------------------------------------------------------------------------------------------------------------------------- |
@@ -135,42 +147,42 @@ Templates: `auth-otp-email`, `auth-otp-sms`, `auth-otp-whatsapp` (EN/AR,
135
147
 
136
148
  ## Options
137
149
 
138
- | Option | Type | Default | Meaning |
139
- | ------------------ | -------------------------------- | -------------------------- | --------------------------------- |
140
- | `tier` | `1 \| 2` | required | Delivery mechanism — no auto |
141
- | `channels` | `("sms"\|"whatsapp"\|"email")[]` | required on Tier 2 | Build-time preferred order |
142
- | `ttlMs` | `number` | 10m | Challenge lifetime |
143
- | `resendCooldownMs` | `number` | 60s | Tier 2 resend spacing |
144
- | `exposeDevOtp` | `boolean` | `false` | Tier 2 only — raw OTP in response |
145
- | `from` | `string` | `OKE <no-reply@oke.local>` | Email template From |
146
- | `secret` | `string` | active\* | Auth secret (\*from `gate.auth`) |
147
- | `sessions` | `SessionStore` | active\* | Session store |
148
- | `identities` | `IdentityStore` | new | Email → user |
149
- | `phones` | `PhoneStore` | new | Phone → user |
150
- | `verifications` | `VerificationStore` | new | Challenge store |
150
+ | Option | Type | Default | Meaning |
151
+ | ------------------ | -------------------------------- | -------------------------- | ----------------------------------- |
152
+ | `mode` | `"provider" \| "app"` | required | Delivery mechanism — no auto |
153
+ | `channels` | `("sms"\|"whatsapp"\|"email")[]` | required in app mode | Build-time preferred order |
154
+ | `ttlMs` | `number` | 10m | Challenge lifetime |
155
+ | `resendCooldownMs` | `number` | 60s | App-mode resend spacing |
156
+ | `exposeDevOtp` | `boolean` | `false` | App mode only — raw OTP in response |
157
+ | `from` | `string` | `OKE <no-reply@oke.local>` | Email template From |
158
+ | `secret` | `string` | active\* | Auth secret (\*from `gate.auth`) |
159
+ | `sessions` | `SessionStore` | active\* | Session store |
160
+ | `identities` | `IdentityStore` | new | Email → user |
161
+ | `phones` | `PhoneStore` | new | Phone → user |
162
+ | `verifications` | `VerificationStore` | new | Challenge store |
151
163
 
152
164
  ## Surfaces
153
165
 
154
- | Flow | Path | Gate | Tier |
155
- | ----------------- | ------------------------ | ------------------------ | ------ |
156
- | `auth.requestOtp` | `POST /auth/otp/request` | `gate.public` + otp rate | 1 + 2 |
157
- | `auth.verifyOtp` | `POST /auth/otp/verify` | `gate.public` + otp rate | 1 + 2 |
158
- | `auth.resendOtp` | `POST /auth/otp/resend` | `gate.public` + otp rate | 2 only |
166
+ | Flow | Path | Gate | Mode |
167
+ | ----------------- | ------------------------ | ------------------------ | ------------- |
168
+ | `auth.requestOtp` | `POST /auth/otp/request` | `gate.public` + otp rate | both |
169
+ | `auth.verifyOtp` | `POST /auth/otp/verify` | `gate.public` + otp rate | both |
170
+ | `auth.resendOtp` | `POST /auth/otp/resend` | `gate.public` + otp rate | app mode only |
159
171
 
160
172
  ## Troubleshooting
161
173
 
162
174
  <Accordions>
163
- <Accordion title='otp(): tier is required'>
175
+ <Accordion title='otp(): mode is required'>
164
176
 
165
- You omitted `tier`. Set `tier: 1` or `tier: 2` explicitly — OKE never infers
166
- which mechanism you meant.
177
+ You omitted `mode`. Set `mode: "provider"` or `mode: "app"` explicitly — OKE
178
+ never infers which mechanism you meant.
167
179
 
168
180
  </Accordion>
169
- <Accordion title="Boot fails on Tier 1">
181
+ <Accordion title="Boot fails in provider mode">
170
182
 
171
183
  No Verify-capable SMS driver is bound. Set `drivers.channel.sms` to `taqnyat`
172
184
  (or another driver with `sendOtp`/`verifyOtp`), or switch to
173
- `otp({ tier: 2, channels: [...] })`.
185
+ `otp({ mode: "app", channels: [...] })`.
174
186
 
175
187
  </Accordion>
176
188
  <Accordion title="resend_cooldown">
@@ -179,7 +191,7 @@ Wait for `resendCooldownMs` (default 60s). The challenge TTL is unchanged —
179
191
  only delivery is rate-limited.
180
192
 
181
193
  </Accordion>
182
- <Accordion title="No email / SMS with the code (Tier 2)">
194
+ <Accordion title="No email / SMS with the code (app mode)">
183
195
 
184
196
  In `local` / `test` the `console` driver captures messages. Use
185
197
  `exposeDevOtp: true` for unit tests without a real provider.
@@ -190,7 +202,7 @@ In `local` / `test` the `console` driver captures messages. Use
190
202
  ## Learn more
191
203
 
192
204
  - [Magic link](/docs/plugins/magic-link) — link instead of a code
193
- - [Channel](/docs/elements/channel) — `fx.send`, drivers, Mailpit
205
+ - [Channel](/docs/elements/channel) — `fx.send`, `fx.sendOtp`, drivers, Mailpit
194
206
  - [Gate](/docs/elements/gate) — `gate.auth`
195
207
 
196
208
  ## Next
@@ -0,0 +1,85 @@
1
+ ---
2
+ title: "Azure Cache for Redis"
3
+ description: "Azure-managed Redis — Access keys blade, TLS port 6380 vs 6379, Basic tier no SLA."
4
+ icon: "Zap"
5
+ source: "docs/spec/unified-theory.md"
6
+ ---
7
+
8
+ Azure Cache for Redis spans Basic → Enterprise. New caches expect TLS.
9
+ `drivers.store.kv` stays `redis`.
10
+
11
+ <Callout title="The one rule">
12
+ Build `rediss://` from **Overview** hostname + **Access keys** primary key + SSL port **6380**. Do
13
+ not use 6379 unless you explicitly allowed non-TLS.
14
+ </Callout>
15
+
16
+ ## Find credentials (current portal)
17
+
18
+ 1. Azure Portal → your **Azure Cache for Redis** resource.
19
+ 2. **Overview** → copy **Host name** (`….redis.cache.windows.net`).
20
+ 3. **Settings → Authentication** → **Access keys** tab (or **Overview → Show access
21
+ keys**) → copy **Primary** key.
22
+ 4. Ports: Overview link next to **Ports**, or docs defaults — **6380** TLS, **6379**
23
+ non-TLS (disabled by default on new caches).
24
+ 5. Enterprise tiers may use port **10000** — check Overview for that SKU.
25
+
26
+ ```bash title="process env"
27
+ REDIS_URL=rediss://:PRIMARY_KEY@my-cache.redis.cache.windows.net:6380
28
+ ```
29
+
30
+ Azure's “connection string” blade often shows StackExchange-style
31
+ `host:6380,password=…,ssl=True` — translate that to `rediss://:password@host:6380` for
32
+ oke.
33
+
34
+ ## Production guidance
35
+
36
+ | Tier | Notes |
37
+ | -------------------- | --------------------------------------- |
38
+ | Basic | Shared, **no SLA** — not for production |
39
+ | Standard | Replicated |
40
+ | Premium / Enterprise | Clustering, persistence, VNet |
41
+
42
+ Non-TLS: **Settings → Advanced settings → Allow access only via SSL = No** — avoid in
43
+ production. Entra ID auth exists on newer tiers; oke's URL driver expects access-key
44
+ auth in `REDIS_URL`.
45
+
46
+ ## Real gotcha — port 6380 vs 6379
47
+
48
+ Using `redis://…:6379` against a TLS-only cache fails. New caches disable non-TLS;
49
+ always start from **6380** + `rediss://` unless you intentionally opened 6379.
50
+
51
+ ## Troubleshooting
52
+
53
+ <Accordions>
54
+ <Accordion title="Connection reset / SSL errors on 6379">
55
+
56
+ TLS-only cache. Switch to port **6380** and `rediss://`. Confirm Advanced settings still
57
+ require SSL.
58
+
59
+ </Accordion>
60
+ <Accordion title="WRONGPASS invalid username-password pair">
61
+
62
+ Primary key rotated or secondary key pasted by mistake. Re-copy **Primary** from
63
+ **Authentication → Access keys** and update `REDIS_URL` (empty username, key as
64
+ password).
65
+
66
+ </Accordion>
67
+ </Accordions>
68
+
69
+ ## Learn more
70
+
71
+ - [Redis (image)](/docs/recipes/redis)
72
+ - [ElastiCache](/docs/providers/elasticache) · [Memorystore](/docs/providers/memorystore)
73
+ - [Store · KV](/docs/elements/store#kv)
74
+
75
+ ## Next
76
+
77
+ <Cards>
78
+ <Card title="ElastiCache" description="AWS's equivalent." href="/docs/providers/elasticache" />
79
+ <Card title="Memorystore" description="GCP's equivalent." href="/docs/providers/memorystore" />
80
+ <Card
81
+ title="CockroachDB"
82
+ description="Managed SQL-side pair."
83
+ href="/docs/providers/cockroachdb"
84
+ />
85
+ </Cards>
@@ -0,0 +1,86 @@
1
+ ---
2
+ title: "CockroachDB"
3
+ description: "Distributed SQL — Cloud Connect dialog, verify-full + CA cert, CSL license, port 26257."
4
+ icon: "Database"
5
+ source: "docs/spec/unified-theory.md"
6
+ ---
7
+
8
+ CockroachDB speaks Postgres wire closely enough that `drivers.store.sql` stays
9
+ `postgres`. Multi-region and distributed transactions are Cockroach's concern beneath
10
+ that protocol.
11
+
12
+ <Callout title="The one rule">
13
+ Use the Cloud Console **Connect** dialog and keep `sslmode=verify-full` with the downloaded CA —
14
+ `sslmode=require` alone is rejected for secure clusters.
15
+ </Callout>
16
+
17
+ ## Find credentials (current console)
18
+
19
+ 1. Open [CockroachDB Cloud](https://cockroachlabs.cloud) → your **cluster**.
20
+ 2. Click **Connect** (cluster overview / top right).
21
+ 3. Open the **Connection string** tab (or **General connection string**).
22
+ 4. Expand **Download CA Cert** — run the provided command so `root.crt` lands in the
23
+ default Postgres cert directory (or note the path).
24
+ 5. Copy the `postgresql://…` string; paste the password when prompted (shown once for
25
+ new SQL users — reset under **SQL Users** if lost).
26
+
27
+ ```bash title="process env"
28
+ DATABASE_URL=postgresql://user:password@….cockroachlabs.cloud:26257/defaultdb?sslmode=verify-full&sslrootcert=/path/to/root.crt
29
+ ```
30
+
31
+ Default SQL port is **26257**, not 5432.
32
+
33
+ ## Production guidance
34
+
35
+ | Topic | Guidance |
36
+ | ------- | --------------------------------------------------------------------------------------- |
37
+ | TLS | `verify-full` + `sslrootcert` — required for Cloud |
38
+ | Pooling | Prefer Cockroach's guidance / built-in limits; do not assume Neon-style `-pooler` hosts |
39
+ | Regions | Configure survivability in the Console — opaque to the `postgres` driver |
40
+
41
+ CockroachDB Software License (since Nov 2024): Core open-source discontinued; free for
42
+ orgs under $10M ARR with community support; paid tiers add dedicated support. Not OSI
43
+ open source.
44
+
45
+ ## Real gotcha — CA cert path
46
+
47
+ Copying the connection string without downloading the CA yields TLS verify failures
48
+ even when the password is correct. The Connect dialog's download command and
49
+ `sslrootcert=` must agree on the same file path in the environment that runs the app.
50
+
51
+ ## Troubleshooting
52
+
53
+ <Accordions>
54
+ <Accordion title="certificate verify failed / SSL connection error">
55
+
56
+ Missing or wrong `sslrootcert`. Re-download from **Connect → Download CA Cert**, point
57
+ `sslrootcert` at that file, keep `sslmode=verify-full`. Using `require` without verify
58
+ is not accepted for Cloud's default secure posture.
59
+
60
+ </Accordion>
61
+ <Accordion title="password authentication failed for user">
62
+
63
+ Password is shown once at user creation. Reset under the cluster **SQL Users** page,
64
+ then update `DATABASE_URL`.
65
+
66
+ </Accordion>
67
+ </Accordions>
68
+
69
+ ## Learn more
70
+
71
+ - [YugabyteDB](/docs/providers/yugabytedb) — Apache 2.0 distributed alternative
72
+ - [CockroachDB (self-hosted)](/docs/recipes/cockroachdb) — single-node Docker recipe
73
+ - [Postgres (image)](/docs/recipes/postgres) — driver this backs
74
+ - [Store · SQL](/docs/elements/store#sql) — schema workflows
75
+
76
+ ## Next
77
+
78
+ <Cards>
79
+ <Card
80
+ title="YugabyteDB"
81
+ description="Apache-2.0 licensed alternative."
82
+ href="/docs/providers/yugabytedb"
83
+ />
84
+ <Card title="Neon" description="Serverless single-region option." href="/docs/providers/neon" />
85
+ <Card title="PgDog" description="Self-hosted pooling." href="/docs/recipes/pgdog" />
86
+ </Cards>
@@ -0,0 +1,88 @@
1
+ ---
2
+ title: "DigitalOcean Managed Caching"
3
+ description: "Valkey-backed DO Databases — Overview Connection Details, trusted sources, TLS-required high port."
4
+ icon: "Zap"
5
+ source: "docs/spec/unified-theory.md"
6
+ ---
7
+
8
+ DigitalOcean's managed Redis offering moved to **Valkey** (Managed Caching) after Aiven
9
+ stepped back from Redis. Wire protocol unchanged — `drivers.store.kv` stays `redis`.
10
+
11
+ <Callout title="The one rule">
12
+ Databases → cluster → **Overview → Connection Details**. Copy the `rediss://` URI (public or
13
+ private). Add the client to **Trusted Sources** or you get connection refused.
14
+ </Callout>
15
+
16
+ ## Find credentials (current control panel)
17
+
18
+ 1. [cloud.digitalocean.com/databases](https://cloud.digitalocean.com/databases) → click
19
+ the **Valkey / Caching** cluster.
20
+ 2. **Overview** → **Connection Details**:
21
+ - Toggle **Public network** vs **Private network** (VPC)
22
+ - Copy host, port, user, password, or the assembled connection string
23
+ 3. Password is hidden until you reveal/copy it in that panel.
24
+ 4. **Network Access** / trusted sources: add app Droplet, App Platform app, or VPC CIDR
25
+ (from Overview **VPC Network**) before connecting.
26
+
27
+ ```bash title="process env"
28
+ REDIS_URL=rediss://default:PASSWORD@db-valkey-nyc1-….db.ondigitalocean.com:25061
29
+ ```
30
+
31
+ Port is a **random high port** from Connection Details — not `6379`. TLS is required;
32
+ there is no plaintext option.
33
+
34
+ ## Production guidance
35
+
36
+ | Topic | Guidance |
37
+ | --------------- | ------------------------------------------------------------------------------------- |
38
+ | Engine | **Valkey** on new clusters; older “Managed Redis” capped / unsupported past Redis 7.2 |
39
+ | TLS | Always — use `rediss://` |
40
+ | Trusted sources | Hard firewall — missing entry ⇒ refused even with correct password |
41
+ | VPC | Prefer private connection string + VPC CIDR as a single trusted source |
42
+
43
+ Standalone **Upstash-on-DigitalOcean marketplace** listings are a different, deprecated
44
+ product — not this Databases service.
45
+
46
+ ## Real gotcha — trusted sources
47
+
48
+ Correct `REDIS_URL` from a laptop not in Trusted Sources fails with connection refused.
49
+ Add your IP (or use a Droplet already allowed / VPC CIDR) under **Network Access**.
50
+
51
+ ## Troubleshooting
52
+
53
+ <Accordions>
54
+ <Accordion title="Connection refused (hostname)">
55
+
56
+ Wrong port, or client IP not in trusted sources. Re-copy port from **Connection
57
+ Details**; add the client under **Network Access → Trusted Sources**.
58
+
59
+ </Accordion>
60
+ <Accordion title="Connection refused (IP) on private hostname">
61
+
62
+ Private URL used from outside the VPC. Switch to **Public network** details (and allow
63
+ your IP), or run the app on a Droplet in the same VPC with the private URI.
64
+
65
+ </Accordion>
66
+ </Accordions>
67
+
68
+ ## Learn more
69
+
70
+ - [Valkey (image)](/docs/recipes/valkey) — self-hosted peer
71
+ - [Store · KV](/docs/elements/store#kv)
72
+ - [Dragonfly Cloud](/docs/providers/dragonfly-cloud) — alternative managed KV
73
+
74
+ ## Next
75
+
76
+ <Cards>
77
+ <Card
78
+ title="Dragonfly Cloud"
79
+ description="Another managed alternative."
80
+ href="/docs/providers/dragonfly-cloud"
81
+ />
82
+ <Card
83
+ title="Redis Cloud"
84
+ description="Vendor-native alternative."
85
+ href="/docs/providers/redis-cloud"
86
+ />
87
+ <Card title="Caddy" description="Local proxy pairing." href="/docs/recipes/caddy" />
88
+ </Cards>
@@ -0,0 +1,82 @@
1
+ ---
2
+ title: "Dragonfly Cloud"
3
+ description: "Managed Dragonfly — data store row drawer, Redis-compatible Connection URI, TLS passkey, private network prod."
4
+ icon: "Zap"
5
+ source: "docs/spec/unified-theory.md"
6
+ ---
7
+
8
+ Dragonfly Cloud runs the same multi-threaded engine as the
9
+ [Dragonfly image](/docs/recipes/dragonfly), with a managed endpoint.
10
+ `drivers.store.kv` stays `redis`.
11
+
12
+ <Callout title="The one rule">
13
+ Click the **data store row** to open the side drawer — copy the **Redis-compatible Connection
14
+ URI** (includes passkey). Paste it as `REDIS_URL`.
15
+ </Callout>
16
+
17
+ ## Find credentials (current console)
18
+
19
+ 1. Open Dragonfly Cloud → **Data Stores**.
20
+ 2. Wait until **Status** is **Active**.
21
+ 3. Click the data store **row** (opens the configuration drawer).
22
+ 4. Copy:
23
+ - **Redis-compatible Connection URI** (e.g. `rediss://default:PASS@….dragonflydb.cloud:6385`)
24
+ - or host / port / `default` user / passkey separately
25
+ 5. Paste the URI into `REDIS_URL` unchanged when it already uses `rediss://`.
26
+
27
+ ```bash title="process env"
28
+ REDIS_URL=rediss://default:PASSKEY@xxxxx.dragonflydb.cloud:6385
29
+ ```
30
+
31
+ Smoke-check: `redis-cli -u "$REDIS_URL" PING`.
32
+
33
+ ## Production guidance
34
+
35
+ | Topic | Guidance |
36
+ | --------------- | ---------------------------------------------------------------------------- |
37
+ | Public network | TLS + passkey **on** by default — leave TLS enabled |
38
+ | Private network | Recommended for production (peering) — passkey still required on public |
39
+ | HA | Enable high availability in the data store settings before you need failover |
40
+ | Driver | Same `redis` driver as self-hosted Dragonfly |
41
+ | Port | Drawer URI often uses **6385** (not 6379) — copy the URI wholesale |
42
+
43
+ Self-hosting comparison: the [Dragonfly image](/docs/recipes/dragonfly) needs
44
+ `OKE_STORE_KV_PASSWORD` + `memlock`; Cloud replaces that with the drawer passkey.
45
+
46
+ Do not reuse a self-hosted `REDIS_URL` without `rediss://` when the drawer shows TLS.
47
+
48
+ ## Real gotcha — connecting before Active
49
+
50
+ The drawer is visible while the store is still provisioning; clients get connection
51
+ errors until **Status = Active**. Wait for Active before wiring CI or app boot.
52
+
53
+ ## Troubleshooting
54
+
55
+ <Accordions>
56
+ <Accordion title="Connection refused / timeout while Status is not Active">
57
+
58
+ Provisioning. Retry when the console shows **Active**. Do not rotate the passkey yet —
59
+ confirm status first.
60
+
61
+ </Accordion>
62
+ <Accordion title="NOAUTH / WRONGPASS">
63
+
64
+ URI missing the passkey, or passkey rotated in the drawer without updating env. Re-copy
65
+ the Connection URI from the data store drawer after any rotation.
66
+
67
+ </Accordion>
68
+ </Accordions>
69
+
70
+ ## Learn more
71
+
72
+ - [Dragonfly (image)](/docs/recipes/dragonfly) — self-hosted peer
73
+ - [Store · KV](/docs/elements/store#kv)
74
+ - [Upstash](/docs/providers/upstash) — serverless alternative
75
+
76
+ ## Next
77
+
78
+ <Cards>
79
+ <Card title="Upstash" description="Serverless-friendly option." href="/docs/providers/upstash" />
80
+ <Card title="Redis Cloud" description="Vendor-native Redis." href="/docs/providers/redis-cloud" />
81
+ <Card title="YugabyteDB" description="Managed SQL-side pair." href="/docs/providers/yugabytedb" />
82
+ </Cards>
@@ -0,0 +1,92 @@
1
+ ---
2
+ title: "Amazon ElastiCache"
3
+ description: "AWS-managed Redis OSS or Valkey — Primary Endpoint, AUTH token, Redis OSS capped at 7.1, VPC-only."
4
+ icon: "Zap"
5
+ source: "docs/spec/unified-theory.md"
6
+ ---
7
+
8
+ ElastiCache runs Redis OSS-compatible or Valkey engines inside your VPC. Both speak the
9
+ same wire protocol — `drivers.store.kv` stays `redis`.
10
+
11
+ <Callout title="The one rule">
12
+ Copy the **Primary Endpoint** (cluster mode disabled) from the ElastiCache console — not a replica
13
+ reader endpoint. Use `rediss://` when encryption in transit is on.
14
+ </Callout>
15
+
16
+ ## Find credentials (current console)
17
+
18
+ 1. AWS Console → **ElastiCache** → **Valkey caches** or **Redis OSS caches**.
19
+ 2. Click the **cluster name** (not only the radio button).
20
+ 3. On the cluster detail page, copy:
21
+ - **Primary Endpoint** (+ port, usually `6379`) for cluster-mode **disabled**
22
+ - **Configuration Endpoint** for cluster-mode **enabled** (needs a cluster-aware
23
+ client — oke's single-URL driver expects non-cluster / primary)
24
+ 4. Auth: cluster **Connectivity** / **Auth token** (or Secrets Manager reference) —
25
+ set at creation or rotation; there is no “password eye” identical to Redis Cloud.
26
+ 5. Build `REDIS_URL` yourself:
27
+
28
+ ```bash title="process env"
29
+ # Encryption in transit ON (default on many new clusters)
30
+ REDIS_URL=rediss://:AUTH_TOKEN@my-cluster.xxxxx.ng.0001.use1.cache.amazonaws.com:6379
31
+
32
+ # Transit encryption OFF
33
+ # REDIS_URL=redis://:AUTH_TOKEN@my-cluster.xxxxx.ng.0001.use1.cache.amazonaws.com:6379
34
+ ```
35
+
36
+ ## Production guidance
37
+
38
+ | Topic | Guidance |
39
+ | ------------------ | ----------------------------------------------------------------------------------- |
40
+ | Networking | **VPC-only** — app must share VPC, peering, or PrivateLink; no public hostname |
41
+ | Engine | Redis OSS **or** Valkey — same `redis` driver |
42
+ | Cluster mode | Prefer **disabled** + Primary Endpoint for oke's URL-shaped client |
43
+ | Transit encryption | When enabled, scheme must be `rediss://` |
44
+ | AUTH | Set at create/rotate — ElastiCache does not show a Redis-Cloud-style “eye” password |
45
+
46
+ Reader endpoints exist for read scaling; oke's single `REDIS_URL` should target the
47
+ **Primary Endpoint** so writes and Gate/Signal counters hit the primary.
48
+
49
+ ## Real gotcha — Redis OSS version cap
50
+
51
+ ElastiCache **Redis OSS tops out at 7.1**. Versions **7.2+ are Valkey-only**. You can
52
+ in-place upgrade Redis OSS → Valkey 7.2; planning a “Redis 7.2” engine on ElastiCache
53
+ is a category error — pick Valkey or stay ≤7.1 on Redis OSS.
54
+
55
+ ## Troubleshooting
56
+
57
+ <Accordions>
58
+ <Accordion title="Connection timed out from laptop / CI">
59
+
60
+ Expected — no public endpoint. Run the app in the VPC (ECS/EKS/EC2) or use a bastion /
61
+ VPN. Security groups must allow the app SG → cache port.
62
+
63
+ </Accordion>
64
+ <Accordion title="WRONGPASS / NOAUTH after enabling AUTH">
65
+
66
+ Token not embedded in `REDIS_URL`, or still using `redis://` against a TLS-required
67
+ endpoint. Match scheme to **Encryption in-transit**, put the token after `rediss://:`.
68
+
69
+ </Accordion>
70
+ </Accordions>
71
+
72
+ ## Learn more
73
+
74
+ - [Redis (image)](/docs/recipes/redis) · [Valkey (image)](/docs/recipes/valkey)
75
+ - [Memorystore](/docs/providers/memorystore) — GCP equivalent
76
+ - [Store · KV](/docs/elements/store#kv)
77
+
78
+ ## Next
79
+
80
+ <Cards>
81
+ <Card title="Memorystore" description="GCP's equivalent." href="/docs/providers/memorystore" />
82
+ <Card
83
+ title="Azure Cache for Redis"
84
+ description="Azure's equivalent."
85
+ href="/docs/providers/azure-redis"
86
+ />
87
+ <Card
88
+ title="Redis Cloud"
89
+ description="Vendor-neutral managed option."
90
+ href="/docs/providers/redis-cloud"
91
+ />
92
+ </Cards>