@hanzo/rooms 0.1.7 → 0.1.8

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/Billing.js CHANGED
@@ -15,7 +15,8 @@ import { Box, Text, XStack } from '@hanzo/ui';
15
15
  import { useIam } from '@hanzo/iam/react';
16
16
  import { formatCents } from '@hanzo/usage';
17
17
  import { renewal, useSubscription, useTier } from './lib/tier.js';
18
- import { payPage, planName } from './lib/plans.js';
18
+ import { payPage } from './lib/pay.js';
19
+ import { planName } from './lib/plans.js';
19
20
  export function Billing() {
20
21
  const { isAuthenticated } = useIam();
21
22
  const { tier } = useTier(isAuthenticated);
package/dist/Chat.js CHANGED
@@ -60,7 +60,8 @@ import { Share } from "./Share.js";
60
60
  import { useStarred } from "./stars.js";
61
61
  import { useModel } from "./model.js";
62
62
  import { Enso, nameOf, useEffort } from "./enso.js";
63
- import { checkoutUrl, onFree, planName } from './lib/plans.js';
63
+ import { checkoutUrl } from './lib/pay.js';
64
+ import { onFree, planName } from './lib/plans.js';
64
65
  import { Upgrade, useFree } from './Upgrade.js';
65
66
  import { enter, LOGIN } from './lib/destination.js';
66
67
  import { first } from './lib/first.js';
package/dist/Drive.js CHANGED
@@ -6,7 +6,7 @@ import { Box, Button, Text, View, XStack, YStack } from '@hanzo/ui';
6
6
  import { useIam, useOrganizations } from '@hanzo/iam/react';
7
7
  import { useAi } from './lib/ai.js';
8
8
  import { useOpen } from './open.js';
9
- import { checkoutUrl } from './lib/plans.js';
9
+ import { checkoutUrl } from './lib/pay.js';
10
10
  import { BAD, mix } from './lib/mix.js';
11
11
  const blame = (e) => {
12
12
  const text = e instanceof Error ? e.message : String(e ?? '');
package/dist/Me.js CHANGED
@@ -29,7 +29,8 @@ import { createOrg, say } from './lib/org.js';
29
29
  import { useTier } from './lib/tier.js';
30
30
  import { list } from './lib/list.js';
31
31
  import { org as current, orgs, pick, renew, scope, superAdmin } from './lib/session.js';
32
- import { payPage, planName } from './lib/plans.js';
32
+ import { payPage } from './lib/pay.js';
33
+ import { planName } from './lib/plans.js';
33
34
  import { ENTRY } from './lib/host.js';
34
35
  import { SupportPicker } from './Support.js';
35
36
  import { BAD } from './lib/mix.js';
package/dist/Orgs.js CHANGED
@@ -39,7 +39,8 @@ import { api } from './lib/api.js';
39
39
  import { usePersonal, useTier } from './lib/tier.js';
40
40
  import { ORG, PICKED, assumed, hasSession, org, orgs as claimed, pick, renew, scope } from './lib/session.js';
41
41
  import { team as workspace } from './lib/host.js';
42
- import { cartUrl, charge, checkoutUrl, money, priced, usePlan, usePlans } from './lib/plans.js';
42
+ import { checkoutUrl, money } from './lib/pay.js';
43
+ import { cartUrl, charge, priced, usePlan, usePlans } from './lib/plans.js';
43
44
  import { createInvitation, inviteLink } from './lib/invite.js';
44
45
  import { countSignup } from './lib/intent.js';
45
46
  import { BAD, mix } from './lib/mix.js';
package/dist/Settings.js CHANGED
@@ -34,7 +34,8 @@ import { ModelSelector, RESEARCH } from '@hanzo/ui/models';
34
34
  import { UsagePanel } from '@hanzo/usage/panel';
35
35
  import { Catalog } from './Directory.js';
36
36
  import { useModel } from './model.js';
37
- import { payPage, planName } from './lib/plans.js';
37
+ import { payPage } from './lib/pay.js';
38
+ import { planName } from './lib/plans.js';
38
39
  import { api } from './lib/api.js';
39
40
  import { renewal, useSubscription, useTier } from './lib/tier.js';
40
41
  import { sku, spendShown, useLimits } from './lib/limits.js';
package/dist/Shell.js CHANGED
@@ -74,7 +74,7 @@ import { Find } from "./Find.js";
74
74
  import { Account } from "./Account.js";
75
75
  import { ModeMark } from "./ModeMark.js";
76
76
  import { called } from "./team.js";
77
- import { checkoutUrl } from './lib/plans.js';
77
+ import { checkoutUrl } from './lib/pay.js';
78
78
  /** Tabs: the terminals, at their own host. */
79
79
  const TABS = "https://tabs.hanzo.ai/app";
80
80
  /** Where a plan is chosen. `lib/plans` owns the address; this is the door. */
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The pay site's addresses and money as a sentence says it.
3
+ *
4
+ * Kept apart from `plans.ts`, which reads the bundled plan catalogue: a page
5
+ * that only links the pay page or prints a price carries none of it.
6
+ */
7
+ /**
8
+ * Where money changes hands: the checkout, mounted at hanzo.ai/pay so a buyer
9
+ * never leaves the site. It is hanzo-inc/pay, served from the same export
10
+ * pay.hanzo.ai was; that host now redirects here.
11
+ *
12
+ * billing.hanzo.ai has no route at the edge and answers 404, and /billing on
13
+ * this site is the Billing PRODUCT's page — a reader sent there to buy a plan
14
+ * lands on marketing. /pay takes `?plan=`, `?interval=`, `?returnUrl=` and
15
+ * `?org=`, and comes back. Every "add credit" and "billing" link reads this one
16
+ * address. Absolute, because this export also serves cloud.hanzo.ai and
17
+ * hanzo.bot, and the checkout lives on hanzo.ai.
18
+ */
19
+ export declare const BILLING_URL = "https://hanzo.ai/pay";
20
+ /**
21
+ * The checkout address, opened on a plan when one is named, and returning to
22
+ * `back` once the buyer has paid. Without `back` a paid buyer lands on the pay
23
+ * site's receipt with no way into what they bought.
24
+ *
25
+ * ONE writer for this address. It was spelled out in three places — the
26
+ * personal ladder, the business strip and the /account hand-off — and a plan id
27
+ * only selects the card a reader clicked if every writer spells the query the
28
+ * same way.
29
+ */
30
+ export declare function checkoutUrl(id?: string, back?: string): string;
31
+ /**
32
+ * A page on the pay site, for the organization this browser works in.
33
+ *
34
+ * pay charges and reads the ledger it is named, and it can only offer the ones
35
+ * the token lists; which of them this workspace is in is a fact only this site
36
+ * holds. `?org=` carries it across, and pay honours it only while the token
37
+ * offers it. Call it at the moment of leaving: the organization lives in this
38
+ * browser and moves with the switcher.
39
+ */
40
+ export declare function payPage(path?: string): string;
41
+ /** The pay address with its query, written in one place for both callers above. */
42
+ export declare function payUrl(path: string, query: Record<string, string | null | undefined>): string;
43
+ export declare const dollars: (n: number) => string;
44
+ /** Money as a sentence says it: whole dollars bare, anything else to the cent — $20, $16.67. */
45
+ export declare const money: (n: number) => string;
@@ -0,0 +1,59 @@
1
+ /**
2
+ * The pay site's addresses and money as a sentence says it.
3
+ *
4
+ * Kept apart from `plans.ts`, which reads the bundled plan catalogue: a page
5
+ * that only links the pay page or prints a price carries none of it.
6
+ */
7
+ import { org } from "./session.js";
8
+ /**
9
+ * Where money changes hands: the checkout, mounted at hanzo.ai/pay so a buyer
10
+ * never leaves the site. It is hanzo-inc/pay, served from the same export
11
+ * pay.hanzo.ai was; that host now redirects here.
12
+ *
13
+ * billing.hanzo.ai has no route at the edge and answers 404, and /billing on
14
+ * this site is the Billing PRODUCT's page — a reader sent there to buy a plan
15
+ * lands on marketing. /pay takes `?plan=`, `?interval=`, `?returnUrl=` and
16
+ * `?org=`, and comes back. Every "add credit" and "billing" link reads this one
17
+ * address. Absolute, because this export also serves cloud.hanzo.ai and
18
+ * hanzo.bot, and the checkout lives on hanzo.ai.
19
+ */
20
+ export const BILLING_URL = "https://hanzo.ai/pay";
21
+ /**
22
+ * The checkout address, opened on a plan when one is named, and returning to
23
+ * `back` once the buyer has paid. Without `back` a paid buyer lands on the pay
24
+ * site's receipt with no way into what they bought.
25
+ *
26
+ * ONE writer for this address. It was spelled out in three places — the
27
+ * personal ladder, the business strip and the /account hand-off — and a plan id
28
+ * only selects the card a reader clicked if every writer spells the query the
29
+ * same way.
30
+ */
31
+ export function checkoutUrl(id, back) {
32
+ return payUrl(id ? "/cart" : "/", { plan: id, returnUrl: back });
33
+ }
34
+ /**
35
+ * A page on the pay site, for the organization this browser works in.
36
+ *
37
+ * pay charges and reads the ledger it is named, and it can only offer the ones
38
+ * the token lists; which of them this workspace is in is a fact only this site
39
+ * holds. `?org=` carries it across, and pay honours it only while the token
40
+ * offers it. Call it at the moment of leaving: the organization lives in this
41
+ * browser and moves with the switcher.
42
+ */
43
+ export function payPage(path = "/") {
44
+ return payUrl(path, { org: org() });
45
+ }
46
+ /** The pay address with its query, written in one place for both callers above. */
47
+ export function payUrl(path, query) {
48
+ const q = new URLSearchParams();
49
+ for (const [k, v] of Object.entries(query))
50
+ if (v)
51
+ q.set(k, v);
52
+ const s = q.toString();
53
+ if (path === "/" && !s)
54
+ return BILLING_URL;
55
+ return `${BILLING_URL}${path}${s ? `?${s}` : ""}`;
56
+ }
57
+ export const dollars = (n) => `$${n.toFixed(2)}`;
58
+ /** Money as a sentence says it: whole dollars bare, anything else to the cent — $20, $16.67. */
59
+ export const money = (n) => (Number.isInteger(n) ? `$${n.toLocaleString("en-US")}` : dollars(n));
@@ -69,27 +69,6 @@ export interface SubscriptionPlan {
69
69
  checkoutUrl?: string;
70
70
  checkoutId?: string;
71
71
  }
72
- /**
73
- * The checkout address, opened on a plan when one is named, and returning to
74
- * `back` once the buyer has paid. Without `back` a paid buyer lands on the pay
75
- * site's receipt with no way into what they bought.
76
- *
77
- * ONE writer for this address. It was spelled out in three places — the
78
- * personal ladder, the business strip and the /account hand-off — and a plan id
79
- * only selects the card a reader clicked if every writer spells the query the
80
- * same way.
81
- */
82
- export declare function checkoutUrl(id?: string, back?: string): string;
83
- /**
84
- * A page on the pay site, for the organization this browser works in.
85
- *
86
- * pay charges and reads the ledger it is named, and it can only offer the ones
87
- * the token lists; which of them this workspace is in is a fact only this site
88
- * holds. `?org=` carries it across, and pay honours it only while the token
89
- * offers it. Call it at the moment of leaving: the organization lives in this
90
- * browser and moves with the switcher.
91
- */
92
- export declare function payPage(path?: string): string;
93
72
  /**
94
73
  * The checkout a plan's CTA opens.
95
74
  *
@@ -122,6 +101,7 @@ export declare function fallbackPlans(category: string): SubscriptionPlan[];
122
101
  * a reader with no build in between.
123
102
  */
124
103
  export declare function useCatalog(): SubscriptionPlan[];
104
+ /** Dollars as a price is written: two places, always, so a card and a button agree. */
125
105
  /** The row an organization runs on, priced. */
126
106
  export interface OrgPlan {
127
107
  plan: SubscriptionPlan | null;
@@ -156,8 +136,6 @@ export declare function usePlan(category?: string): OrgPlan;
156
136
  export declare function usePlans(category: string): SubscriptionPlan[];
157
137
  /** A row priced the way every surface writes it. */
158
138
  export declare function priced(plan: SubscriptionPlan | null): OrgPlan;
159
- /** Money as a sentence says it: whole dollars bare, anything else to the cent — $20, $16.67. */
160
- export declare const money: (n: number) => string;
161
139
  /**
162
140
  * What one term of a plan charges, in dollars, or null where the catalog sells
163
141
  * no such term. A month is `priceMonthly`. A year is the total the catalog
package/dist/lib/plans.js CHANGED
@@ -33,56 +33,7 @@ import { useEffect, useMemo, useState } from "react";
33
33
  import { subscriptionPlans } from "@hanzo/plans";
34
34
  import { where } from "../where.js";
35
35
  import { api } from "./api.js";
36
- import { org } from "./session.js";
37
- /**
38
- * Where money changes hands: the checkout, mounted at hanzo.ai/pay so a buyer
39
- * never leaves the site. It is hanzo-inc/pay, served from the same export
40
- * pay.hanzo.ai was; that host now redirects here.
41
- *
42
- * billing.hanzo.ai has no route at the edge and answers 404, and /billing on
43
- * this site is the Billing PRODUCT's page — a reader sent there to buy a plan
44
- * lands on marketing. /pay takes `?plan=`, `?interval=`, `?returnUrl=` and
45
- * `?org=`, and comes back. Every "add credit" and "billing" link reads this one
46
- * address. Absolute, because this export also serves cloud.hanzo.ai and
47
- * hanzo.bot, and the checkout lives on hanzo.ai.
48
- */
49
- const BILLING_URL = "https://hanzo.ai/pay";
50
- /**
51
- * The checkout address, opened on a plan when one is named, and returning to
52
- * `back` once the buyer has paid. Without `back` a paid buyer lands on the pay
53
- * site's receipt with no way into what they bought.
54
- *
55
- * ONE writer for this address. It was spelled out in three places — the
56
- * personal ladder, the business strip and the /account hand-off — and a plan id
57
- * only selects the card a reader clicked if every writer spells the query the
58
- * same way.
59
- */
60
- export function checkoutUrl(id, back) {
61
- return payUrl(id ? "/cart" : "/", { plan: id, returnUrl: back });
62
- }
63
- /**
64
- * A page on the pay site, for the organization this browser works in.
65
- *
66
- * pay charges and reads the ledger it is named, and it can only offer the ones
67
- * the token lists; which of them this workspace is in is a fact only this site
68
- * holds. `?org=` carries it across, and pay honours it only while the token
69
- * offers it. Call it at the moment of leaving: the organization lives in this
70
- * browser and moves with the switcher.
71
- */
72
- export function payPage(path = "/") {
73
- return payUrl(path, { org: org() });
74
- }
75
- /** The pay address with its query, written in one place for both callers above. */
76
- function payUrl(path, query) {
77
- const q = new URLSearchParams();
78
- for (const [k, v] of Object.entries(query))
79
- if (v)
80
- q.set(k, v);
81
- const s = q.toString();
82
- if (path === "/" && !s)
83
- return BILLING_URL;
84
- return `${BILLING_URL}${path}${s ? `?${s}` : ""}`;
85
- }
36
+ import { BILLING_URL, checkoutUrl, dollars, money, payUrl } from "./pay.js";
86
37
  /**
87
38
  * The checkout a plan's CTA opens.
88
39
  *
@@ -205,8 +156,6 @@ export function useCatalog() {
205
156
  }, []);
206
157
  return rows;
207
158
  }
208
- /** Dollars as a price is written: two places, always, so a card and a button agree. */
209
- const dollars = (n) => `$${n.toFixed(2)}`;
210
159
  /**
211
160
  * Which plan an organization runs on, and what it costs. A plan is a
212
161
  * subscription with usage limits; it mints no credit, so nothing here says it does.
@@ -242,8 +191,6 @@ export function usePlans(category) {
242
191
  export function priced(plan) {
243
192
  return { plan, price: plan ? dollars(plan.priceMonthly ?? 0) : "—" };
244
193
  }
245
- /** Money as a sentence says it: whole dollars bare, anything else to the cent — $20, $16.67. */
246
- export const money = (n) => (Number.isInteger(n) ? `$${n.toLocaleString("en-US")}` : dollars(n));
247
194
  /**
248
195
  * What one term of a plan charges, in dollars, or null where the catalog sells
249
196
  * no such term. A month is `priceMonthly`. A year is the total the catalog
@@ -275,11 +222,16 @@ export function saving(plan) {
275
222
  return null;
276
223
  return Math.round((1 - year / (12 * month)) * 100);
277
224
  }
278
- /** The models the Free plan runs, as @hanzo/plans states them: `ai.models` on the `free` row. */
279
- const FREE_MODELS = new Set(subscriptionPlans.find((p) => p.id === "free")?.entitlements?.["ai.models"] ?? []);
225
+ /**
226
+ * The models the Free plan runs, as @hanzo/plans states them: `ai.models` on
227
+ * the `free` row. Read on first ask and not at import, so a page that only
228
+ * formats money or names the pay page carries none of the catalogue.
229
+ */
230
+ let freeModels = null;
280
231
  /** Whether the Free plan runs a model: one its row names, or any `:free` route. */
281
232
  export function onFree(model) {
282
- return FREE_MODELS.has(model) || model.endsWith(":free");
233
+ freeModels ??= new Set(subscriptionPlans.find((p) => p.id === "free")?.entitlements?.["ai.models"] ?? []);
234
+ return freeModels.has(model) || model.endsWith(":free");
283
235
  }
284
236
  /**
285
237
  * The catalog's own name for a plan slug — "max-20x" reads as "Max 20x" —
package/dist/lib/tier.js CHANGED
@@ -25,7 +25,7 @@ import { useCallback, useEffect, useState } from 'react';
25
25
  import { api } from './api.js';
26
26
  import { bearer, org, orgs, scope } from './session.js';
27
27
  import { list } from './list.js';
28
- import { money } from './plans.js';
28
+ import { money } from './pay.js';
29
29
  import { date } from './limits.js';
30
30
  /** An error that names the status, for `say()` to turn into a sentence. */
31
31
  const refusal = (status, message) => Object.assign(new Error(message), { status });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzo/rooms",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
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",