anbaric 1.79.3 → 1.80.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.
package/docs/README.md CHANGED
@@ -28,6 +28,7 @@ What the framework gives you, one capability at a time.
28
28
  - [File storage](features/file-storage.md) — bytes at a path, local or in your tenant's storage
29
29
  - [Auditing](features/auditing.md) — the record of who changed what
30
30
  - [Entitlements](features/entitlements.md) — what a user has been granted, checked per request
31
+ - [Public apps](features/public-apps.md) — apps anyone can open without signing in
31
32
  - [Skills](features/skills.md) — guidance your builders write for the agents working on your tenant
32
33
  - [Prompts](features/prompts.md) — versioned model instructions and schemas, saved at startup
33
34
  - [Serving a web UI](features/serving-a-web-ui.md) — putting your data on a page
@@ -76,6 +76,9 @@ anbaric jobs watch <job-id> # follow a job as it progresses
76
76
  Without the setting, jobs pause from the drain until the new version is up.
77
77
  The setting takes effect from the next deploy and is off by default. Anbaric
78
78
  Cloud only.
79
+ - **Public apps**, also switched on per app on the Manage apps page, for
80
+ $100/£100 a month, can be opened by anyone without signing in; see
81
+ [Public apps](public-apps.md).
79
82
 
80
83
  ## Updating and tearing down
81
84
 
@@ -42,12 +42,14 @@ server.on("request", async (request, response) => {
42
42
 
43
43
  A request with no session, or one the platform can't resolve, is simply not
44
44
  entitled - `hasEntitlement` returns `false` rather than throwing.
45
+ That is what a [public app](public-apps.md) sees for an anonymous visitor.
45
46
 
46
47
  ## Global entitlements
47
48
 
48
49
  Some entitlements aren't about one app. A **global entitlement** belongs to no
49
50
  app and is created in the console, never by `registerEntitlement`. Every tenant
50
- starts with one, `access`.
51
+ starts with one, `access`. A [public app](public-apps.md) needs no `access`:
52
+ anyone can open it.
51
53
 
52
54
  A grant can be scoped too. Granting a user `access` **for your app** and
53
55
  granting them `access` **globally** both make `hasEntitlement(request, "access")`
@@ -0,0 +1,76 @@
1
+ # Public apps
2
+
3
+ An app is private by default: only members of your tenant can open it, after
4
+ signing in. A **public app** can be opened by anyone with its address, without
5
+ signing in and without the `access` entitlement - a storefront, a booking page,
6
+ a form for your customers.
7
+
8
+ A builder turns it on per app on the console's **Manage apps** page. It costs
9
+ $100/£100 a month per public app, charged by the day it is public and never
10
+ covered by the free allowance. It takes effect within a few seconds and
11
+ restarts nothing.
12
+
13
+ ## Who your app sees
14
+
15
+ A public app is reached by two kinds of visitor:
16
+
17
+ - **A member** of your tenant who is signed in. They arrive with their session,
18
+ exactly as they would at a private app, so `hasEntitlement` and
19
+ `Human.fromSession` work for them and your other entitlements still apply.
20
+ - **Anyone else** - a stranger, or someone signed in to Anbaric who belongs to
21
+ a different tenant. They arrive with **no session at all**. The platform
22
+ never hands your app a session it did not issue, so nobody's identity from
23
+ elsewhere reaches your code.
24
+
25
+ Your app decides what an anonymous visitor may see and do. Check for a member
26
+ before anything that needs one:
27
+
28
+ ```ts
29
+ import {Human, hasEntitlement} from "anbaric";
30
+
31
+ const visitorOf = async (request : IncomingMessage) : Promise<Human | undefined> => {
32
+ try {
33
+ return await Human.fromSession(request);
34
+ } catch {
35
+ return undefined;
36
+ }
37
+ };
38
+
39
+ server.on("request", async (request, response) => {
40
+ if (request.url === "/admin" && ! await hasEntitlement(request, "admin")) {
41
+ response.writeHead(403).end("Members with the admin entitlement only");
42
+ return;
43
+ }
44
+ const visitor = await visitorOf(request);
45
+ ...
46
+ });
47
+ ```
48
+
49
+ `hasEntitlement` answers `false` for an anonymous visitor rather than throwing;
50
+ `Human.fromSession` throws, which is why it is wrapped above. Anything an
51
+ anonymous visitor does - a job started from a form, say - should be attributed
52
+ to a `Code` actor of your own naming, such as `new Code("storefront")`.
53
+
54
+ ## Letting members sign in
55
+
56
+ A member who is not signed in is treated as anonymous until they are. Give them
57
+ a link to `/login` on your app's own address:
58
+
59
+ ```html
60
+ <a href="/login">Sign in</a>
61
+ ```
62
+
63
+ It takes them through the sign-in and back to the page the link was on - read
64
+ from the browser's Referer, and only trusted when that page is on your app's
65
+ own address; otherwise they land on your app's home page. Someone already signed
66
+ in goes straight back. An app served under `/app/<name>` rather than its own
67
+ address can link to `/login` the same way.
68
+
69
+ Prefer serving a public app at its own address (see
70
+ [Serving a web UI](serving-a-web-ui.md)). Under `/app/<name>`, an absolute link
71
+ such as `/styles.css` falls outside the app and is not public.
72
+
73
+ ## Next
74
+
75
+ - [Entitlements](entitlements.md) - what a member has been granted
76
+ - [Authorization with actors and roles](../patterns/authorization.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anbaric",
3
- "version": "1.79.3",
3
+ "version": "1.80.0",
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",
@@ -24,9 +24,9 @@
24
24
  "prepublishOnly": "npm run build"
25
25
  },
26
26
  "dependencies": {
27
- "anbaric-impl-cloud": "^1.79.3",
28
- "anbaric-data-store": "^1.79.3",
29
- "anbaric-state-machine": "^1.79.3",
30
- "anbaric-tsapi": "^1.79.3"
27
+ "anbaric-impl-cloud": "^1.80.0",
28
+ "anbaric-data-store": "^1.80.0",
29
+ "anbaric-state-machine": "^1.80.0",
30
+ "anbaric-tsapi": "^1.80.0"
31
31
  }
32
32
  }