omnigateway 0.7.3 → 0.8.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 (42) hide show
  1. package/README.md +90 -4
  2. package/bin/omni.js +7969 -5797
  3. package/gateway.js +17222 -14645
  4. package/package.json +1 -1
  5. package/public/assets/{Chip-BOyBT5TP.js → Chip-DG-mqRx0.js} +1 -1
  6. package/public/assets/{CopyValue-DRHHQlN_.js → CopyValue-CItB094V.js} +1 -1
  7. package/public/assets/Lamp-Cxp-OxUq.js +25 -0
  8. package/public/assets/{Rack-D798XvPQ.js → Rack-xBT_6EtM.js} +5 -5
  9. package/public/assets/{RequestTable-CEBhwDs7.js → RequestTable-CM9mPiMF.js} +1 -1
  10. package/public/assets/{SummaryDeck-DBCSHihY.js → SummaryDeck-C3ZwZ3ng.js} +1 -1
  11. package/public/assets/{Toggle-CdCCoDEo.js → Toggle-CmXXn6F3.js} +1 -1
  12. package/public/assets/{TokenBreakdown-DDI9uTPW.js → TokenBreakdown-COJ643vg.js} +1 -1
  13. package/public/assets/{WindowChart-C-Y6U3WF.js → WindowChart-BrLf4KCu.js} +1 -1
  14. package/public/assets/_app.accounts-B-OYO2Yi.js +59 -0
  15. package/public/assets/_app.console-BOZ1wncA.js +44 -0
  16. package/public/assets/{_app.database-D0W0pcxC.js → _app.database-B5oHZPbu.js} +4 -4
  17. package/public/assets/{_app.index-CyxnfhVX.js → _app.index-CB3UFRwF.js} +5 -5
  18. package/public/assets/{_app.keys-D9qmw9Tj.js → _app.keys-B89CMo3x.js} +2 -2
  19. package/public/assets/{_app.logs-DtXUZETW.js → _app.logs-CNAnRW07.js} +1 -1
  20. package/public/assets/{_app.models-CNxwXyFl.js → _app.models-DpRcGhag.js} +4 -4
  21. package/public/assets/_app.plugins._pluginId-LzBq-Zjj.js +2 -0
  22. package/public/assets/{_app.plugins._pluginId-87Ox_hkW.js → _app.plugins._pluginId-sYDTZ9Px.js} +1 -1
  23. package/public/assets/{_app.settings-DjiMSl1Y.js → _app.settings-BV085FpM.js} +4 -4
  24. package/public/assets/{_app.usage-CZz9raYR.js → _app.usage-CGuOdYun.js} +3 -3
  25. package/public/assets/{chevron-right-CPoaXYHw.js → chevron-right-BeVtzzum.js} +1 -1
  26. package/public/assets/{client-CZnyYbay.js → client-Mf5f5R9Z.js} +1 -1
  27. package/public/assets/index-3lpol4cr.js +13 -0
  28. package/public/assets/{login-BtlMmyKj.js → login-BpvnkW6i.js} +2 -2
  29. package/public/assets/{login-dV42ZQIA.js → login-CwYbEKWH.js} +2 -2
  30. package/public/assets/plus-nHMFjQ2I.js +1 -0
  31. package/public/assets/{preload-helper-4wSmu2-E.js → preload-helper-8jyVfd2a.js} +1 -1
  32. package/public/assets/{shared-OJcoRCqT.js → shared-B2Lmnazz.js} +1 -1
  33. package/public/assets/{stream-CEb81tzM.js → stream-VJMOV03S.js} +1 -1
  34. package/public/assets/{trash-2-BjpqTubo.js → trash-2-CbjLfrko.js} +1 -1
  35. package/public/index.html +7 -7
  36. package/public/shared/dashboard-sdk.js +1 -1
  37. package/public/assets/Lamp-ZlMzNs5N.js +0 -25
  38. package/public/assets/_app.accounts-CLLLwN77.js +0 -59
  39. package/public/assets/_app.console-Dr9qxU7J.js +0 -44
  40. package/public/assets/_app.plugins._pluginId-CZWipH1n.js +0 -2
  41. package/public/assets/index-DNSPtYpM.js +0 -13
  42. package/public/assets/plus-_zo43Lvf.js +0 -1
package/README.md CHANGED
@@ -487,6 +487,9 @@ Configuration is environment variables, read from the installation's `.env`:
487
487
  | `OMNI_BODY_LOGGING_ALLOWED` | No | unset | Permits request/response body capture on this installation. Read at boot. Capture also needs the runtime setting; see [Recording bodies](#recording-bodies) |
488
488
  | `OMNI_ROOT` | No | the installation in the current directory, else `~/.config/omnigateway` | Which installation the CLI acts on, when `--root` is not passed |
489
489
  | `OMNI_PLUGIN_REGISTRY` | No | the public npm registry | Registry `omni plugin install <name>` resolves through; must be `https://` |
490
+ | `OMNI_CLUSTER_MODE` | No | unset | `true` selects [cluster mode](#running-more-than-one-gateway) and requires the two URLs below; unset is one process on SQLite, and then the URLs must be unset too |
491
+ | `OMNI_DATABASE_URL` | In cluster mode | — | The shared Postgres store |
492
+ | `OMNI_REDIS_URL` | In cluster mode | — | The coordinator every process of a cluster shares: rate-limit counters, sessions, leases, push fan-out |
490
493
 
491
494
  `OMNI_ROOT` is the one variable read from your shell and never from a root's `.env`, for the
492
495
  reason it has to be: a variable that selects the installation cannot live inside the installation
@@ -525,6 +528,70 @@ boot, so a change to it takes a restart. Snapshot retention —
525
528
  deliberately edited on the Database screen instead; see
526
529
  [Snapshots and restore](#snapshots-and-restore) for why.
527
530
 
531
+ ## Running more than one gateway
532
+
533
+ One process on SQLite is the default and is what every command in this document assumes. A
534
+ fleet — several replicas behind a load balancer, on Kubernetes or otherwise — is **cluster
535
+ mode**, switched on by `OMNI_CLUSTER_MODE=true` and needing two things beside the gateway:
536
+
537
+ - **Postgres** as the store, named by `OMNI_DATABASE_URL`. Every replica reads and writes one
538
+ database; there is no SQLite file, no snapshot, no restore, and no `omni db vacuum` — those are
539
+ `pg_dump`'s job now, and the Database screen says so.
540
+ - **Redis** (or Valkey) as the coordinator, named by `OMNI_REDIS_URL`. It holds what a fleet must
541
+ agree on and a database is the wrong shape for: the per-minute request ring and the concurrency
542
+ gauge, the long-window counters, admin sessions, pending OAuth flows, quota-probe cooldowns, the
543
+ leases that make the background loops run once rather than N times, and the fan-out that lets a
544
+ console on one replica hear a change made on another.
545
+
546
+ ```bash
547
+ OMNI_CLUSTER_MODE=true
548
+ OMNI_DATABASE_URL=postgres://omni:secret@db.internal:5432/omni
549
+ OMNI_REDIS_URL=redis://cache.internal:6379
550
+ OMNI_ENCRYPTION_KEY=… # the same on every replica
551
+ ```
552
+
553
+ Boot refuses the switch without both URLs, and refuses either URL without the switch: a
554
+ replica that believes it is clustered and is not is the failure this variable exists to make
555
+ loud.
556
+
557
+ What holds across the fleet, exactly: every API-key limit at every window and dimension; token
558
+ refresh, which one replica performs while the others wait and reuse the result; a cookie issued
559
+ by one replica, which every other verifies and a password change ends everywhere. What is
560
+ per-replica and says so: the console's **Console** screen shows one process's stdout, so it grows
561
+ a selector when there is more than one, and its default view is every process merged by time.
562
+ What is per-replica and does not say so: the routing `load` weight is one round trip stale
563
+ between replicas, so a burst arriving at once on two of them can stack for that long.
564
+
565
+ **No sticky sessions are needed.** The WebSocket the console holds may land on any replica; the
566
+ ingress only needs to pass upgrades and hold an idle timeout above ten seconds. A rolling deploy
567
+ closes each replica's sockets with `1001`, the console reconnects to a live one and refetches
568
+ once.
569
+
570
+ **When Redis is unreachable**, the request path keeps serving: each replica falls back to its
571
+ own in-memory counters, so limits degrade to N-fold until Redis returns, and one line per thirty
572
+ seconds says so (`coord=redis coordFallback=true`). The console does not: a session that cannot
573
+ be checked against the shared store is refused with `503`, because a session verified locally is
574
+ one a password change on another replica cannot end. `GET /health` reports `mode`, `nodeId` and
575
+ `coord` (`ok` or `fallback`) for a readiness probe to read.
576
+
577
+ Plugins are loaded from each replica's own `<root>/plugins/`; bake them into the image so every
578
+ replica holds the same set. Plugin storage is Postgres in cluster mode, so a plugin's SQL is
579
+ written for it. `POST /api/restart` refuses in cluster mode — roll the deployment instead.
580
+
581
+ Moving an existing SQLite installation onto Postgres:
582
+
583
+ ```bash
584
+ omni stop
585
+ omni db migrate --to postgres://omni:secret@db.internal:5432/omni
586
+ ```
587
+
588
+ It copies credentials (re-encrypted with the same `OMNI_ENCRYPTION_KEY`), API keys, virtual
589
+ models, settings, both passwords and every completed request log into an **empty** Postgres
590
+ database, rebuilds the rollups, and prints what it did not carry: request bodies, `usage_daily`
591
+ older than the retained logs, quota readings and breaker state (re-measured within a poll
592
+ interval), sessions, and `plugin_*` tables, whose SQL is the source dialect's. It refuses while a
593
+ gateway is running and refuses a target that holds anything.
594
+
528
595
  ## Recording bodies
529
596
 
530
597
  By default the gateway records no prompts and no responses. For incident
@@ -648,10 +715,29 @@ docker run --rm \
648
715
  omnigateway
649
716
  ```
650
717
 
651
- The container listens on `0.0.0.0:9000` and keeps its database at
652
- `/data/omnigateway.db`. Note that **the image builds the gateway only**: it
653
- serves the APIs and returns 404 for the console. Use the CLI or the control API
654
- against it, or install the npm package if you want the console.
718
+ The container listens on `0.0.0.0:9000`, serves the console, and keeps its
719
+ database and plugins under `/data`. It runs as the unprivileged `bun` user and
720
+ carries a `HEALTHCHECK` on `/health`.
721
+
722
+ For a fleet, set `OMNI_CLUSTER_MODE=true` with `OMNI_DATABASE_URL` and `OMNI_REDIS_URL` and
723
+ drop the volume;
724
+ see [Running more than one gateway](#running-more-than-one-gateway). A
725
+ Kubernetes deployment — Deployment, Service, Ingress with the timeouts streaming
726
+ needs, HPA, and an example Secret — is under `k8s/` as a kustomize
727
+ base:
728
+
729
+ ```bash
730
+ cp k8s/secret.example.yaml k8s/secret.yaml # edit it
731
+ kubectl apply -f k8s/secret.yaml
732
+ kubectl apply -k k8s
733
+ ```
734
+
735
+ Releases deploy by GitOps: a `v*` tag publishes `ghcr.io/harismawan/omnigateway:<version>`
736
+ and the workflow commits that version into `k8s/kustomization.yaml` on `main`, which Argo
737
+ CD syncs. Rolling back is editing `newTag` by hand.
738
+
739
+ Plugins in a fleet are baked into the image so every replica holds the same
740
+ set: `COPY plugins/ /data/plugins/` in a derived Dockerfile.
655
741
 
656
742
  Give the container a restart policy — `--restart unless-stopped` — if you want a
657
743
  restart request to bring it back. A container cannot read its own policy, so