@neta-art/cohub 8.20.1 → 8.21.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 +6 -117
- package/dist/chunks/environment.d.ts +2508 -2308
- package/dist/chunks/http.d.ts +4 -2
- package/dist/chunks/http.js +5 -2
- package/dist/chunks/websocket.d.ts +1 -1
- package/dist/http.d.ts +1 -1
- package/dist/index.d.ts +70 -70
- package/dist/index.js +102 -1
- package/dist/protocol/dist/runtime/index.d.ts +1 -0
- package/dist/protocol/dist/runtime/native.d.ts +2 -0
- package/package.json +1 -2
- package/docs/app-runtime-guide.md +0 -1331
package/README.md
CHANGED
|
@@ -231,122 +231,11 @@ An **App** (previously *Work*) is a published, shareable web page hosted by
|
|
|
231
231
|
Cohub. When a viewer opens an App, it runs inside a Cohub-managed runtime that
|
|
232
232
|
provides short-lived access tokens — no API keys required.
|
|
233
233
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
viewer, permissions, optional invocation identifiers, and the current shell
|
|
238
|
-
location (`context.shell`). A new chat background has `shell.surface:
|
|
239
|
-
"background"` with the hosting Space in `shell.space` (`session` / `turn` are
|
|
240
|
-
null); `invocation.spaceId` is the same Space for compatibility.
|
|
241
|
-
Returns `null` outside an App runtime. `client.app.onContextChanged()` pushes
|
|
242
|
-
fresh state.
|
|
243
|
-
- `client.auth.authorize({ target, scopes, reason?, alwaysAsk?, fallback? })`
|
|
244
|
-
— requests consent for an account, a specific Space, or a viewer-picked
|
|
245
|
-
Space. Silent when a grant covers the scopes. Returns the actual target,
|
|
246
|
-
how it was resolved, and the authoritative grant; see the
|
|
247
|
-
[authorization contract](../../docs/app-authorization.md).
|
|
248
|
-
`client.auth.request()` / `requestSpace()` / `requestCreateSpace()` remain
|
|
249
|
-
available for older Apps.
|
|
250
|
-
- `client.context().permissions.viewerGrants` — render the viewer's current
|
|
251
|
-
per-space grants. Grant management uses an account-authenticated client or
|
|
252
|
-
the CLI; an App session cannot manage its own grants.
|
|
253
|
-
- `client.app.commerce.*` — entitlement checks, credit consumption,
|
|
254
|
-
purchases.
|
|
255
|
-
- `client.app.realtime.*` — temporary rooms, typed events, presence, and
|
|
256
|
-
membership.
|
|
257
|
-
|
|
258
|
-
### Quick start (inside an App)
|
|
234
|
+
The App runtime APIs — `client.context()`, `client.auth.authorize()`, app
|
|
235
|
+
scopes and viewer grants, realtime rooms, callable surface, composer context,
|
|
236
|
+
commerce, and App Actions — are documented in one place:
|
|
259
237
|
|
|
260
|
-
|
|
261
|
-
// Browsers don't inject ENV — pass it explicitly.
|
|
262
|
-
const client = createCohubClient({ env: "prod" });
|
|
263
|
-
|
|
264
|
-
const ctx = await client.context();
|
|
265
|
-
if (!ctx?.app?.id) throw new Error("Not inside a published app.");
|
|
266
|
-
|
|
267
|
-
const sourceSessionId = ctx.invocation?.sessionId ?? null;
|
|
268
|
-
// `shell.space` is the current Cohub location. `app.homeSpace` is the App's
|
|
269
|
-
// owning Space. A new chat background also has `invocation.spaceId`.
|
|
270
|
-
const spaceId = ctx.shell?.space?.id ?? ctx.invocation?.spaceId ?? ctx.app.homeSpace?.id;
|
|
271
|
-
const space = client.space(spaceId);
|
|
272
|
-
|
|
273
|
-
// Request viewer grants from a user gesture (button click)
|
|
274
|
-
const consent = await client.auth.authorize({
|
|
275
|
-
target: { kind: "space", spaceId },
|
|
276
|
-
scopes: ["session.prompt.fullaccess", "generation.create"],
|
|
277
|
-
reason: "This app sends prompts and generates images.",
|
|
278
|
-
});
|
|
279
|
-
if (consent.status !== "granted") return;
|
|
280
|
-
// Act on the granted target, which may differ from the request.
|
|
281
|
-
const activeSpace = consent.target.kind === "space"
|
|
282
|
-
? client.space(consent.target.spaceId)
|
|
283
|
-
: space;
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
### The permission model (critical)
|
|
287
|
-
|
|
288
|
-
An app's effective permission for one Space is the union of **two grant
|
|
289
|
-
sources** — either one is enough:
|
|
290
|
-
|
|
291
|
-
- **App scopes** (no consent): eight bounded scopes — `space.view`,
|
|
292
|
-
`session.view`, `file.view`, `file.edit`, `taskrun.view`,
|
|
293
|
-
`session.prompt.readonly`, `session.prompt.fullaccess`, `command.execute` —
|
|
294
|
-
granted at publish time via `appScopes`, applying only to the app's own
|
|
295
|
-
Space.
|
|
296
|
-
- **Viewer grants** (consent-required): any permission the viewer holds, on
|
|
297
|
-
any Space they choose — one grant per Space, valid 14 days, re-validated
|
|
298
|
-
against the viewer's live access on every request. Includes scopes beyond
|
|
299
|
-
the eight app scopes, such as `generation.create` and the account-level
|
|
300
|
-
`user.*` scopes.
|
|
301
|
-
|
|
302
|
-
**They never substitute for each other's halves.** `session.prompt.fullaccess`
|
|
303
|
-
lets you send a prompt but does NOT let you read the reply — that needs
|
|
304
|
-
`session.view`. `generation.create` lets you create a generation task, but
|
|
305
|
-
polling its result needs `taskrun.view`.
|
|
306
|
-
|
|
307
|
-
Render grant state from `ctx.permissions.viewerGrants`; act through
|
|
308
|
-
`auth.authorize()` (silent when covered). `allowedViewerScopes` is deprecated —
|
|
309
|
-
viewer grants are no longer gated by the app configuration.
|
|
310
|
-
|
|
311
|
-
### Realtime rooms
|
|
312
|
-
|
|
313
|
-
App runtime rooms are generic, temporary event channels. The SDK does not
|
|
314
|
-
know the App's business events; define their names and payload types in the
|
|
315
|
-
App itself.
|
|
316
|
-
|
|
317
|
-
```ts
|
|
318
|
-
type Events = {
|
|
319
|
-
"shared.state.updated": { value: number };
|
|
320
|
-
"activity.submitted": { itemId: string };
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
const room = await client.app.realtime.createRoom<Events>({
|
|
324
|
-
code: "TEAM-ALPHA", // optional; generated when omitted
|
|
325
|
-
maxParticipants: 64,
|
|
326
|
-
expiresInSeconds: 2 * 60 * 60,
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
const stop = room.subscribe("shared.state.updated", (event) => {
|
|
330
|
-
console.log(event.sequence, event.data.value, event.self);
|
|
331
|
-
});
|
|
332
|
-
|
|
333
|
-
await room.publish("shared.state.updated", { value: 42 });
|
|
334
|
-
await room.setPresence({ status: "active" });
|
|
335
|
-
await room.leave();
|
|
336
|
-
stop();
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
`expiresInSeconds` is an absolute lifetime from server-side room creation. It
|
|
340
|
-
never extends on publish, presence, or heartbeat. The maximum lifetime is
|
|
341
|
-
24 hours. Room events are live and ordered while connected, with publish ACKs
|
|
342
|
-
and sequence-gap detection; events missed during a disconnect are not replayed.
|
|
343
|
-
|
|
344
|
-
For high-frequency traffic such as input frames, `room.send(type, data)` skips
|
|
345
|
-
the per-event ACK that would otherwise cap throughput at one round trip per
|
|
346
|
-
event; failures surface through `room.onSendError`. Every connection is its own
|
|
347
|
-
participant by default; create the room with `seatPerUser: true` to give each
|
|
348
|
-
viewer a single seat instead.
|
|
238
|
+
**[App development](https://cohub.live/docs/developers/apps)**
|
|
349
239
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
**[App Runtime Guide](./docs/app-runtime-guide.md)**.
|
|
240
|
+
Runtime APIs only work inside a published App; local pages get `null` from
|
|
241
|
+
`context()`.
|