omnigateway 0.7.3 → 0.8.1
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 +107 -7
- package/bin/omni.js +7938 -5697
- package/gateway.js +17363 -14714
- package/package.json +1 -1
- package/public/assets/{Chip-BOyBT5TP.js → Chip-BZWa7onX.js} +1 -1
- package/public/assets/{CopyValue-DRHHQlN_.js → CopyValue-Cs2JUZQD.js} +1 -1
- package/public/assets/Lamp-BHYJpauE.js +25 -0
- package/public/assets/{Rack-D798XvPQ.js → Rack-CRuJZY00.js} +5 -5
- package/public/assets/{RequestTable-CEBhwDs7.js → RequestTable-D9hFf4o5.js} +1 -1
- package/public/assets/{SummaryDeck-DBCSHihY.js → SummaryDeck-D29h0rFx.js} +1 -1
- package/public/assets/{Toggle-CdCCoDEo.js → Toggle-BIHUR4pS.js} +1 -1
- package/public/assets/{TokenBreakdown-DDI9uTPW.js → TokenBreakdown-D5mQFSfo.js} +1 -1
- package/public/assets/{WindowChart-C-Y6U3WF.js → WindowChart-DVl7kwqb.js} +1 -1
- package/public/assets/_app.accounts-C3Yv991L.js +59 -0
- package/public/assets/_app.console-Bvo2fugd.js +44 -0
- package/public/assets/_app.database-CfWNOIl-.js +24 -0
- package/public/assets/{_app.index-CyxnfhVX.js → _app.index-CgI1OrZR.js} +5 -5
- package/public/assets/{_app.keys-D9qmw9Tj.js → _app.keys-CcfPhvCD.js} +2 -2
- package/public/assets/{_app.logs-DtXUZETW.js → _app.logs-C8ZiArCn.js} +1 -1
- package/public/assets/{_app.models-CNxwXyFl.js → _app.models-nfMWzVb4.js} +4 -4
- package/public/assets/_app.plugins._pluginId-ByykviWs.js +2 -0
- package/public/assets/{_app.plugins._pluginId-87Ox_hkW.js → _app.plugins._pluginId-CE8Jknhs.js} +1 -1
- package/public/assets/{_app.settings-DjiMSl1Y.js → _app.settings-C45FJLeX.js} +4 -4
- package/public/assets/{_app.usage-CZz9raYR.js → _app.usage-C5s-DfBV.js} +3 -3
- package/public/assets/{chevron-right-CPoaXYHw.js → chevron-right-B7JOx5ra.js} +1 -1
- package/public/assets/{client-CZnyYbay.js → client-DvN2dbYV.js} +1 -1
- package/public/assets/index-BW1O9p6N.js +13 -0
- package/public/assets/{login-dV42ZQIA.js → login-9Ovj_4DV.js} +2 -2
- package/public/assets/{login-BtlMmyKj.js → login-DvRXHEGv.js} +2 -2
- package/public/assets/plus-64jUPIDJ.js +1 -0
- package/public/assets/{preload-helper-4wSmu2-E.js → preload-helper-D2sCuvIY.js} +1 -1
- package/public/assets/{shared-OJcoRCqT.js → shared-BKWNmsjH.js} +1 -1
- package/public/assets/{stream-CEb81tzM.js → stream-BUWwtwme.js} +1 -1
- package/public/assets/{trash-2-BjpqTubo.js → trash-2-rvGFhAn8.js} +1 -1
- package/public/index.html +7 -7
- package/public/shared/dashboard-sdk.js +1 -1
- package/public/assets/Lamp-ZlMzNs5N.js +0 -25
- package/public/assets/_app.accounts-CLLLwN77.js +0 -59
- package/public/assets/_app.console-Dr9qxU7J.js +0 -44
- package/public/assets/_app.database-D0W0pcxC.js +0 -24
- package/public/assets/_app.plugins._pluginId-CZWipH1n.js +0 -2
- package/public/assets/index-DNSPtYpM.js +0 -13
- 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
|
|
@@ -513,6 +516,15 @@ bun apps/gateway/src/index.ts >> /var/log/omni.log 2>&1
|
|
|
513
516
|
`omni start` does both for the gateway it supervises, and under systemd the journal needs no
|
|
514
517
|
setup.
|
|
515
518
|
|
|
519
|
+
In a fleet, capture is per process. Each replica can capture its own — tee its stdout to a file
|
|
520
|
+
inside the container and point `OMNI_LOG_FILE` at the same path — and the Console screen then
|
|
521
|
+
merges every process's tail and lets you pick one. That is worth having for an incident on a
|
|
522
|
+
running pod, and it is not a log stack: the file dies with the container, nothing rotates it, and
|
|
523
|
+
the screen reads one process at a time. Ship stdout to a collector for anything beyond that —
|
|
524
|
+
Elasticsearch and Kibana, Loki and Grafana, or whatever already reads your containers — where the
|
|
525
|
+
lines outlive the process that wrote them and can be searched across all of them at once. The
|
|
526
|
+
Console screen says so itself when it finds a fleet capturing nothing.
|
|
527
|
+
|
|
516
528
|
Everything else lives in the database rather than the environment, so it can be
|
|
517
529
|
changed without a restart: the six routing weights, `maxAttempts`,
|
|
518
530
|
`requestDeadlineMs`, the circuit breaker's `breakerThreshold` and
|
|
@@ -525,6 +537,70 @@ boot, so a change to it takes a restart. Snapshot retention —
|
|
|
525
537
|
deliberately edited on the Database screen instead; see
|
|
526
538
|
[Snapshots and restore](#snapshots-and-restore) for why.
|
|
527
539
|
|
|
540
|
+
## Running more than one gateway
|
|
541
|
+
|
|
542
|
+
One process on SQLite is the default and is what every command in this document assumes. A
|
|
543
|
+
fleet — several replicas behind a load balancer, on Kubernetes or otherwise — is **cluster
|
|
544
|
+
mode**, switched on by `OMNI_CLUSTER_MODE=true` and needing two things beside the gateway:
|
|
545
|
+
|
|
546
|
+
- **Postgres** as the store, named by `OMNI_DATABASE_URL`. Every replica reads and writes one
|
|
547
|
+
database; there is no SQLite file, no snapshot, no restore, and no `omni db vacuum` — those are
|
|
548
|
+
`pg_dump`'s job now, and the Database screen says so.
|
|
549
|
+
- **Redis** (or Valkey) as the coordinator, named by `OMNI_REDIS_URL`. It holds what a fleet must
|
|
550
|
+
agree on and a database is the wrong shape for: the per-minute request ring and the concurrency
|
|
551
|
+
gauge, the long-window counters, admin sessions, pending OAuth flows, quota-probe cooldowns, the
|
|
552
|
+
leases that make the background loops run once rather than N times, and the fan-out that lets a
|
|
553
|
+
console on one replica hear a change made on another.
|
|
554
|
+
|
|
555
|
+
```bash
|
|
556
|
+
OMNI_CLUSTER_MODE=true
|
|
557
|
+
OMNI_DATABASE_URL=postgres://omni:secret@db.internal:5432/omni
|
|
558
|
+
OMNI_REDIS_URL=redis://cache.internal:6379
|
|
559
|
+
OMNI_ENCRYPTION_KEY=… # the same on every replica
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
Boot refuses the switch without both URLs, and refuses either URL without the switch: a
|
|
563
|
+
replica that believes it is clustered and is not is the failure this variable exists to make
|
|
564
|
+
loud.
|
|
565
|
+
|
|
566
|
+
What holds across the fleet, exactly: every API-key limit at every window and dimension; token
|
|
567
|
+
refresh, which one replica performs while the others wait and reuse the result; a cookie issued
|
|
568
|
+
by one replica, which every other verifies and a password change ends everywhere. What is
|
|
569
|
+
per-replica and says so: the console's **Console** screen shows one process's stdout, so it grows
|
|
570
|
+
a selector when there is more than one, and its default view is every process merged by time.
|
|
571
|
+
What is per-replica and does not say so: the routing `load` weight is one round trip stale
|
|
572
|
+
between replicas, so a burst arriving at once on two of them can stack for that long.
|
|
573
|
+
|
|
574
|
+
**No sticky sessions are needed.** The WebSocket the console holds may land on any replica; the
|
|
575
|
+
ingress only needs to pass upgrades and hold an idle timeout above ten seconds. A rolling deploy
|
|
576
|
+
closes each replica's sockets with `1001`, the console reconnects to a live one and refetches
|
|
577
|
+
once.
|
|
578
|
+
|
|
579
|
+
**When Redis is unreachable**, the request path keeps serving: each replica falls back to its
|
|
580
|
+
own in-memory counters, so limits degrade to N-fold until Redis returns, and one line per thirty
|
|
581
|
+
seconds says so (`coord=redis coordFallback=true`). The console does not: a session that cannot
|
|
582
|
+
be checked against the shared store is refused with `503`, because a session verified locally is
|
|
583
|
+
one a password change on another replica cannot end. `GET /health` reports `mode`, `nodeId` and
|
|
584
|
+
`coord` (`ok` or `fallback`) for a readiness probe to read.
|
|
585
|
+
|
|
586
|
+
Plugins are loaded from each replica's own `<root>/plugins/`; bake them into the image so every
|
|
587
|
+
replica holds the same set. Plugin storage is Postgres in cluster mode, so a plugin's SQL is
|
|
588
|
+
written for it. `POST /api/restart` refuses in cluster mode — roll the deployment instead.
|
|
589
|
+
|
|
590
|
+
Moving an existing SQLite installation onto Postgres:
|
|
591
|
+
|
|
592
|
+
```bash
|
|
593
|
+
omni stop
|
|
594
|
+
omni db migrate --to postgres://omni:secret@db.internal:5432/omni
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
It copies credentials (re-encrypted with the same `OMNI_ENCRYPTION_KEY`), API keys, virtual
|
|
598
|
+
models, settings, both passwords and every completed request log into an **empty** Postgres
|
|
599
|
+
database, rebuilds the rollups, and prints what it did not carry: request bodies, `usage_daily`
|
|
600
|
+
older than the retained logs, quota readings and breaker state (re-measured within a poll
|
|
601
|
+
interval), sessions, and `plugin_*` tables, whose SQL is the source dialect's. It refuses while a
|
|
602
|
+
gateway is running and refuses a target that holds anything.
|
|
603
|
+
|
|
528
604
|
## Recording bodies
|
|
529
605
|
|
|
530
606
|
By default the gateway records no prompts and no responses. For incident
|
|
@@ -574,9 +650,12 @@ format, structural bounds, and masking rules.
|
|
|
574
650
|
## Snapshots and restore
|
|
575
651
|
|
|
576
652
|
The console's Database screen reports what this installation occupies — the
|
|
577
|
-
database file, its write-ahead log, the captured-body tree,
|
|
578
|
-
compaction would give back
|
|
579
|
-
figures.
|
|
653
|
+
database file, its write-ahead log, the captured-body tree, the free pages a
|
|
654
|
+
compaction would give back, and every table by size — and takes snapshots.
|
|
655
|
+
`omni db stats` prints the same figures. On Postgres both show the server's own
|
|
656
|
+
size, the `request_bodies` table and the per-table listing instead; there is no
|
|
657
|
+
file, so nothing here compacts, snapshots or restores it — `pg_dump` is the
|
|
658
|
+
backup.
|
|
580
659
|
|
|
581
660
|
**What a snapshot is.** One self-contained SQLite file, written into a
|
|
582
661
|
`snapshots/` directory beside the database. The write-ahead log is folded in, so
|
|
@@ -648,10 +727,31 @@ docker run --rm \
|
|
|
648
727
|
omnigateway
|
|
649
728
|
```
|
|
650
729
|
|
|
651
|
-
The container listens on `0.0.0.0:9000
|
|
652
|
-
`/data
|
|
653
|
-
|
|
654
|
-
|
|
730
|
+
The container listens on `0.0.0.0:9000`, serves the console, and keeps its
|
|
731
|
+
database and plugins under `/data`. It runs as the unprivileged `bun` user and
|
|
732
|
+
carries a `HEALTHCHECK` on `/health`.
|
|
733
|
+
|
|
734
|
+
For a fleet, set `OMNI_CLUSTER_MODE=true` with `OMNI_DATABASE_URL` and `OMNI_REDIS_URL` and
|
|
735
|
+
drop the volume;
|
|
736
|
+
see [Running more than one gateway](#running-more-than-one-gateway). A
|
|
737
|
+
Kubernetes deployment — Deployment, Service, Ingress with the timeouts streaming
|
|
738
|
+
needs, HPA, and an example Secret — is under `k8s/` as a kustomize
|
|
739
|
+
base:
|
|
740
|
+
|
|
741
|
+
```bash
|
|
742
|
+
cp k8s/secret.example.yaml k8s/secret.yaml # edit it
|
|
743
|
+
kubectl apply -f k8s/secret.yaml
|
|
744
|
+
kubectl apply -k k8s
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
Releases deploy by GitOps: a `v*` tag publishes `ghcr.io/harismawan/omnigateway:<version>`
|
|
748
|
+
and the workflow commits that version into `k8s/kustomization.yaml` on `main`, which Argo
|
|
749
|
+
CD syncs. Rolling back is editing `newTag` by hand.
|
|
750
|
+
|
|
751
|
+
Plugins in a fleet are baked into the image so every replica holds the same
|
|
752
|
+
set: `COPY plugins/ /data/plugins/` in a derived Dockerfile. The image is
|
|
753
|
+
public, so no pull secret is configured; a private fork adds
|
|
754
|
+
`imagePullSecrets` to the Deployment.
|
|
655
755
|
|
|
656
756
|
Give the container a restart policy — `--restart unless-stopped` — if you want a
|
|
657
757
|
restart request to bring it back. A container cannot read its own policy, so
|