@hanzo/rooms 0.1.30 → 0.1.32

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/dist/Chat.js CHANGED
@@ -1185,12 +1185,11 @@ function Thread({ placeholder = message(), initial, anonymous = false, heading,
1185
1185
  // `center` on the surface, which spaces the pair from outside it,
1186
1186
  // because with a foot the composer is a shell around this frame and
1187
1187
  // a margin given here would land inside the shell.
1188
- // THE SAME MEASURE THE REST OF THIS FILE READS AT. The notice line and
1189
- // the error block are centred. A line of prose has a
1190
- // comfortable length and a field people write prose into has the same
1191
- // one.
1188
+ // THE SAME MEASURE THE REST OF THIS FILE READS AT. The transcript's
1189
+ // text sits at the measure less its own 0.75rem gutters, so the field
1190
+ // is that wide too and its edges line up with the words above it.
1192
1191
  width: "calc(100% - 32px)",
1193
- maxW: `calc(${MEASURE} - 3rem)`,
1192
+ maxW: `calc(${MEASURE} - 1.5rem)`,
1194
1193
  mx: "auto",
1195
1194
  ...(framed ? pane() : null),
1196
1195
  // THE COMPONENT'S OWN SHAPE, and nothing here reaching into it.
@@ -1239,7 +1238,7 @@ function Thread({ placeholder = message(), initial, anonymous = false, heading,
1239
1238
  },
1240
1239
  // WHAT GOES WITH THE MESSAGE, above the frame: one chip a file, each
1241
1240
  // with its own remove, and the reason any file was refused.
1242
- head: files.length || turnedAway || preparing || talk.open || talk.refusal || pause ? (_jsxs(YStack, { width: "calc(100% - 32px)", maxW: `calc(${MEASURE} - 3rem)`, mx: "auto", gap: "$1.5", children: [pause ? (_jsx(LimitedBanner, { message: pause.message, actions: pause.actions, onAction: act, onUsage: () => showSettings("usage") })) : null, actWrong ? (_jsx(Text, { role: "alert", "data-slot": "limited-banner-wrong", fontSize: "$2", color: BAD, children: actWrong })) : null, files.length ? (_jsx(XStack, { gap: "$1.5", flexWrap: "wrap", role: "list", "aria-label": "Attached files", "data-slot": "composer-attached", children: files.map((one) => (_jsx(HeldChip, { one: one, onRemove: () => drop(at, one.id) }, one.id))) })) : null, preparing ? (_jsxs(Text, { role: "status", "aria-live": "polite", "data-slot": "composer-preparing", fontSize: "$2", color: "$soft", children: [preparing, "\u2026"] })) : null, turnedAway ? (_jsx(Text, { role: "alert", fontSize: "$2", color: BAD, children: turnedAway })) : null, talk.open || talk.refusal ? (_jsx(Text, { role: "status", "aria-live": "polite", "data-slot": "composer-talk-reply", fontSize: "$2", color: talk.refusal ? BAD : "$soft", children: talk.refusal
1241
+ head: files.length || turnedAway || preparing || talk.open || talk.refusal || pause ? (_jsxs(YStack, { width: "calc(100% - 32px)", maxW: `calc(${MEASURE} - 1.5rem)`, mx: "auto", gap: "$1.5", children: [pause ? (_jsx(LimitedBanner, { message: pause.message, actions: pause.actions, onAction: act, onUsage: () => showSettings("usage") })) : null, actWrong ? (_jsx(Text, { role: "alert", "data-slot": "limited-banner-wrong", fontSize: "$2", color: BAD, children: actWrong })) : null, files.length ? (_jsx(XStack, { gap: "$1.5", flexWrap: "wrap", role: "list", "aria-label": "Attached files", "data-slot": "composer-attached", children: files.map((one) => (_jsx(HeldChip, { one: one, onRemove: () => drop(at, one.id) }, one.id))) })) : null, preparing ? (_jsxs(Text, { role: "status", "aria-live": "polite", "data-slot": "composer-preparing", fontSize: "$2", color: "$soft", children: [preparing, "\u2026"] })) : null, turnedAway ? (_jsx(Text, { role: "alert", fontSize: "$2", color: BAD, children: turnedAway })) : null, talk.open || talk.refusal ? (_jsx(Text, { role: "status", "aria-live": "polite", "data-slot": "composer-talk-reply", fontSize: "$2", color: talk.refusal ? BAD : "$soft", children: talk.refusal
1243
1242
  ? worded(talk.refusal)
1244
1243
  : talk.reply
1245
1244
  ? `Hanzo: ${talk.reply}`
@@ -1251,7 +1250,7 @@ function Thread({ placeholder = message(), initial, anonymous = false, heading,
1251
1250
  listening: "In conversation — click to hang up",
1252
1251
  speaking: "Hanzo is speaking — talk to interrupt",
1253
1252
  }, children: () => _jsx(AudioLines, { size: 15 }) }) }), _jsx(Control, { type: "button", size: ROUND, fill: true, "data-slot": "composer-send", "aria-label": chat.streaming ? "Stop" : "Send", opacity: chat.streaming || draft.trim() || files.length ? 1 : 0.4, onClick: () => (chat.streaming ? chat.stop() : submit()), children: chat.streaming ? (_jsx(Square, { size: 13, fill: "currentColor" })) : (_jsx(ArrowUp, { size: 15, strokeWidth: 2.5 })) })] })),
1254
- } }), _jsx(Crew, {}), isFree(model) ? (_jsx(XStack, { items: "center", justify: "center", py: "$1", px: "$3", borderTopWidth: 1, borderColor: "$borderColor", bg: "$background", children: _jsxs(Text, { fontSize: "$1", color: "$soft", children: ["Free chat is data-shared to train models. ", _jsx(Anchor, { href: site("/privacy"), fontSize: "$1", color: "$ink", children: "Privacy" })] }) })) : null, consent, _jsx(Upgrade, { ask: ask, onClose: () => setAsk(null) })] }));
1253
+ } }), said.length === 0 ? _jsx(Crew, {}) : null, isFree(model) ? (_jsx(XStack, { items: "center", justify: "center", py: "$1", px: "$3", borderTopWidth: 1, borderColor: "$borderColor", bg: "$background", children: _jsxs(Text, { fontSize: "$1", color: "$soft", children: ["Free chat is data-shared to train models. ", _jsx(Anchor, { href: site("/privacy"), fontSize: "$1", color: "$ink", children: "Privacy" })] }) })) : null, consent, _jsx(Upgrade, { ask: ask, onClose: () => setAsk(null) })] }));
1255
1254
  }
1256
1255
  /** The agreement free asks for, in @hanzo/ai's words so every surface says one thing. */
1257
1256
  function Consent({ question, onAgree, onCancel, }) {
package/dist/lib/org.d.ts CHANGED
@@ -5,8 +5,8 @@
5
5
  * delete the org DELETE /v1/iam/organizations/admin/<org>
6
6
  * found a team org POST /v1/iam/organizations {owner: admin, name, displayName}
7
7
  * business address GET|PUT /v1/settings/organization (cloud's per-org config)
8
- * your keys GET|POST|DELETE /v1/account/keys (minted by IAM on you, shown once)
9
- * the org's keys GET /v1/iam/keys?owner=<org>, DELETE /v1/iam/keys/<org>/<name>
8
+ * API keys GET|POST /v1/account/keys, DELETE /v1/account/keys/<id>
9
+ * (yours; every key of the org for an admin; a secret shown once)
10
10
  * payment methods GET /v1/billing/methods
11
11
  * invoices GET /v1/billing/invoices
12
12
  *
@@ -59,30 +59,37 @@ export declare function readAddress(): Promise<Address>;
59
59
  */
60
60
  export declare function saveAddress(next: Address): Promise<Address>;
61
61
  export type KeyType = 'secret' | 'publishable';
62
- /** One of the reader's own keys in the acting org. A secret key's value is never listed. */
63
- export interface OwnKey {
62
+ /**
63
+ * One API key the reader may see: their own, or any key of an org they administer.
64
+ * Each is its own credential, so creating one never replaces another. A secret
65
+ * key's value is never listed; `key` carries it once, in the answer to a create.
66
+ */
67
+ export interface ApiKey {
68
+ id: string;
69
+ name: string;
64
70
  type: KeyType;
71
+ /** The head of the credential, enough to tell which string it is. */
65
72
  prefix?: string;
66
- /** The whole value, for a publishable key only: it is public by construction. */
73
+ /** The whole value: always for a publishable key, once for a new secret one. */
67
74
  key?: string;
68
- createdAt?: string;
69
- }
70
- export declare function ownKeys(): Promise<OwnKey[]>;
71
- /** Mints the reader's key of `type`, replacing the one they held, and answers it — once. */
72
- export declare function mintKey(type: KeyType): Promise<string>;
73
- export declare const revokeOwnKey: (type: KeyType) => Promise<unknown>;
74
- /** One of the org's keys, as IAM lists them: the secret half never leaves IAM. */
75
- export interface OrgKey {
76
- owner: string;
77
- name: string;
78
- displayName?: string;
79
- user?: string;
80
- scope?: string;
81
- state?: string;
82
- createdTime?: string;
75
+ status: 'active' | 'expired' | 'revoked' | 'disabled';
76
+ /** Who the key speaks for, `<org>/<user>`. */
77
+ creator?: string;
78
+ created?: string;
79
+ expires?: string;
80
+ revoker?: string;
81
+ revoked?: string;
82
+ /** What the key may reach; empty reaches whatever its holder does. */
83
+ limit?: string[];
83
84
  }
84
- export declare function orgKeys(org: string): Promise<OrgKey[]>;
85
- export declare const revokeKey: (k: Pick<OrgKey, 'owner' | 'name'>) => Promise<unknown>;
85
+ export declare function keys(): Promise<ApiKey[]>;
86
+ /** Creates a new key beside the ones held, and answers it with its value — once. */
87
+ export declare function createKey(input: {
88
+ name?: string;
89
+ type: KeyType;
90
+ }): Promise<ApiKey>;
91
+ /** Revokes exactly one key. It stays listed as revoked; every other key keeps working. */
92
+ export declare const revokeKey: (id: string) => Promise<ApiKey>;
86
93
  /** A card on file, as billing lists it. */
87
94
  export interface Method {
88
95
  id: string;
package/dist/lib/org.js CHANGED
@@ -5,8 +5,8 @@
5
5
  * delete the org DELETE /v1/iam/organizations/admin/<org>
6
6
  * found a team org POST /v1/iam/organizations {owner: admin, name, displayName}
7
7
  * business address GET|PUT /v1/settings/organization (cloud's per-org config)
8
- * your keys GET|POST|DELETE /v1/account/keys (minted by IAM on you, shown once)
9
- * the org's keys GET /v1/iam/keys?owner=<org>, DELETE /v1/iam/keys/<org>/<name>
8
+ * API keys GET|POST /v1/account/keys, DELETE /v1/account/keys/<id>
9
+ * (yours; every key of the org for an admin; a secret shown once)
10
10
  * payment methods GET /v1/billing/methods
11
11
  * invoices GET /v1/billing/invoices
12
12
  *
@@ -112,21 +112,18 @@ export async function saveAddress(next) {
112
112
  const stored = await ask(PROFILE, { method: 'PUT', json: { config: { ...held, address: next } } });
113
113
  return addressOf(stored.config);
114
114
  }
115
- export async function ownKeys() {
115
+ export async function keys() {
116
116
  return list((await ask('/v1/account/keys')).keys);
117
117
  }
118
- /** Mints the reader's key of `type`, replacing the one they held, and answers it — once. */
119
- export async function mintKey(type) {
120
- const made = await ask('/v1/account/keys', { method: 'POST', json: { type } });
118
+ /** Creates a new key beside the ones held, and answers it with its value — once. */
119
+ export async function createKey(input) {
120
+ const made = await ask('/v1/account/keys', { method: 'POST', json: input });
121
121
  if (!made?.key)
122
122
  throw new Refusal(502, 'IAM answered without a key.');
123
- return made.key;
123
+ return made;
124
124
  }
125
- export const revokeOwnKey = (type) => ask(`/v1/account/keys?type=${type}`, { method: 'DELETE' });
126
- export async function orgKeys(org) {
127
- return list((await ask(`/v1/iam/keys?owner=${enc(org)}`)).keys);
128
- }
129
- export const revokeKey = (k) => ask(`/v1/iam/keys/${enc(k.owner)}/${enc(k.name)}`, { method: 'DELETE' });
125
+ /** Revokes exactly one key. It stays listed as revoked; every other key keeps working. */
126
+ export const revokeKey = (id) => ask(`/v1/account/keys/${enc(id)}`, { method: 'DELETE' });
130
127
  export async function methods() {
131
128
  const got = await ask('/v1/billing/methods');
132
129
  return list(Array.isArray(got) ? got : got?.data);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzo/rooms",
3
- "version": "0.1.30",
3
+ "version": "0.1.32",
4
4
  "description": "The workspace rooms — Home, Chat, Inbox, Contacts, Meet, Cal, Drive, Board, Work, Bots — and the frame that holds them, once, for every Hanzo surface.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",