@hanzo/rooms 0.1.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/LICENSE-APACHE +205 -0
- package/LICENSE-MIT +21 -0
- package/README.md +23 -0
- package/dist/Account.d.ts +8 -0
- package/dist/Account.js +58 -0
- package/dist/Beluga.d.ts +12 -0
- package/dist/Beluga.js +152 -0
- package/dist/Billing.d.ts +1 -0
- package/dist/Billing.js +31 -0
- package/dist/Board.d.ts +9 -0
- package/dist/Board.js +447 -0
- package/dist/Boxes.d.ts +1 -0
- package/dist/Boxes.js +173 -0
- package/dist/CalScheduler.d.ts +15 -0
- package/dist/CalScheduler.js +196 -0
- package/dist/Chat.d.ts +35 -0
- package/dist/Chat.js +1049 -0
- package/dist/Column.d.ts +15 -0
- package/dist/Column.js +88 -0
- package/dist/Contacts.d.ts +1 -0
- package/dist/Contacts.js +301 -0
- package/dist/Directory.d.ts +24 -0
- package/dist/Directory.js +356 -0
- package/dist/Drive.d.ts +2 -0
- package/dist/Drive.js +466 -0
- package/dist/Find.d.ts +7 -0
- package/dist/Find.js +82 -0
- package/dist/Guide.d.ts +6 -0
- package/dist/Guide.js +272 -0
- package/dist/Home.d.ts +39 -0
- package/dist/Home.js +306 -0
- package/dist/Inbox.d.ts +9 -0
- package/dist/Inbox.js +193 -0
- package/dist/Market.d.ts +3 -0
- package/dist/Market.js +149 -0
- package/dist/Me.d.ts +27 -0
- package/dist/Me.js +251 -0
- package/dist/Meet.d.ts +9 -0
- package/dist/Meet.js +370 -0
- package/dist/ModeMark.d.ts +8 -0
- package/dist/ModeMark.js +18 -0
- package/dist/OrgSwitcher.d.ts +31 -0
- package/dist/OrgSwitcher.js +120 -0
- package/dist/Orgs.d.ts +10 -0
- package/dist/Orgs.js +582 -0
- package/dist/Profile.d.ts +4 -0
- package/dist/Profile.js +67 -0
- package/dist/Prose.d.ts +5 -0
- package/dist/Prose.js +111 -0
- package/dist/ProviderMark.d.ts +17 -0
- package/dist/ProviderMark.js +277 -0
- package/dist/Recents.d.ts +10 -0
- package/dist/Recents.js +91 -0
- package/dist/RightPane.d.ts +13 -0
- package/dist/RightPane.js +426 -0
- package/dist/Room.d.ts +8 -0
- package/dist/Room.js +50 -0
- package/dist/Scene.d.ts +12 -0
- package/dist/Scene.js +105 -0
- package/dist/Settings.d.ts +46 -0
- package/dist/Settings.js +321 -0
- package/dist/Setup.d.ts +1 -0
- package/dist/Setup.js +36 -0
- package/dist/Share.d.ts +3 -0
- package/dist/Share.js +130 -0
- package/dist/Shared.d.ts +1 -0
- package/dist/Shared.js +113 -0
- package/dist/Shell.d.ts +63 -0
- package/dist/Shell.js +1225 -0
- package/dist/Start.d.ts +1 -0
- package/dist/Start.js +96 -0
- package/dist/Support.d.ts +14 -0
- package/dist/Support.js +122 -0
- package/dist/Talk.d.ts +4 -0
- package/dist/Talk.js +107 -0
- package/dist/Upgrade.d.ts +11 -0
- package/dist/Upgrade.js +75 -0
- package/dist/Usage.d.ts +1 -0
- package/dist/Usage.js +21 -0
- package/dist/Vibe.d.ts +2 -0
- package/dist/Vibe.js +188 -0
- package/dist/Work.d.ts +12 -0
- package/dist/Work.js +256 -0
- package/dist/bots/Bots.d.ts +2 -0
- package/dist/bots/Bots.js +456 -0
- package/dist/bots/Lights.d.ts +8 -0
- package/dist/bots/Lights.js +13 -0
- package/dist/bots/api.d.ts +120 -0
- package/dist/bots/api.js +75 -0
- package/dist/bots/face.d.ts +5 -0
- package/dist/bots/face.js +13 -0
- package/dist/bots/ink.d.ts +7 -0
- package/dist/bots/ink.js +29 -0
- package/dist/bots/kit.d.ts +113 -0
- package/dist/bots/kit.js +43 -0
- package/dist/bots/runtime.d.ts +4 -0
- package/dist/bots/runtime.js +326 -0
- package/dist/card.d.ts +52 -0
- package/dist/card.js +52 -0
- package/dist/cast.d.ts +143 -0
- package/dist/cast.js +251 -0
- package/dist/connect.d.ts +29 -0
- package/dist/connect.js +64 -0
- package/dist/contacts-store.d.ts +111 -0
- package/dist/contacts-store.js +276 -0
- package/dist/conversations.d.ts +54 -0
- package/dist/conversations.js +98 -0
- package/dist/copy.d.ts +23 -0
- package/dist/copy.js +39 -0
- package/dist/crew.d.ts +36 -0
- package/dist/crew.js +304 -0
- package/dist/dev.d.ts +3 -0
- package/dist/dev.js +102 -0
- package/dist/enso.d.ts +70 -0
- package/dist/enso.js +112 -0
- package/dist/failure.d.ts +57 -0
- package/dist/failure.js +143 -0
- package/dist/ground.d.ts +32 -0
- package/dist/ground.js +32 -0
- package/dist/host.d.ts +76 -0
- package/dist/host.js +76 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +12 -0
- package/dist/kept.d.ts +5 -0
- package/dist/kept.js +27 -0
- package/dist/lib/account.d.ts +49 -0
- package/dist/lib/account.js +229 -0
- package/dist/lib/ai.d.ts +46 -0
- package/dist/lib/ai.js +140 -0
- package/dist/lib/api.d.ts +43 -0
- package/dist/lib/api.js +62 -0
- package/dist/lib/bare.d.ts +9 -0
- package/dist/lib/bare.js +7 -0
- package/dist/lib/coding.d.ts +105 -0
- package/dist/lib/coding.js +87 -0
- package/dist/lib/destination.d.ts +102 -0
- package/dist/lib/destination.js +260 -0
- package/dist/lib/durable.d.ts +66 -0
- package/dist/lib/durable.js +107 -0
- package/dist/lib/first.d.ts +11 -0
- package/dist/lib/first.js +23 -0
- package/dist/lib/home.d.ts +61 -0
- package/dist/lib/home.js +54 -0
- package/dist/lib/host.d.ts +104 -0
- package/dist/lib/host.js +132 -0
- package/dist/lib/hostname.d.ts +1 -0
- package/dist/lib/hostname.js +14 -0
- package/dist/lib/hydrated.d.ts +1 -0
- package/dist/lib/hydrated.js +20 -0
- package/dist/lib/integrations.d.ts +21 -0
- package/dist/lib/integrations.js +1 -0
- package/dist/lib/intent.d.ts +6 -0
- package/dist/lib/intent.js +71 -0
- package/dist/lib/invite.d.ts +155 -0
- package/dist/lib/invite.js +245 -0
- package/dist/lib/limits.d.ts +55 -0
- package/dist/lib/limits.js +119 -0
- package/dist/lib/list.d.ts +9 -0
- package/dist/lib/list.js +11 -0
- package/dist/lib/mark.d.ts +13 -0
- package/dist/lib/mark.js +85 -0
- package/dist/lib/mix.d.ts +22 -0
- package/dist/lib/mix.js +22 -0
- package/dist/lib/models.d.ts +27 -0
- package/dist/lib/models.js +106 -0
- package/dist/lib/org.d.ts +109 -0
- package/dist/lib/org.js +140 -0
- package/dist/lib/path.d.ts +9 -0
- package/dist/lib/path.js +29 -0
- package/dist/lib/plans.d.ts +193 -0
- package/dist/lib/plans.js +310 -0
- package/dist/lib/prose.d.ts +13 -0
- package/dist/lib/prose.js +62 -0
- package/dist/lib/reach.d.ts +17 -0
- package/dist/lib/reach.js +70 -0
- package/dist/lib/rooms.json +23 -0
- package/dist/lib/served.d.ts +20 -0
- package/dist/lib/served.js +92 -0
- package/dist/lib/session.d.ts +211 -0
- package/dist/lib/session.js +493 -0
- package/dist/lib/share.d.ts +131 -0
- package/dist/lib/share.js +216 -0
- package/dist/lib/signout.d.ts +14 -0
- package/dist/lib/signout.js +40 -0
- package/dist/lib/tags.d.ts +27 -0
- package/dist/lib/tags.js +46 -0
- package/dist/lib/tap.d.ts +17 -0
- package/dist/lib/tap.js +9 -0
- package/dist/lib/tier.d.ts +115 -0
- package/dist/lib/tier.js +207 -0
- package/dist/lib/tiers.d.ts +9 -0
- package/dist/lib/tiers.js +141 -0
- package/dist/lib/todo.d.ts +125 -0
- package/dist/lib/todo.js +379 -0
- package/dist/look.d.ts +1 -0
- package/dist/look.js +21 -0
- package/dist/meters.d.ts +8 -0
- package/dist/meters.js +31 -0
- package/dist/model.d.ts +4 -0
- package/dist/model.js +44 -0
- package/dist/network.d.ts +64 -0
- package/dist/network.js +216 -0
- package/dist/open.d.ts +81 -0
- package/dist/open.js +149 -0
- package/dist/pane.d.ts +92 -0
- package/dist/pane.js +231 -0
- package/dist/progress.d.ts +46 -0
- package/dist/progress.js +51 -0
- package/dist/recent.d.ts +67 -0
- package/dist/recent.js +161 -0
- package/dist/rooms.d.ts +131 -0
- package/dist/rooms.js +195 -0
- package/dist/roster.d.ts +28 -0
- package/dist/roster.js +70 -0
- package/dist/span.d.ts +14 -0
- package/dist/span.js +50 -0
- package/dist/speech.d.ts +44 -0
- package/dist/speech.js +229 -0
- package/dist/stars.d.ts +16 -0
- package/dist/stars.js +75 -0
- package/dist/tabs.d.ts +26 -0
- package/dist/tabs.js +25 -0
- package/dist/team.d.ts +11 -0
- package/dist/team.gen.d.ts +10 -0
- package/dist/team.gen.js +11 -0
- package/dist/team.js +30 -0
- package/dist/tools.d.ts +35 -0
- package/dist/tools.js +143 -0
- package/dist/tours.d.ts +24 -0
- package/dist/tours.js +311 -0
- package/dist/waiting.d.ts +15 -0
- package/dist/waiting.js +17 -0
- package/dist/where.d.ts +54 -0
- package/dist/where.js +14 -0
- package/package.json +108 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** Whether the store answered and the answer was no — exported so a surface can
|
|
2
|
+
* offer the way past a refusal rather than only describing it. */
|
|
3
|
+
export declare const refused: (error: unknown) => boolean;
|
|
4
|
+
/**
|
|
5
|
+
* A sentence about `subject` — "your drive", "this board" — naming what a
|
|
6
|
+
* reader can do next. Never the caught text: an error written for an operator
|
|
7
|
+
* is not an answer for a reader.
|
|
8
|
+
*/
|
|
9
|
+
export declare function say(error: unknown, subject: string, act?: 'read' | 'save'): string;
|
|
10
|
+
/**
|
|
11
|
+
* The reader's version of a failure, keeping what the store said when that is
|
|
12
|
+
* an answer.
|
|
13
|
+
*
|
|
14
|
+
* A gateway that refuses over credit, a context that ran long, a model nobody
|
|
15
|
+
* serves — each of those is the reader's own situation, stated by the only
|
|
16
|
+
* thing that knows it, and translating them away would leave a room saying
|
|
17
|
+
* nothing where it could have said the one useful thing. A gateway that is not
|
|
18
|
+
* there, or one that refused the account, is the estate talking to itself; that
|
|
19
|
+
* half is replaced.
|
|
20
|
+
*/
|
|
21
|
+
export declare function plainly(error: unknown, subject: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Whether a refusal asks for a plan, and the checkout it names.
|
|
24
|
+
*
|
|
25
|
+
* The gateway refuses a model the plan does not include with 402
|
|
26
|
+
* `plan_required`, a Free caller whose share is spent with 402
|
|
27
|
+
* `allowance_spent`, and a free request the shared pool cannot serve with 429
|
|
28
|
+
* `pool_busy` or `pool_exhausted`, each with an `upgrade_url`. The code decides,
|
|
29
|
+
* never the sentence. The address is kept only when it is an https page on
|
|
30
|
+
* hanzo.ai or one of its hosts; any other leaves `href` empty and the caller
|
|
31
|
+
* builds its own.
|
|
32
|
+
*/
|
|
33
|
+
export declare function planRequired(error: unknown): {
|
|
34
|
+
href?: string;
|
|
35
|
+
} | null;
|
|
36
|
+
/** A plan holder's spent window. */
|
|
37
|
+
export interface Cap {
|
|
38
|
+
limit: 'session' | 'day';
|
|
39
|
+
/** When it opens again, RFC 3339. */
|
|
40
|
+
resets: string | null;
|
|
41
|
+
/** The next plan's checkout, on hanzo.ai only. Absent at the top plan. */
|
|
42
|
+
href?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Whether a refusal is a plan's usage limit, and which window.
|
|
46
|
+
*
|
|
47
|
+
* A paid plan is a subscription with limits: a spent session or day comes back
|
|
48
|
+
* 429 `usage_cap_exceeded` naming the window, its reset and, below the top
|
|
49
|
+
* plan, an `upgrade_url`. The month refuses nothing — Enso and Zen keep
|
|
50
|
+
* answering — so no other window is a cap. The code decides, never the
|
|
51
|
+
* sentence, and the address is kept by the rule `planRequired` keeps.
|
|
52
|
+
*/
|
|
53
|
+
export declare function capped(error: unknown): Cap | null;
|
|
54
|
+
/** The family a model id belongs to, as a reader knows it, or '' for one outside them. */
|
|
55
|
+
export declare const familyOf: (id: string) => string;
|
|
56
|
+
/** What the server said about a failure, for the detail folded under the plain line. */
|
|
57
|
+
export declare const detail: (error: unknown) => string;
|
package/dist/failure.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
// What to tell a reader when a room's store does not answer.
|
|
3
|
+
//
|
|
4
|
+
// The rooms used to print the error they caught, which on a store that is down
|
|
5
|
+
// reads "mount /v1/s3: no instance running". That says nothing a reader can act
|
|
6
|
+
// on — it names a mount and an instance, neither of which is theirs — and it
|
|
7
|
+
// puts the shape of the estate on a public page. The detail is still in the
|
|
8
|
+
// network tab, where the person who can act on it is looking.
|
|
9
|
+
//
|
|
10
|
+
// ONE FUNCTION, because every room owes the same three answers and three copies
|
|
11
|
+
// would drift into three vocabularies for one event.
|
|
12
|
+
import { told } from './lib/reach.js';
|
|
13
|
+
/**
|
|
14
|
+
* THE STATUS, WHERE THE FAILURE CARRIES ONE.
|
|
15
|
+
*
|
|
16
|
+
* `@hanzo/ai`'s APIError publishes `status` as a number, and a number is a fact
|
|
17
|
+
* — while the message beside it is prose the SDK is free to improve. It did:
|
|
18
|
+
* 0.6.16 added a table answering 503 with "The service is not running right
|
|
19
|
+
* now.", which reads the same to a person and matches none of the patterns
|
|
20
|
+
* below, so every downed store fell through to the flat "Could not read" and
|
|
21
|
+
* the rooms stopped saying that nothing had been lost. Reading the status first
|
|
22
|
+
* is what makes this survive the next rewording.
|
|
23
|
+
*/
|
|
24
|
+
const status = (e) => {
|
|
25
|
+
const s = e?.status;
|
|
26
|
+
return typeof s === 'number' && Number.isFinite(s) ? s : null;
|
|
27
|
+
};
|
|
28
|
+
/** True where a failure is the store being absent rather than the reader. The
|
|
29
|
+
* text is still read, because a network failure raises before any status. */
|
|
30
|
+
const absent = (text) => /no instance running|not running|service unavailable|503|econnrefused|failed to fetch|network/i.test(text);
|
|
31
|
+
/**
|
|
32
|
+
* True where the answer was no, whoever said it.
|
|
33
|
+
*
|
|
34
|
+
* Three vocabularies for one event. The gateway says 401 "authentication
|
|
35
|
+
* required" on a turn and 403 "a validated principal is required" on a read,
|
|
36
|
+
* and the SDK raises before sending at all when it has no credential to send
|
|
37
|
+
* with. A reader meets the same wall in every case, so all three read as one.
|
|
38
|
+
*/
|
|
39
|
+
const barred = (text) => /401|403|forbidden|unauthori[sz]ed|not authori[sz]ed|authentication required|validated principal|permission|serve anonymous|anonymous completions/i.test(text);
|
|
40
|
+
/** Whether the store answered and the answer was no — exported so a surface can
|
|
41
|
+
* offer the way past a refusal rather than only describing it. */
|
|
42
|
+
export const refused = (error) => {
|
|
43
|
+
const code = status(error);
|
|
44
|
+
if (code === 401 || code === 403)
|
|
45
|
+
return true;
|
|
46
|
+
return barred(error instanceof Error ? error.message : String(error ?? ''));
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* A sentence about `subject` — "your drive", "this board" — naming what a
|
|
50
|
+
* reader can do next. Never the caught text: an error written for an operator
|
|
51
|
+
* is not an answer for a reader.
|
|
52
|
+
*/
|
|
53
|
+
export function say(error, subject, act = 'read') {
|
|
54
|
+
const text = error instanceof Error ? error.message : String(error ?? '');
|
|
55
|
+
const code = status(error);
|
|
56
|
+
// VERB FIRST, so the subject's number never has to agree with anything. Said
|
|
57
|
+
// subject-first, "your projects is not answering" is what a plural name gets,
|
|
58
|
+
// and every caller then has to remember to phrase its subject singular.
|
|
59
|
+
if (code === 502 || code === 503 || code === 504 || absent(text))
|
|
60
|
+
return `Could not reach ${subject}. Nothing has been lost — try again shortly.`;
|
|
61
|
+
if (code === 401 || code === 403 || barred(text))
|
|
62
|
+
return act === 'save'
|
|
63
|
+
? `This account cannot change ${subject}.`
|
|
64
|
+
: `This account cannot open ${subject}.`;
|
|
65
|
+
return act === 'save' ? `Could not save ${subject}.` : `Could not read ${subject}.`;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The reader's version of a failure, keeping what the store said when that is
|
|
69
|
+
* an answer.
|
|
70
|
+
*
|
|
71
|
+
* A gateway that refuses over credit, a context that ran long, a model nobody
|
|
72
|
+
* serves — each of those is the reader's own situation, stated by the only
|
|
73
|
+
* thing that knows it, and translating them away would leave a room saying
|
|
74
|
+
* nothing where it could have said the one useful thing. A gateway that is not
|
|
75
|
+
* there, or one that refused the account, is the estate talking to itself; that
|
|
76
|
+
* half is replaced.
|
|
77
|
+
*/
|
|
78
|
+
export function plainly(error, subject) {
|
|
79
|
+
const text = error instanceof Error ? error.message : String(error ?? '');
|
|
80
|
+
return absent(text) || barred(text) ? say(error, subject) : told(error) ?? text;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The refusals a plan lifts, by the status each arrives with: a model the plan
|
|
84
|
+
* does not include, and the Free plan's two limits — a person's own share of
|
|
85
|
+
* the pool spent for the window, and the pool every free user shares used up.
|
|
86
|
+
*/
|
|
87
|
+
const LIFTED = {
|
|
88
|
+
plan_required: 402,
|
|
89
|
+
allowance_spent: 402,
|
|
90
|
+
pool_busy: 429,
|
|
91
|
+
pool_exhausted: 429,
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Whether a refusal asks for a plan, and the checkout it names.
|
|
95
|
+
*
|
|
96
|
+
* The gateway refuses a model the plan does not include with 402
|
|
97
|
+
* `plan_required`, a Free caller whose share is spent with 402
|
|
98
|
+
* `allowance_spent`, and a free request the shared pool cannot serve with 429
|
|
99
|
+
* `pool_busy` or `pool_exhausted`, each with an `upgrade_url`. The code decides,
|
|
100
|
+
* never the sentence. The address is kept only when it is an https page on
|
|
101
|
+
* hanzo.ai or one of its hosts; any other leaves `href` empty and the caller
|
|
102
|
+
* builds its own.
|
|
103
|
+
*/
|
|
104
|
+
export function planRequired(error) {
|
|
105
|
+
const said = error?.body?.error;
|
|
106
|
+
const code = typeof said?.code === 'string' ? said.code : '';
|
|
107
|
+
if (!LIFTED[code] || status(error) !== LIFTED[code])
|
|
108
|
+
return null;
|
|
109
|
+
return { href: ours(said?.upgrade_url) };
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Whether a refusal is a plan's usage limit, and which window.
|
|
113
|
+
*
|
|
114
|
+
* A paid plan is a subscription with limits: a spent session or day comes back
|
|
115
|
+
* 429 `usage_cap_exceeded` naming the window, its reset and, below the top
|
|
116
|
+
* plan, an `upgrade_url`. The month refuses nothing — Enso and Zen keep
|
|
117
|
+
* answering — so no other window is a cap. The code decides, never the
|
|
118
|
+
* sentence, and the address is kept by the rule `planRequired` keeps.
|
|
119
|
+
*/
|
|
120
|
+
export function capped(error) {
|
|
121
|
+
const said = error?.body?.error;
|
|
122
|
+
if (said?.code !== 'usage_cap_exceeded' || status(error) !== 429)
|
|
123
|
+
return null;
|
|
124
|
+
if (said.limit !== 'session' && said.limit !== 'day')
|
|
125
|
+
return null;
|
|
126
|
+
return { limit: said.limit, resets: typeof said.resets_at === 'string' ? said.resets_at : null, href: ours(said.upgrade_url) };
|
|
127
|
+
}
|
|
128
|
+
function ours(href) {
|
|
129
|
+
if (typeof href !== 'string')
|
|
130
|
+
return undefined;
|
|
131
|
+
try {
|
|
132
|
+
const url = new URL(href);
|
|
133
|
+
const host = url.hostname;
|
|
134
|
+
return url.protocol === 'https:' && (host === 'hanzo.ai' || host.endsWith('.hanzo.ai')) ? url.toString() : undefined;
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/** The family a model id belongs to, as a reader knows it, or '' for one outside them. */
|
|
141
|
+
export const familyOf = (id) => /^(hanzo\/)?enso/i.test(id) ? 'Enso' : /^(hanzo\/)?zen/i.test(id) ? 'Zen' : '';
|
|
142
|
+
/** What the server said about a failure, for the detail folded under the plain line. */
|
|
143
|
+
export const detail = (error) => told(error) ?? (error instanceof Error ? error.message : String(error ?? ''));
|
package/dist/ground.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ground the workspace's cards stand on, and how each card is cut.
|
|
3
|
+
*
|
|
4
|
+
* A PANE is a card floating on the ground, cut by the `--pane-*` tokens
|
|
5
|
+
* (app/globals.css): a corner, an edge, the lens behind it, and the second
|
|
6
|
+
* paper rung's lit edge and drop. The fill is the caller's rung: `--pane-fill`
|
|
7
|
+
* in the app's frame, `sheet(1)`/`sheet(2)` where a pane lies in a room.
|
|
8
|
+
*
|
|
9
|
+
* The drop is a prop and not `sheet(2)`'s `elevation-2` class, whose shadow is
|
|
10
|
+
* `!important`: a Dev run's pane steps aside for the two panes inside it by
|
|
11
|
+
* slot (@hanzo/build's `run-split`), and an important shadow would stay behind.
|
|
12
|
+
*/
|
|
13
|
+
export declare const pane: (fill?: string) => {
|
|
14
|
+
readonly backgroundColor: string;
|
|
15
|
+
readonly borderRadius: 'var(--pane-round)';
|
|
16
|
+
readonly borderWidth: 1;
|
|
17
|
+
readonly borderColor: 'var(--pane-edge)';
|
|
18
|
+
readonly backdropFilter: 'var(--pane-blur)';
|
|
19
|
+
readonly boxShadow: 'var(--shadow-sheet-2)';
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* THE FLOOR under the app's frame (app/_web.tsx, components/settings/Frame.tsx):
|
|
23
|
+
* design's top light falling off down the window over the faint lamps of
|
|
24
|
+
* `--pane-ground`. A straight fall rather than a radial glow, because at these
|
|
25
|
+
* alphas a circle quantises into rings a blur makes plainer.
|
|
26
|
+
*/
|
|
27
|
+
export declare const floor: {
|
|
28
|
+
readonly backgroundColor: 'var(--pane-floor)';
|
|
29
|
+
readonly backgroundImage: 'linear-gradient(to bottom, var(--glass-strong), transparent), var(--pane-ground)';
|
|
30
|
+
readonly backgroundSize: '100% 70%, auto';
|
|
31
|
+
readonly backgroundRepeat: 'no-repeat';
|
|
32
|
+
};
|
package/dist/ground.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ground the workspace's cards stand on, and how each card is cut.
|
|
3
|
+
*
|
|
4
|
+
* A PANE is a card floating on the ground, cut by the `--pane-*` tokens
|
|
5
|
+
* (app/globals.css): a corner, an edge, the lens behind it, and the second
|
|
6
|
+
* paper rung's lit edge and drop. The fill is the caller's rung: `--pane-fill`
|
|
7
|
+
* in the app's frame, `sheet(1)`/`sheet(2)` where a pane lies in a room.
|
|
8
|
+
*
|
|
9
|
+
* The drop is a prop and not `sheet(2)`'s `elevation-2` class, whose shadow is
|
|
10
|
+
* `!important`: a Dev run's pane steps aside for the two panes inside it by
|
|
11
|
+
* slot (@hanzo/build's `run-split`), and an important shadow would stay behind.
|
|
12
|
+
*/
|
|
13
|
+
export const pane = (fill = 'var(--pane-fill)') => ({
|
|
14
|
+
backgroundColor: fill,
|
|
15
|
+
borderRadius: 'var(--pane-round)',
|
|
16
|
+
borderWidth: 1,
|
|
17
|
+
borderColor: 'var(--pane-edge)',
|
|
18
|
+
backdropFilter: 'var(--pane-blur)',
|
|
19
|
+
boxShadow: 'var(--shadow-sheet-2)',
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* THE FLOOR under the app's frame (app/_web.tsx, components/settings/Frame.tsx):
|
|
23
|
+
* design's top light falling off down the window over the faint lamps of
|
|
24
|
+
* `--pane-ground`. A straight fall rather than a radial glow, because at these
|
|
25
|
+
* alphas a circle quantises into rings a blur makes plainer.
|
|
26
|
+
*/
|
|
27
|
+
export const floor = {
|
|
28
|
+
backgroundColor: 'var(--pane-floor)',
|
|
29
|
+
backgroundImage: 'linear-gradient(to bottom, var(--glass-strong), transparent), var(--pane-ground)',
|
|
30
|
+
backgroundSize: '100% 70%, auto',
|
|
31
|
+
backgroundRepeat: 'no-repeat',
|
|
32
|
+
};
|
package/dist/host.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a host tells the rooms.
|
|
3
|
+
*
|
|
4
|
+
* The rooms name no framework and no site. Everything that differs between the
|
|
5
|
+
* surfaces that mount them arrives here, in two halves, because two kinds of
|
|
6
|
+
* caller read them:
|
|
7
|
+
*
|
|
8
|
+
* configure({ site: 'https://hanzo.ai', home: '/', signUp: '/start' })
|
|
9
|
+
*
|
|
10
|
+
* <Rooms router={useRouter()} search={useSearchParams()} route={route} Link={Link}>
|
|
11
|
+
* <Room mode="cal" />
|
|
12
|
+
* </Rooms>
|
|
13
|
+
*
|
|
14
|
+
* The ADDRESSES — where the app's pages live, which gateway and IAM to talk to,
|
|
15
|
+
* the plan catalogue to paint first — do not change while the page is open, and
|
|
16
|
+
* plain modules (`api()`, `iam()`, `site()`, the plan reads) call them outside
|
|
17
|
+
* any component and on pages the rooms never draw. So the host states them once
|
|
18
|
+
* with `configure()`, in a module its root imports, before anything renders.
|
|
19
|
+
*
|
|
20
|
+
* The ROUTER, the query and the route change as the page moves, so they ride
|
|
21
|
+
* React context, and a room reads them with `useRooms()`.
|
|
22
|
+
*/
|
|
23
|
+
import { type AnchorHTMLAttributes, type ComponentType, type ReactNode } from 'react';
|
|
24
|
+
/** A link the host's router owns: next/link under Next, an anchor elsewhere. */
|
|
25
|
+
export type Link = ComponentType<AnchorHTMLAttributes<HTMLAnchorElement> & {
|
|
26
|
+
href: string;
|
|
27
|
+
prefetch?: boolean;
|
|
28
|
+
}>;
|
|
29
|
+
export interface Router {
|
|
30
|
+
push(href: string): void;
|
|
31
|
+
replace(href: string): void;
|
|
32
|
+
back(): void;
|
|
33
|
+
forward(): void;
|
|
34
|
+
}
|
|
35
|
+
interface Moving {
|
|
36
|
+
router: Router;
|
|
37
|
+
/** The address's query, for the rooms that read one (Dev's `?at=`). */
|
|
38
|
+
search: URLSearchParams | null;
|
|
39
|
+
route: string;
|
|
40
|
+
Link: Link;
|
|
41
|
+
}
|
|
42
|
+
export interface RoomsProps extends Omit<Moving, 'search'> {
|
|
43
|
+
/** Absent where no mounted room reads the query, so a static export needs no Suspense for it. */
|
|
44
|
+
search?: URLSearchParams | null;
|
|
45
|
+
children?: ReactNode;
|
|
46
|
+
}
|
|
47
|
+
/** The router, the query, the route and the link the host mounted the rooms with. */
|
|
48
|
+
export declare const useRooms: () => Moving;
|
|
49
|
+
/** The org in scope, by the id the appearance layers are keyed on. */
|
|
50
|
+
export declare function useOrg(): {
|
|
51
|
+
id?: string;
|
|
52
|
+
name?: string;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* The person's appearance — theme, type, spacing, corners, accent — resolved
|
|
56
|
+
* for the org in scope and kept with their IAM account, so a choice made here
|
|
57
|
+
* follows them to every Hanzo origin. Every control that changes how the rooms
|
|
58
|
+
* look goes through this, and only this.
|
|
59
|
+
*/
|
|
60
|
+
export declare function useLook(): {
|
|
61
|
+
pref: import("@hanzo/appearance").Preference;
|
|
62
|
+
set: (patch: Partial<import("@hanzo/appearance").Preference>) => void;
|
|
63
|
+
reset: () => void;
|
|
64
|
+
scope: import("@hanzo/appearance").Scope;
|
|
65
|
+
setScope: (s: import("@hanzo/appearance").Scope) => import("@hanzo/appearance").Resolved;
|
|
66
|
+
from: Partial<Record<keyof import("@hanzo/appearance").Preference, "install" | "org" | "user" | "userOrg">>;
|
|
67
|
+
layer: "user" | "userOrg";
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* The look, applied: mounted once at the host's root, inside its IamProvider,
|
|
71
|
+
* so every page — a room or not — opens in the person's theme and accent and
|
|
72
|
+
* keeps their choice in step with IAM.
|
|
73
|
+
*/
|
|
74
|
+
export declare function Look(): any;
|
|
75
|
+
export declare function Rooms({ router, search, route, Link, children }: RoomsProps): import("react").JSX.Element;
|
|
76
|
+
export {};
|
package/dist/host.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* What a host tells the rooms.
|
|
5
|
+
*
|
|
6
|
+
* The rooms name no framework and no site. Everything that differs between the
|
|
7
|
+
* surfaces that mount them arrives here, in two halves, because two kinds of
|
|
8
|
+
* caller read them:
|
|
9
|
+
*
|
|
10
|
+
* configure({ site: 'https://hanzo.ai', home: '/', signUp: '/start' })
|
|
11
|
+
*
|
|
12
|
+
* <Rooms router={useRouter()} search={useSearchParams()} route={route} Link={Link}>
|
|
13
|
+
* <Room mode="cal" />
|
|
14
|
+
* </Rooms>
|
|
15
|
+
*
|
|
16
|
+
* The ADDRESSES — where the app's pages live, which gateway and IAM to talk to,
|
|
17
|
+
* the plan catalogue to paint first — do not change while the page is open, and
|
|
18
|
+
* plain modules (`api()`, `iam()`, `site()`, the plan reads) call them outside
|
|
19
|
+
* any component and on pages the rooms never draw. So the host states them once
|
|
20
|
+
* with `configure()`, in a module its root imports, before anything renders.
|
|
21
|
+
*
|
|
22
|
+
* The ROUTER, the query and the route change as the page moves, so they ride
|
|
23
|
+
* React context, and a room reads them with `useRooms()`.
|
|
24
|
+
*/
|
|
25
|
+
import { createContext, useContext } from 'react';
|
|
26
|
+
import { useIam, useOrganizations } from '@hanzo/iam/react';
|
|
27
|
+
import { useAppearance } from '@hanzo/appearance';
|
|
28
|
+
import { where } from './where.js';
|
|
29
|
+
const Plain = ({ prefetch: _prefetch, ...rest }) => _jsx("a", { ...rest });
|
|
30
|
+
const Context = createContext({
|
|
31
|
+
router: {
|
|
32
|
+
push: (href) => window.location.assign(href),
|
|
33
|
+
replace: (href) => window.location.replace(href),
|
|
34
|
+
back: () => window.history.back(),
|
|
35
|
+
forward: () => window.history.forward(),
|
|
36
|
+
},
|
|
37
|
+
search: null,
|
|
38
|
+
route: '/',
|
|
39
|
+
Link: Plain,
|
|
40
|
+
});
|
|
41
|
+
/** The router, the query, the route and the link the host mounted the rooms with. */
|
|
42
|
+
export const useRooms = () => useContext(Context);
|
|
43
|
+
/** The org in scope, by the id the appearance layers are keyed on. */
|
|
44
|
+
export function useOrg() {
|
|
45
|
+
const { currentOrg } = useOrganizations();
|
|
46
|
+
const one = currentOrg;
|
|
47
|
+
return { id: one?.id || one?.name, name: one?.displayName || one?.name };
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The person's appearance — theme, type, spacing, corners, accent — resolved
|
|
51
|
+
* for the org in scope and kept with their IAM account, so a choice made here
|
|
52
|
+
* follows them to every Hanzo origin. Every control that changes how the rooms
|
|
53
|
+
* look goes through this, and only this.
|
|
54
|
+
*/
|
|
55
|
+
export function useLook() {
|
|
56
|
+
const { accessToken } = useIam();
|
|
57
|
+
const org = useOrg();
|
|
58
|
+
// Signed out there is no person to ask about, so IAM is not asked: a stranger
|
|
59
|
+
// passing through a room on the way to sign in sends nothing to the issuer.
|
|
60
|
+
return useAppearance({
|
|
61
|
+
org: org.id,
|
|
62
|
+
account: accessToken ? { base: (where().iam ?? 'https://hanzo.id').replace(/\/+$/, ''), token: accessToken } : undefined,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The look, applied: mounted once at the host's root, inside its IamProvider,
|
|
67
|
+
* so every page — a room or not — opens in the person's theme and accent and
|
|
68
|
+
* keeps their choice in step with IAM.
|
|
69
|
+
*/
|
|
70
|
+
export function Look() {
|
|
71
|
+
useLook();
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
export function Rooms({ router, search = null, route, Link, children }) {
|
|
75
|
+
return _jsx(Context.Provider, { value: { router, search, route, Link }, children: children });
|
|
76
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @hanzo/rooms — the workspace rooms, once, for every Hanzo surface.
|
|
3
|
+
*
|
|
4
|
+
* import { configure, Rooms } from '@hanzo/rooms'
|
|
5
|
+
* import { Room } from '@hanzo/rooms/Room'
|
|
6
|
+
* import { CalScheduler } from '@hanzo/rooms/CalScheduler'
|
|
7
|
+
*
|
|
8
|
+
* The root names what a host passes; each room is its own subpath, so a page
|
|
9
|
+
* loads the rooms it draws and no others.
|
|
10
|
+
*/
|
|
11
|
+
export { configure, where, site } from './where.js';
|
|
12
|
+
export type { Addresses } from './where.js';
|
|
13
|
+
export { Rooms, Look, useRooms, useLook, useOrg } from './host.js';
|
|
14
|
+
export type { Router, Link, RoomsProps } from './host.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @hanzo/rooms — the workspace rooms, once, for every Hanzo surface.
|
|
3
|
+
*
|
|
4
|
+
* import { configure, Rooms } from '@hanzo/rooms'
|
|
5
|
+
* import { Room } from '@hanzo/rooms/Room'
|
|
6
|
+
* import { CalScheduler } from '@hanzo/rooms/CalScheduler'
|
|
7
|
+
*
|
|
8
|
+
* The root names what a host passes; each room is its own subpath, so a page
|
|
9
|
+
* loads the rooms it draws and no others.
|
|
10
|
+
*/
|
|
11
|
+
export { configure, where, site } from './where.js';
|
|
12
|
+
export { Rooms, Look, useRooms, useLook, useOrg } from './host.js';
|
package/dist/kept.d.ts
ADDED
package/dist/kept.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* A value kept in this browser as JSON; storage that throws keeps it in memory.
|
|
5
|
+
* Read in the initializer: the app renders only in the browser (app/_apex.tsx).
|
|
6
|
+
*/
|
|
7
|
+
export function useKept(key, initial) {
|
|
8
|
+
const [value, setValue] = useState(() => {
|
|
9
|
+
try {
|
|
10
|
+
const raw = localStorage.getItem(key);
|
|
11
|
+
return raw === null ? initial : JSON.parse(raw);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return initial;
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
const set = (v) => {
|
|
18
|
+
setValue(v);
|
|
19
|
+
try {
|
|
20
|
+
localStorage.setItem(key, JSON.stringify(v));
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
/* kept for this page only */
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
return [value, set];
|
|
27
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
export interface OrganizationMember {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
email: string;
|
|
6
|
+
role: string;
|
|
7
|
+
avatar?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface Organization {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
/** The reader's role in it as the token's `orgs` claim states it: owner | admin | member. */
|
|
13
|
+
role: string;
|
|
14
|
+
avatar?: string;
|
|
15
|
+
plan?: string;
|
|
16
|
+
memberCount?: number;
|
|
17
|
+
members?: OrganizationMember[];
|
|
18
|
+
description?: string;
|
|
19
|
+
website?: string;
|
|
20
|
+
location?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface User {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
email: string;
|
|
26
|
+
avatar?: string;
|
|
27
|
+
bio?: string;
|
|
28
|
+
location?: string;
|
|
29
|
+
joinedDate?: string;
|
|
30
|
+
website?: string;
|
|
31
|
+
phone?: string;
|
|
32
|
+
}
|
|
33
|
+
interface AccountContextType {
|
|
34
|
+
user: User | null;
|
|
35
|
+
setUser: (user: User) => void;
|
|
36
|
+
organizations: Organization[];
|
|
37
|
+
currentOrganization: Organization | null;
|
|
38
|
+
isLoading: boolean;
|
|
39
|
+
switchOrganization: (orgId: string) => void;
|
|
40
|
+
/** Writes to IAM and resolves once the row is stored. Rejects with the
|
|
41
|
+
* reason where it is not — a caller that reports success does so on this. */
|
|
42
|
+
updateUserProfile: (userData: Partial<User>) => Promise<void>;
|
|
43
|
+
updateOrganization: (orgData: Partial<Organization>) => void;
|
|
44
|
+
}
|
|
45
|
+
export declare const AccountProvider: React.FC<{
|
|
46
|
+
children: ReactNode;
|
|
47
|
+
}>;
|
|
48
|
+
export declare const useAccount: () => AccountContextType;
|
|
49
|
+
export {};
|