anbaric 1.19.0 → 1.20.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.
Files changed (2) hide show
  1. package/README.md +337 -154
  2. package/package.json +9 -5
package/README.md CHANGED
@@ -1,208 +1,370 @@
1
- # anbaric
1
+ # Anbaric
2
2
 
3
- Anbaric is a TypeScript framework for building stateful applications. An
4
- application is expressed as one or more state machines: long-lived jobs move
5
- through named states, driven by actions and transitions, with their data
6
- validated against a schema and every change recorded in an audit trail.
7
- Alongside the state machine the framework provides schema-validated document
8
- storage and secret storage.
3
+ Anbaric is a TypeScript framework for building stateful enterprise applications. Anbaric is designed to help vibe-coded applications go the last mile, by providing persistence, state management, authentication and auditing.
9
4
 
10
- Anbaric also provides a platform for deploying the applications built on it. The
11
- same application runs unchanged on a developer's machine, on a server you
12
- operate, or on Anbaric Cloud, where a single CLI command deploys it. Application
13
- code depends only on the interfaces in this package; the framework selects
14
- in-memory or platform-backed implementations from the environment, so no
15
- deployment detail appears in the code.
5
+ We believe that fully bespoke software is the future, and this project was created to help a wider range of people build their own solutions, without compromising enterprise IT standards.
16
6
 
17
- This package (`anbaric`) is the umbrella install for writing an application. It
18
- re-exports the app-facing surface of the underlying packages.
7
+ ## Getting started
8
+
9
+ Install the Anbaric package and the CLI:
19
10
 
20
11
  ```bash
12
+ npm init
21
13
  npm install anbaric
14
+ npm install -g anbaric-cli
22
15
  ```
23
16
 
24
- An Anbaric application is a standard Node.js ESM program written in TypeScript:
25
- set `"type": "module"` in `package.json`, point `main` at the TypeScript entry
26
- file, and run it with `tsx`.
27
-
28
- ## State machines
29
-
30
- A **`StateMachine`** defines a workflow. It is constructed with an identifier, a
31
- list of states, the name of the start state, and the property schema for its
32
- jobs.
33
-
34
- - A **`State`** is a named step. It holds a list of **actions** to run while a
35
- job sits in that state, and a list of **transitions** to the next state.
36
- - An **`Action`** is a unit of work. Its `run` function receives the job and
37
- returns a `Map` of property changes: `run(job) => Promise<Map<string, any>>`.
38
- An action does not mutate the job directly; the returned properties are
39
- validated and applied by the machine. Each action declares the **actor** that
40
- performs it.
41
- - A **`Transition`** names a target state and carries a predicate over the job.
42
- When a job is processed, the first transition whose predicate holds moves the
43
- job to that state.
44
- - A **`Job`** is one instance moving through the machine. It carries an
45
- identifier, its current `state`, a `Map` of `properties`, and provenance
46
- (`workflowId`, `startedBy`, `startedAt`, `lastUpdated`). Jobs are immutable;
47
- each change produces a new version.
48
- - A **`PropertyDefinition`** describes one property a job may carry: whether it
49
- is required and how its value is validated. Every property a job holds —
50
- including properties set by actions — must have a definition, or the change is
51
- rejected.
52
- - An **`Actor`** identifies who performs an operation, for authorization and
53
- auditing. The actor types are `Code`, `Human`, `Agent` and `System`. `Code`
54
- actions run automatically as jobs are processed; a `Human` or `Agent` actor
55
- represents work performed by a person or an autonomous agent.
56
-
57
- A job progresses automatically as it is processed: matching actions run, their
58
- properties are applied, and the first satisfied transition advances the state.
59
- This repeats until the job reaches a state from which nothing more applies.
17
+ Prompt your agent:
60
18
 
61
- There are three ways to influence a job:
19
+ ```
20
+ Use Anbaric to build me a CRM.
21
+ ```
22
+
23
+ Run locally as usual (`npm run start`) or deploy to the Anbaric Cloud (`anbaric app deploy`).
62
24
 
63
- - `startJob(properties?, actor?)` creates a job in the start state.
64
- - `updateJob(jobId, properties, actor)` applies an explicit property change.
65
- - `executeAction(jobId, action)` runs a single action immediately.
66
- - Actions subscribed to a state run automatically whenever a job in that state
67
- is processed.
25
+ Anbaric is open source and you can self-host the platform or sign up at https://cloud.anbaric.ai to use the hosted version.
68
26
 
69
- Every operation is validated against the schema and written to the audit trail,
70
- which records the resource, the actor, the interactions (create, update, state
71
- change, delete, read), and a description of what changed.
27
+ ## What the code looks like
72
28
 
73
- ## Documents and secrets
29
+ Anbaric has a collection of features that can be used in your application. Here are some examples:
74
30
 
75
- For data that does not belong to a job, the framework provides two stores,
76
- obtained from factories and used with an actor for auditing.
31
+ ### Persist JSON
77
32
 
78
- - **`JsonStore`** stores JSON documents in named collections, optionally
79
- validated against a JSON Schema.
80
- - **`SecretStore`** stores named secret strings, encrypted at rest, and never
81
- records secret values in the audit trail.
33
+ In this example we will store a customer's details in a JSON document. Every change that is made in Anbaric requires an `Actor` to be specified, which is used to ensure a complete audit trail exists for any application built using Anbaric. In general, an actor will be either a "human" actor, an AI agent or code being executed by the system.
34
+
35
+ When your app serves a page to a signed-in user, `Human.fromSession` turns that request into the human actor behind it — it resolves the browser's platform session (the `anbaric_session` cookie) against the platform, so the audit trail names the real user. Pass it the incoming request (or the session token directly). Outside a request — a seed script or system code — construct the actor yourself, e.g. `new Human("ada", ["admin"])` or a `Code` actor.
82
36
 
83
37
  ```ts
84
- import {Human, JsonStoreFactory, SecretStoreFactory} from "anbaric";
38
+ import {Human, JsonStoreFactory} from "anbaric";
85
39
 
86
- const actor = new Human("ada", "admin");
40
+ // inside your app's HTTP handler, `request` is the incoming browser request
41
+ const actor = await Human.fromSession(request);
42
+ const customers = JsonStoreFactory.instance("customers");
43
+
44
+ await customers.create(actor, "ada", { name: "Ada Lovelace", email: "ada@example.com" });
45
+ const ada = await customers.retrieve("ada", actor);
46
+ ```
47
+
48
+ ### Run a state machine
49
+
50
+ A state machine models work as jobs moving through named states. Actions run while a job sits in a state, and transitions decide where it goes next. A state machine can combine steps using different types of actors, so humans can own some action, AI agents and code can automate others.
51
+
52
+ ```ts
53
+ import {Action, Code, PropertyDefinition, State, StateMachine, Transition} from "anbaric";
54
+
55
+ const sendWelcome = new Action("Send welcome email", new Code("welcome"));
56
+ sendWelcome.run = async (job) => {
57
+ // Access properties stored against the job
58
+ const email = job.properties.get("email");
59
+ // Run some code
60
+ console.log(`Sending welcome email to ${email}`);
61
+ // Return new properties to add to the job
62
+ const newProperties = new Map();
63
+ newProperties.set("emailSent", true);
64
+ return newProperties;
65
+ };
66
+
67
+ const onboarding = new StateMachine("onboarding", [
68
+ new State("new", [sendWelcome], [new Transition("active", (job) => job.properties.get("emailSent") === true)]),
69
+ new State("active"),
70
+ ]);
71
+
72
+ const customer = await onboarding.startJob(new Map([["email", "ada@example.com"]]));
73
+ ```
87
74
 
88
- const customers = JsonStoreFactory.instance("customers", {
89
- type: "object",
90
- required: ["name"],
91
- properties: { name: { type: "string" } },
75
+ The job starts in `new`; when it is processed the action runs, sets `emailSent`, and the transition advances it to `active`.
76
+
77
+ ### Using AI agents to automate states
78
+
79
+ An **agent** is an actor whose properties are produced by a model rather than by
80
+ hand-written code. A `RemoteLLMAgenticAction` gives the agent a prompt and a JSON
81
+ Schema, and applies the properties it returns to the job. Here an OpenAI-backed
82
+ agent triages a support ticket:
83
+
84
+ ```ts
85
+ import {OpenAIAgent, RemoteLLMAgenticAction, State, StateMachine, Transition} from "anbaric";
86
+
87
+ const triager = new OpenAIAgent("triager", "support", {
88
+ apiKey: process.env.OPENAI_API_KEY!,
89
+ model: "gpt-5.4-mini",
92
90
  });
93
- await customers.create(actor, "ada", { name: "Ada" });
94
- const record = await customers.retrieve("ada", actor);
95
91
 
96
- const secrets = SecretStoreFactory.instance();
97
- await secrets.create(actor, "api-key", "s3cr3t");
92
+ const triage = new RemoteLLMAgenticAction(
93
+ "Triage the ticket",
94
+ triager,
95
+ [{ role: "system", content: "Decide the priority of the support ticket from its subject." }],
96
+ { type: "object", properties: { priority: { type: "string", enum: ["low", "high"] } } },
97
+ );
98
+
99
+ const support = new StateMachine("support", [
100
+ new State("open", [triage], [new Transition("prioritised", (job) => job.properties.has("priority"))]),
101
+ new State("prioritised"),
102
+ ]);
98
103
  ```
99
104
 
100
- ## Running and deploying
101
-
102
- Persistence, queueing and consumers are supplied by environment-driven
103
- factories, so the same application runs in several ways without code changes.
104
-
105
- - **Local.** With no environment configured, every store, queue and consumer is
106
- in-memory and jobs progress automatically. Running the program with
107
- `npx tsx src/main.ts` is a complete local run, suitable for development and
108
- testing.
109
- - **Anbaric Cloud.** `anbaric app deploy` packages the application (source only, no
110
- `node_modules`) and runs it on the hosted platform. The platform installs the
111
- application's own dependencies as it builds the image, so any npm package the
112
- application imports works when deployed. The platform injects the configuration
113
- that points the factories at platform-backed persistence, queueing, documents
114
- and secrets; application code is unchanged. Authentication, job inspection and
115
- updates are available through the CLI.
116
- - **Self-hosted.** The [`anbaric-hosting`](https://npmjs.com/package/anbaric-hosting)
117
- package runs the platform — the API, dispatcher, build layer and app proxy —
118
- on infrastructure you operate, backed by Postgres.
105
+ Because the agent is just another actor, its work is audited like any other —
106
+ the triage decision is attributed to `triager`.
119
107
 
120
- Applications should not set the `ANBARIC_*` factory variables themselves; the
121
- platform sets them when the application is deployed.
108
+ ### Wait for human input
122
109
 
123
- ## Example
110
+ Sometimes a job cannot progress by itself — it needs a person to approve
111
+ something, fill in a form, or make a decision. An **`Await`** is a step in a
112
+ state's action list that *pauses* the job instead of running: when a job reaches
113
+ it, the job is parked in the **`Awaiting input`** status and is not processed
114
+ again until its properties are updated. Point people at wherever they provide
115
+ that input with a **`resolveUrl`** — a function of the job, so you can build a
116
+ per-job link with the job id (and anything else) in the query string.
117
+
118
+ Here an order waits for a human to approve it. The app serves a small approval
119
+ UI at `/approve` (any framework — the page itself is omitted here); it reads the
120
+ job id from the query string, collects the decision, and calls
121
+ `updateJob(jobId, { approved: true }, actor)`. The `Await` sends the reviewer
122
+ there, and a transition moves the job on once `approved` is set:
124
123
 
125
124
  ```ts
126
- import {Action, Code, PropertyDefinition, State, StateMachine, Transition} from "anbaric";
125
+ import {Await, State, StateMachine, Transition} from "anbaric";
127
126
 
128
- const name = new PropertyDefinition("name");
129
- name.required = true;
127
+ const approve = new Await("Approve the order", "HUMAN");
128
+ approve.fields = ["approved"]; // the input we expect back
129
+ approve.resolveUrl = (job) => `/approve?job=${job.id}`; // where the human provides it
130
130
 
131
- const email = new PropertyDefinition("email");
132
- email.required = true;
131
+ const fulfilment = new StateMachine("fulfilment", [
132
+ new State("review", [approve], [new Transition("approved", (job) => job.properties.get("approved") === true)]),
133
+ new State("approved"),
134
+ ]);
133
135
 
134
- const welcomeSent = new PropertyDefinition("welcomeSent");
135
- welcomeSent.validation = (value) => typeof value === "boolean";
136
+ const order = await fulfilment.startJob(new Map([["total", 4200]]));
137
+ // The job reaches `approve`, parks in "Awaiting input", and waits.
138
+ // When the approval UI calls updateJob(order.id, { approved: true }, actor),
139
+ // the job resumes, the transition fires, and it advances to `approved`.
140
+ ```
136
141
 
137
- const sendWelcome = new Action("Send welcome email", new Code("send-welcome"));
138
- sendWelcome.run = async (job) => {
139
- // ... send the email to job.properties.get("email") ...
140
- return new Map([["welcomeSent", true]]);
141
- };
142
+ The pause is recorded in the audit trail, and the [awaiting-input
143
+ widget](#the-admin-console-and-widgets) lists every parked job with a
144
+ clickable `resolveUrl` for those awaiting a human. Pass `"EXTERNAL_SYSTEM"`
145
+ instead of `"HUMAN"` when the input will come from another service rather than a
146
+ person.
142
147
 
143
- const onboarding = new StateMachine(
144
- "customer-onboarding",
145
- [
146
- new State("new", [sendWelcome], [
147
- new Transition("active", (job) => job.properties.get("welcomeSent") === true),
148
- ]),
149
- new State("active"),
150
- ],
151
- "new",
152
- [name, email, welcomeSent],
153
- );
148
+ ### Use an RDBMS
149
+
150
+ A full relational store is available for structured data. Locally it is SQLite; deployed, it is the tenant's PostgreSQL.
151
+
152
+ ```ts
153
+ import {Human, SqlStoreFactory} from "anbaric";
154
+
155
+ const actor = new Human("ada", "admin");
156
+ const sql = SqlStoreFactory.instance();
157
+
158
+ await sql.execute(actor, "CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, body TEXT)");
159
+ await sql.execute(actor, "INSERT INTO notes (body) VALUES (?)", ["hello"]);
160
+ const rows = await sql.query(actor, "SELECT id, body FROM notes");
161
+ ```
162
+
163
+ ### Serve a web UI
164
+
165
+ An app can serve its own HTTP frontend. Listen on `process.env.PORT` and the
166
+ platform's app proxy routes `<platform>/<app-name>/*` to it — combine it with
167
+ the persistence and state-machine APIs above to put your data on a page.
168
+
169
+ ```ts
170
+ import {createServer} from "node:http";
171
+
172
+ createServer((request, response) => {
173
+ response.writeHead(200, { "content-type": "text/html" });
174
+ response.end("<h1>My Anbaric app</h1>");
175
+ }).listen(Number(process.env.PORT ?? 3000));
176
+ ```
177
+
178
+ Serve trivial pages directly like this; build richer UIs with React and the
179
+ Anbaric design system (`anbaric-design-system`). `sample-apps/crm` is a complete
180
+ worked example — an HTTP server that renders its customers as HTML and exposes a
181
+ JSON API backed by a state machine.
182
+
183
+ ## Auditing
184
+
185
+ Every write to a job, document, secret or the SQL store is recorded against the
186
+ actor that made it — which is why the store methods take an actor. An audit
187
+ record captures the actor, the resource, the interaction (create, update, state
188
+ change, delete, kill…) and a short description. Locally the records print to the
189
+ console; deployed, the platform persists them and they are browsable in the
190
+ admin console. Reads and lists can be audited too, but the platform masks them
191
+ by default to keep the volume down.
192
+
193
+ ## Using the CLI
194
+
195
+ `anbaric-cli` authorizes your terminal against a platform, deploys apps, and
196
+ inspects and drives their jobs. After a one-time `anbaric login` (a browser
197
+ flow), a typical loop is:
198
+
199
+ ```bash
200
+ anbaric app deploy # deploy the current project and wait until it is live
201
+ anbaric jobs list # list jobs and their states
202
+ anbaric jobs watch <job-id> # follow a job as it progresses
203
+ anbaric jobs stats # counts per state and the queue depth
204
+ ```
205
+
206
+ Every interactive prompt also has a flag, so the CLI runs unattended in scripts
207
+ and CI. The full command list is in the [CLI reference](#cli-reference) below.
208
+
209
+ ## The Admin console and widgets
210
+
211
+ The platform serves an admin console at its root — a dashboard assembled from
212
+ **plugins**. The built-in `anbaric-plugins/state-machines` plugin lists your
213
+ state machines and their jobs. You add your own pages and widgets by writing a
214
+ small plugin — a `pages`/`widgets` object — and naming it in `ANBARIC_PLUGINS`.
215
+ Widgets are React components, optionally backed by a server-side data function,
216
+ rendered with the platform's design system. See
217
+ [`anbaric-plugins`](anbaric-plugins/README.md).
218
+
219
+ ## State machine deep-dive
220
+
221
+ A **`StateMachine`** is constructed from a workflow id, its `State`s, the start
222
+ state, and the property schema for its jobs. A **`State`** holds the **actions**
223
+ that run while a job sits in it and the **transitions** to other states. An
224
+ **`Action`** has a `run` function returning the property changes to apply — it
225
+ never mutates the job directly. A **`Transition`** names a target state and a
226
+ predicate; the first transition whose predicate holds moves the job. A **`Job`**
227
+ is one instance moving through the machine, carrying its `properties`, its
228
+ current `state`, and its history. A state can be marked terminal (or use the
229
+ `Terminal` helper, which carries a `SUCCESS`/`FAILURE` outcome); a job that
230
+ reaches one stops and is not processed again.
231
+
232
+ Every action also declares the **actor** it runs as (`Code`, `Human` or
233
+ `Agent` — pure identity objects), recorded for auditing and authorization.
234
+ There are three ways to influence a job:
235
+
236
+ 1. **Update it directly**, declaring who is acting:
237
+ `machine.updateJob(jobId, new Map([["approved", true]]), new Human("chris", "manager"))`.
238
+ 2. **Execute an action directly** — the actor is embedded in the action:
239
+ `machine.executeAction(jobId, approveAction)`.
240
+ 3. **Subscribe an action to a state** — pass it in the `State` constructor or
241
+ call `state.subscribe(action)`, and it runs (predicate permitting)
242
+ whenever a job is processed in that state.
243
+
244
+ Whichever way, property changes are schema-validated and audited, and each
245
+ job carries its history: who started it, every from→to transition and the
246
+ actor that made it.
247
+
248
+ A state's action list may also contain an **`Await`** — a pause point rather
249
+ than an actor acting. When a job reaches one it stops running actions and is
250
+ parked: its `status` becomes `Awaiting input` (distinct from its `state`), and
251
+ it holds a **`WaitForInput`** describing what is expected — the `fields`, a
252
+ resolved `resolveUrl`, whether a `HUMAN` or `EXTERNAL_SYSTEM` is expected, and
253
+ any metadata the `Await` computed for the job. A parked job is not re-processed
254
+ until an `updateJob` arrives; on resume it skips its actions and only
255
+ re-evaluates its transitions, so the input drives it on and the wait clears once
256
+ it moves to another state. Actions placed after an `Await` in the same state do
257
+ not run when the job resumes.
258
+
259
+ Everything is pluggable through env-driven factories: locally (no env vars)
260
+ you get in-memory persistence and queueing; deployed, the same factories talk
261
+ to the platform automatically. The same applies to `JsonStoreFactory`
262
+ (schema-validated documents), `SecretStoreFactory` (encrypted secrets) and
263
+ `SqlStoreFactory` (a relational store) from `anbaric-data-store`.
264
+
265
+ The SQL store is backed by SQLite locally (in-memory by default) and, once
266
+ deployed, by the tenant's PostgreSQL in a dedicated `anbaric_app_data` schema
267
+ shared by all of the tenant's apps. Write portable SQL where you can — the two
268
+ differ in a few places, notably parameter placeholders (`?` for SQLite, `$1`
269
+ for PostgreSQL); see the [`anbaric-data-store`](anbaric-data-store/README.md)
270
+ docs for the full list.
271
+
272
+ If your app serves HTTP, listen on `process.env.PORT` and users reach it at
273
+ `<platform>/<app-name>`. All front-end must be React and use the Anbaric
274
+ design system (`anbaric-design-system`) — see the living style guide by
275
+ opening `anbaric-design-system/dist/index.html`.
276
+
277
+ ## Run it locally
278
+
279
+ With no `ANBARIC_*` variables set, the factories return the in-memory
280
+ persistence, queue and stores, so the program runs entirely in-process — no
281
+ database or platform involved. Run the TypeScript entry file directly with tsx;
282
+ `npx` fetches it on demand if your project doesn't already depend on it:
283
+
284
+ ```bash
285
+ npx tsx src/main.ts
286
+ ```
287
+
288
+ Jobs are held in memory and progress as the in-memory consumer delivers them;
289
+ the state is gone when the process exits. This is the mode for development and
290
+ tests.
291
+
292
+ ## Deploy it
154
293
 
155
- const job = await onboarding.startJob(new Map([["name", "Ada"], ["email", "ada@example.com"]]));
294
+ ```bash
295
+ npm install -g anbaric-cli # once; provides the anbaric command
296
+ anbaric login # pick a platform; a browser authorizes this terminal
297
+ anbaric app configure # writes .anbaric/app-config.json (name + internal port)
298
+ anbaric app deploy # packs, uploads, bakes an image, waits until live
156
299
  ```
157
300
 
158
- The job starts in `new`. When it is processed the `sendWelcome` action runs and
159
- sets `welcomeSent`, and the transition then advances the job to `active`. Run
160
- locally this happens automatically in memory; deployed, it happens on the
161
- platform.
301
+ `app deploy` returns once the app is actually up its built-in admin port
302
+ answers the platform's liveness ping. Watch it
303
+ work with `anbaric apps`, `anbaric jobs list [state-machine]`, and
304
+ `anbaric jobs watch <job-id>`. The `app` commands run from anywhere inside the
305
+ project — they walk up to the nearest `package.json`.
306
+
307
+ ### What deployment does (and expects)
308
+
309
+ The platform unpacks your upload onto a pre-canned base image, installs the
310
+ app's dependencies, bakes a Docker image and runs it as a container. One thing
311
+ it does **not** do:
312
+
313
+ - **No build step.** `npm run build` is never run — your TypeScript source is
314
+ executed directly (via tsx). Ship source, not `dist/`.
315
+
316
+ Dependencies, though, *are* installed: the image runs `npm install` for the
317
+ app's declared dependencies (the `anbaric-*` packages and any others), so
318
+ ordinary npm dependencies work. Only source is uploaded — `node_modules` is
319
+ not.
320
+
321
+ An app must have:
322
+
323
+ - `package.json` with `main` pointing at the entry file (e.g. `src/main.ts`)
324
+ and `"type": "module"`.
325
+ - `.anbaric/app-config.json` with a `name` (lowercase letters, numbers, `-`,
326
+ `_`) and an `internalPort` — `anbaric app configure` creates it, and
327
+ `app deploy` prompts if it's missing.
162
328
 
163
- ## Command-line interface
329
+ A built-in admin process answers the platform's liveness check, so an app needs
330
+ no HTTP server of its own to deploy. If it does serve HTTP (reached through the
331
+ app proxy), it listens on `process.env.PORT`. The platform injects all wiring as
332
+ env vars (`ANBARIC_*_TYPE=cloud`, the platform URL, the consumer and admin
333
+ ports) — never hardcode these.
164
334
 
165
- The [`anbaric`](https://npmjs.com/package/anbaric-cli) CLI authenticates a
166
- terminal, deploys applications, and inspects and drives jobs on a platform. The
167
- principal commands are:
335
+ ## CLI reference
168
336
 
169
337
  | Command | Purpose |
170
338
  | --- | --- |
171
- | `anbaric login` / `anbaric logout` | authorize this terminal against a platform, or revoke it |
172
- | `anbaric apps` | list deployed applications |
173
- | `anbaric app configure` | set an application's name and internal port |
174
- | `anbaric app deploy` | deploy an application and wait until it is live |
175
- | `anbaric app update` | deploy over a running application without prompting |
176
- | `anbaric app status <name>` | show an application's deploy state and whether it is up |
177
- | `anbaric app tail <name>` | stream an application's runtime logs |
178
- | `anbaric app tear-down <name>` | stop and remove a deployed application |
339
+ | `anbaric login` | choose a platform and authorize this terminal (browser flow; keypair saved to `~/.anbaric/`) |
340
+ | `anbaric apps` | list deployed apps |
341
+ | `anbaric app configure` | create or update `.anbaric/app-config.json` |
342
+ | `anbaric app deploy` | deploy the app (prompts before replacing a running one) |
343
+ | `anbaric app update` | deploy, replacing without prompting |
344
+ | `anbaric app status <name>` | show an app's deploy state and whether it is up |
345
+ | `anbaric app tail <name>` | stream an app's runtime logs |
346
+ | `anbaric app tear-down <name>` | stop and remove a deployed app |
179
347
  | `anbaric state-machines` | list registered state machines |
180
348
  | `anbaric jobs create <sm-id> <start-state> [k=v ...]` | create a job and queue it for processing |
181
349
  | `anbaric jobs list [state-machine-id]` | list jobs |
182
350
  | `anbaric jobs stats` | job counts per state and the queue size |
183
- | `anbaric jobs watch <job-id>` | follow a job's state as it changes |
184
- | `anbaric jobs set-state <job-id> <state>` | move a job to a state and re-queue it |
185
- | `anbaric jobs update <job-id> <key=value ...>` | change job properties and re-queue |
351
+ | `anbaric jobs watch <job-id>` | follow a job's state live |
352
+ | `anbaric jobs set-state <job-id> <state>` | move a job and re-queue it |
353
+ | `anbaric jobs update <job-id> <key=value ...>` | update job properties and re-queue |
186
354
  | `anbaric jobs kill <job-id>` | kill a job so it stops progressing |
187
355
  | `anbaric jobs kill-old <age>` | kill jobs not updated within `<age>` (e.g. `24h`, `7d`) |
188
356
 
189
- The `app configure`/`deploy`/`update` commands act on the application for the
190
- current project, located by walking up to the nearest `package.json`, so they
191
- run from anywhere inside it.
192
-
193
- Every command accepts flags (such as `--environment`, `--tenant`, `--name`,
194
- `--port`, `--yes`) that supply the answers a prompt would otherwise ask for, so
195
- the CLI can be run non-interactively in scripts and CI. See the
196
- [`anbaric-cli`](https://npmjs.com/package/anbaric-cli) documentation for the
197
- full command and flag reference.
357
+ All commands accept `--platform-url` and `--tenant`; `login` sets the
358
+ defaults. Manage your CLI keys in the browser at `<platform>/manage-keys`.
198
359
 
199
360
  ## Packages
200
361
 
201
- `anbaric` re-exports these packages; install them individually for a narrower
202
- dependency.
362
+ `anbaric` is the umbrella install for writing an application — it re-exports the
363
+ app-facing surface of the packages below. Install them individually for a
364
+ narrower dependency.
203
365
 
204
366
  - [`anbaric-tsapi`](https://npmjs.com/package/anbaric-tsapi) — the interfaces
205
- and value classes: `Job`, `State`, `Action`, `Transition`, `Actor`,
367
+ and value classes: `Job`, `State`, `Action`, `Await`, `Transition`, `Actor`,
206
368
  `JobPersistence`, `JsonStore`, `SecretStore`, `Auditor`.
207
369
  - [`anbaric-state-machine`](https://npmjs.com/package/anbaric-state-machine) —
208
370
  the `StateMachine`, actors, and in-memory implementations.
@@ -213,3 +375,24 @@ dependency.
213
375
  - [`anbaric-cli`](https://npmjs.com/package/anbaric-cli) — the platform CLI.
214
376
  - [`anbaric-hosting`](https://npmjs.com/package/anbaric-hosting) — run a
215
377
  platform yourself.
378
+
379
+ Applications should not set the `ANBARIC_*` factory variables themselves; the
380
+ platform sets them when the application is deployed, so the same code runs
381
+ in-memory locally and platform-backed once deployed.
382
+
383
+ ## Run your own platform
384
+
385
+ `npm install -g anbaric-hosting` provides the full hosting service - API,
386
+ dispatcher, build layers and proxy - bootable with the `anbaric-hosting`
387
+ command and configured entirely through `ANBARIC_*` environment variables.
388
+
389
+ ## Run a platform locally
390
+
391
+ ```bash
392
+ cd gitops/local
393
+ tofu init && tofu apply # Docker Desktop: Postgres + the platform on :8787
394
+ ```
395
+
396
+ See `gitops/README.md` for staging/prod and for enabling Auth0 login.
397
+ `sample-apps/crm` is a complete worked example — deploy it by running
398
+ `anbaric app deploy` from inside `sample-apps/crm`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anbaric",
3
- "version": "1.19.0",
3
+ "version": "1.20.1",
4
4
  "description": "Everything needed to write an Anbaric app: state machines, jobs, document and secret stores, local in-memory implementations and the Anbaric Cloud clients",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -9,10 +9,14 @@
9
9
  "files": [
10
10
  "src"
11
11
  ],
12
+ "scripts": {
13
+ "prepack": "rm -f README.md && cp ../README.md README.md",
14
+ "postpack": "rm -f README.md && ln -s ../README.md README.md"
15
+ },
12
16
  "dependencies": {
13
- "anbaric-impl-cloud": "^1.19.0",
14
- "anbaric-data-store": "^1.19.0",
15
- "anbaric-state-machine": "^1.19.0",
16
- "anbaric-tsapi": "^1.19.0"
17
+ "anbaric-impl-cloud": "^1.20.1",
18
+ "anbaric-data-store": "^1.20.1",
19
+ "anbaric-state-machine": "^1.20.1",
20
+ "anbaric-tsapi": "^1.20.1"
17
21
  }
18
22
  }