@patientos/website-kit 0.2.1 → 0.2.3

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.
@@ -6,7 +6,7 @@ import {
6
6
  PortalAccountClient,
7
7
  PortalPanelClient,
8
8
  StoreClient
9
- } from "./chunk-EO64UB5F.js";
9
+ } from "./chunk-LHP4RZ3N.js";
10
10
  import {
11
11
  mountIslandsWith
12
12
  } from "./chunk-THMT43MV.js";
package/dist/index.d.ts CHANGED
@@ -2,8 +2,9 @@ export { BPOINT_SCRIPT_ORIGIN, BPOINT_SCRIPT_URL, CONSULT_CHUNK_PATH, THIRD_PART
2
2
  import * as React from 'react';
3
3
  export { ISLAND_ATTR, ISLAND_PROPS_ATTR, Island, IslandProps, IslandRegistry, mountIslandsWith, readIslandProps } from './islands.js';
4
4
  export { ISLANDS, IslandName, mountIslands } from './islands-registry.js';
5
- export { B as BookingBlock, a as BookingBlockMarkerProps, b as BookingBlockProps, c as BookingTypeOption, C as Cart, d as CartMarkerProps, e as CartProps, f as CertificateFunnel, g as CertificateFunnelMarkerProps, h as CertificateFunnelProps, i as Checkout, j as CheckoutMarkerProps, k as CheckoutProps, F as FunnelPublicApi, l as FunnelServiceOption, S as Store, m as StoreMarkerProps, n as StoreProps } from './checkout-block-CrO7OxI9.js';
6
- export { P as PortalAccount, a as PortalAccountMarkerProps, b as PortalAccountProps, c as PortalAccountSurface, d as PortalPanel, e as PortalPanelMarkerProps, f as PortalPanelProps, g as PortalSurface } from './portal-account-CaK1lqSZ.js';
5
+ import { P as PortalClient, W as WhoAmI, a as PortalPrefill, b as PublicClaim } from './portal-account-pI1cWgsT.js';
6
+ export { F as FetchLike, c as PortalAccount, d as PortalAccountMarkerProps, e as PortalAccountProps, f as PortalAccountSurface, g as PortalClientConfig, h as PortalPanel, i as PortalPanelMarkerProps, j as PortalPanelProps, k as PortalResult, l as PortalSurface, m as createPortalClient } from './portal-account-pI1cWgsT.js';
7
+ export { B as BookingBlock, a as BookingBlockMarkerProps, b as BookingBlockProps, c as BookingTypeOption, C as Cart, d as CartMarkerProps, e as CartProps, f as CertificateFunnel, g as CertificateFunnelMarkerProps, h as CertificateFunnelProps, i as Checkout, j as CheckoutMarkerProps, k as CheckoutProps, F as FunnelPublicApi, l as FunnelServiceOption, S as Store, m as StoreMarkerProps, n as StoreProps } from './checkout-block-Cog4H4I4.js';
7
8
  export { PatientSurfaceTheme, patientSurfaceTheme } from './patient-surface-theme.js';
8
9
  export { Rgb, contrastRatio, deriveForeground, parseHexColor, relativeLuminance } from './contrast.js';
9
10
  export { AnswerValue, Answers, ShowWhenCondition, evaluateShowWhen, visibleQuestions } from './show-when.js';
@@ -184,6 +185,30 @@ type FAQProps = {
184
185
  } & React.HTMLAttributes<HTMLDivElement>;
185
186
  declare function FAQ({ items, className, ...rest }: FAQProps): React.ReactElement;
186
187
 
188
+ interface PortalProviderProps {
189
+ client: PortalClient;
190
+ children?: React.ReactNode;
191
+ }
192
+ declare function PortalProvider({ client, children }: PortalProviderProps): React.ReactElement;
193
+ declare function usePortalClient(): PortalClient;
194
+ type PortalSessionStatus = 'loading' | 'anonymous' | 'signedIn';
195
+ interface PortalSession {
196
+ status: PortalSessionStatus;
197
+ who: WhoAmI | null;
198
+ refresh(): Promise<void>;
199
+ requestSignInLink(email: string, redirect?: string): Promise<boolean>;
200
+ prefill(): Promise<PortalPrefill | null>;
201
+ mintClaim(): Promise<PublicClaim | null>;
202
+ }
203
+ /**
204
+ * Session state plus the four patient-identity actions used by kit components.
205
+ *
206
+ * SSR renders the neutral `loading` state. Effects are the only place `whoami` starts:
207
+ * there is no module-scope request and no request during render. Every method catches as
208
+ * a second line of defence even though PortalClient is itself total.
209
+ */
210
+ declare function usePortalSession(): PortalSession;
211
+
187
212
  declare const WEBSITE_KIT_VERSION = "0.1.0";
188
213
 
189
- export { Button, type ButtonProps, type ButtonVariant, Container, type ContainerProps, FAQ, type FAQProps, type FaqItem, Hero, type HeroProps, Hours, type HoursProps, type HoursRow, MapEmbed, type MapEmbedProps, Row, type RowProps, Section, type SectionProps, type Service, ServiceGrid, type ServiceGridProps, Stack, type StackProps, TeamGrid, type TeamGridProps, type TeamMember, ThemeProvider, type ThemeProviderProps, WEBSITE_KIT_VERSION, WebsiteShell, type WebsiteShellProps, type WebsiteTheme, defaultTheme, resolveTheme, themeToCssVars };
214
+ export { Button, type ButtonProps, type ButtonVariant, Container, type ContainerProps, FAQ, type FAQProps, type FaqItem, Hero, type HeroProps, Hours, type HoursProps, type HoursRow, MapEmbed, type MapEmbedProps, PortalClient, PortalPrefill, PortalProvider, type PortalProviderProps, type PortalSession, type PortalSessionStatus, PublicClaim, Row, type RowProps, Section, type SectionProps, type Service, ServiceGrid, type ServiceGridProps, Stack, type StackProps, TeamGrid, type TeamGridProps, type TeamMember, ThemeProvider, type ThemeProviderProps, WEBSITE_KIT_VERSION, WebsiteShell, type WebsiteShellProps, type WebsiteTheme, WhoAmI, defaultTheme, resolveTheme, themeToCssVars, usePortalClient, usePortalSession };
package/dist/index.js CHANGED
@@ -1,16 +1,19 @@
1
1
  import {
2
2
  ISLANDS,
3
3
  mountIslands
4
- } from "./chunk-CRYD7EXD.js";
4
+ } from "./chunk-MTOKBMBG.js";
5
5
  import {
6
6
  PortalAccount,
7
7
  PortalPanel,
8
+ PortalProvider,
8
9
  getAppointmentTypes,
9
10
  getClinic,
10
11
  getPublicApi,
11
12
  getServices,
12
- getThemeTokens
13
- } from "./chunk-EO64UB5F.js";
13
+ getThemeTokens,
14
+ usePortalClient,
15
+ usePortalSession
16
+ } from "./chunk-LHP4RZ3N.js";
14
17
  import {
15
18
  BPOINT_SCRIPT_ORIGIN,
16
19
  BPOINT_SCRIPT_URL,
@@ -30,7 +33,9 @@ import {
30
33
  mountIslandsWith,
31
34
  readIslandProps
32
35
  } from "./chunk-THMT43MV.js";
33
- import "./chunk-BW7YKCKH.js";
36
+ import {
37
+ createPortalClient
38
+ } from "./chunk-BHVDY6SC.js";
34
39
  import {
35
40
  contrastRatio,
36
41
  deriveForeground,
@@ -456,6 +461,7 @@ export {
456
461
  MapEmbed,
457
462
  PortalAccount,
458
463
  PortalPanel,
464
+ PortalProvider,
459
465
  Row,
460
466
  Section,
461
467
  ServiceGrid,
@@ -469,6 +475,7 @@ export {
469
475
  WEBSITE_KIT_VERSION,
470
476
  WebsiteShell,
471
477
  contrastRatio,
478
+ createPortalClient,
472
479
  defaultTheme,
473
480
  deriveForeground,
474
481
  evaluateShowWhen,
@@ -480,5 +487,7 @@ export {
480
487
  relativeLuminance,
481
488
  resolveTheme,
482
489
  themeToCssVars,
490
+ usePortalClient,
491
+ usePortalSession,
483
492
  visibleQuestions
484
493
  };
@@ -1,8 +1,7 @@
1
1
  import * as React from 'react';
2
- import { b as BookingBlockProps, h as CertificateFunnelProps, n as StoreProps, e as CartProps, k as CheckoutProps } from './checkout-block-CrO7OxI9.js';
3
- import { f as PortalPanelProps } from './portal-account-CaK1lqSZ.js';
4
- import { F as FetchLike } from './portal-account.client-CqnsCCiC.js';
5
- export { P as PortalAccountClient } from './portal-account.client-CqnsCCiC.js';
2
+ import { b as BookingBlockProps, h as CertificateFunnelProps, n as StoreProps, e as CartProps, k as CheckoutProps } from './checkout-block-Cog4H4I4.js';
3
+ import { j as PortalPanelProps, F as FetchLike } from './portal-account-pI1cWgsT.js';
4
+ export { P as PortalAccountClient } from './portal-account.client-DPRRmfCJ.js';
6
5
 
7
6
  declare function BookingBlockClient(props: BookingBlockProps): React.ReactElement;
8
7
 
@@ -6,11 +6,11 @@ import {
6
6
  PortalAccountClient,
7
7
  PortalPanelClient,
8
8
  StoreClient
9
- } from "./chunk-EO64UB5F.js";
9
+ } from "./chunk-LHP4RZ3N.js";
10
10
  import "./chunk-ZOF22TJA.js";
11
11
  import "./chunk-QDO3SJWR.js";
12
12
  import "./chunk-THMT43MV.js";
13
- import "./chunk-BW7YKCKH.js";
13
+ import "./chunk-BHVDY6SC.js";
14
14
  import "./chunk-MLKGABMK.js";
15
15
  export {
16
16
  BookingBlockClient,
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  ISLANDS,
3
3
  mountIslands
4
- } from "./chunk-CRYD7EXD.js";
5
- import "./chunk-EO64UB5F.js";
4
+ } from "./chunk-MTOKBMBG.js";
5
+ import "./chunk-LHP4RZ3N.js";
6
6
  import "./chunk-ZOF22TJA.js";
7
7
  import "./chunk-QDO3SJWR.js";
8
8
  import "./chunk-THMT43MV.js";
9
- import "./chunk-BW7YKCKH.js";
9
+ import "./chunk-BHVDY6SC.js";
10
10
  import "./chunk-MLKGABMK.js";
11
11
  export {
12
12
  ISLANDS,
@@ -1,5 +1,80 @@
1
1
  import * as React from 'react';
2
2
 
3
+ /** The injectable browser transport. */
4
+ type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
5
+ interface PortalClientConfig {
6
+ /** The validated app API origin, e.g. https://my.pocketdoc.com.au. */
7
+ apiOrigin?: string | null;
8
+ /** The app origin used only to verify whether relative portal API calls belong here. */
9
+ portalOrigin?: string | null;
10
+ /** Where to send a patient who cannot use the client at all. */
11
+ portalUrl?: string | null;
12
+ /** Injectable for tests. */
13
+ fetchImpl?: FetchLike;
14
+ }
15
+ /** Who the app says is signed in on this origin. */
16
+ type WhoAmI = {
17
+ signedIn: false;
18
+ } | {
19
+ signedIn: true;
20
+ givenName: string;
21
+ familyName: string;
22
+ email: string;
23
+ };
24
+ /** The patient's own details, for prefill. Every field is independently nullable. */
25
+ interface PortalPrefill {
26
+ givenName: string | null;
27
+ familyName: string | null;
28
+ email: string | null;
29
+ phone: string | null;
30
+ dateOfBirth: string | null;
31
+ }
32
+ /** A claim token minted for the signed-in patient's corroborated-identity path. */
33
+ interface PublicClaim {
34
+ contactId: string;
35
+ claimToken: string;
36
+ expiresAt: string;
37
+ }
38
+ /** A portal call is always a value, never a thrown transport failure. */
39
+ type PortalResult<T> = {
40
+ ok: true;
41
+ data: T;
42
+ } | {
43
+ ok: false;
44
+ status: number | null;
45
+ error: string | null;
46
+ body?: unknown;
47
+ };
48
+ interface PortalClient {
49
+ /** Whether this client can honestly offer an inline portal interaction. */
50
+ readonly available: boolean;
51
+ /** The validated app origin, or '' for relative same-origin calls. */
52
+ readonly apiOrigin: string;
53
+ /** The configured outbound fallback, or ''. */
54
+ readonly portalHref: string;
55
+ /** Resolve a constant path against this client's one configured origin. */
56
+ url(path: string): string;
57
+ /** The transport bound when this client was created; injectable for tests. */
58
+ readonly fetch: FetchLike;
59
+ /** Who is signed in; unhealthy/unavailable is indistinguishable from signed out. */
60
+ whoAmI(): Promise<WhoAmI>;
61
+ /** Ask for an oracle-free magic link. */
62
+ requestMagicLink(email: string, redirect?: string): Promise<boolean>;
63
+ /** Read the signed-in patient's details. */
64
+ prefill(): Promise<PortalPrefill | null>;
65
+ /** Mint a public claim only for the signed-in patient. */
66
+ mintPublicClaim(): Promise<PublicClaim | null>;
67
+ /** Current page callback, using the app-side return hop when cross-origin. */
68
+ returnPath(): string;
69
+ /** Back-compat account-surface transport; callers still use constant paths. */
70
+ get<T>(path: string): Promise<PortalResult<T>>;
71
+ /** Back-compat account-surface JSON write; callers still use constant paths. */
72
+ send<T>(path: string, method: 'POST' | 'PUT', body: unknown): Promise<PortalResult<T>>;
73
+ /** Back-compat account-surface body-less delete. */
74
+ delete<T>(path: string): Promise<PortalResult<T>>;
75
+ }
76
+ declare function createPortalClient(config?: PortalClientConfig): PortalClient;
77
+
3
78
  /** Which portal surface this panel shows. */
4
79
  type PortalSurface = 'appointments' | 'documents' | 'orders' | 'profile';
5
80
  /** JSON-safe island configuration. Crosses the build→runtime boundary — see `./islands`. */
@@ -49,6 +124,7 @@ interface PublicApiConfig {
49
124
  turnstileSiteKey?: string;
50
125
  portalUrl?: string;
51
126
  portalOrigin?: string;
127
+ portalApiOrigin?: string;
52
128
  }
53
129
 
54
130
  /**
@@ -130,4 +206,4 @@ type PortalAccountMarkerProps = PortalAccountProps & {
130
206
  */
131
207
  declare function PortalAccount({ surface, portalUrl, bookHref, appointmentsHref, funnelHref, portalApiOrigin, className, }: PortalAccountMarkerProps): React.ReactElement;
132
208
 
133
- export { PortalAccount as P, type PortalAccountMarkerProps as a, type PortalAccountProps as b, type PortalAccountSurface as c, PortalPanel as d, type PortalPanelMarkerProps as e, type PortalPanelProps as f, type PortalSurface as g };
209
+ export { type FetchLike as F, type PortalClient as P, type WhoAmI as W, type PortalPrefill as a, type PublicClaim as b, PortalAccount as c, type PortalAccountMarkerProps as d, type PortalAccountProps as e, type PortalAccountSurface as f, type PortalClientConfig as g, PortalPanel as h, type PortalPanelMarkerProps as i, type PortalPanelProps as j, type PortalResult as k, type PortalSurface as l, createPortalClient as m };
@@ -1,32 +1,5 @@
1
1
  import * as React from 'react';
2
- import { b as PortalAccountProps } from './portal-account-CaK1lqSZ.js';
3
-
4
- /** The injectable fetch. Present so every behaviour here is provable without a DOM. */
5
- type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
6
- /**
7
- * The outcome of one portal call. A VALUE, never a throw.
8
- *
9
- * `status` is the HTTP status when the server answered and refused, and `null` when the
10
- * transport failed or the body was not JSON — the caller needs that distinction because
11
- * a 404 means "the clinic turned this off" (a quiet note) while a transport failure means
12
- * "we cannot answer here" (link out).
13
- */
14
- type PortalResult<T> = {
15
- ok: true;
16
- data: T;
17
- }
18
- /**
19
- * `body` is the parsed error payload when there was one — typed `unknown`, NOT `T`:
20
- * a refusal is not the success shape, and a caller must narrow it before trusting a
21
- * field (see `hasPortalIdentity`). Keeping it off `T` also keeps a failed result
22
- * assignable across surface types, which the callers that pass one through rely on.
23
- */
24
- | {
25
- ok: false;
26
- status: number | null;
27
- error: string | null;
28
- body?: unknown;
29
- };
2
+ import { e as PortalAccountProps, F as FetchLike } from './portal-account-pI1cWgsT.js';
30
3
 
31
4
  type PortalAddress = {
32
5
  id: string;
@@ -166,4 +139,4 @@ type PortalAccountClientProps = PortalAccountProps & {
166
139
  */
167
140
  declare function PortalAccountClient(props: PortalAccountClientProps): React.ReactElement;
168
141
 
169
- export { type FetchLike as F, PortalAccountClient as P, type PortalAppointment as a, type PortalAppointmentsBody as b, type PortalResult as c };
142
+ export { PortalAccountClient as P, type PortalAppointment as a, type PortalAppointmentsBody as b };
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
- import { a as PortalAppointment, F as FetchLike, b as PortalAppointmentsBody, c as PortalResult } from './portal-account.client-CqnsCCiC.js';
3
- import './portal-account-CaK1lqSZ.js';
2
+ import { F as FetchLike, k as PortalResult } from './portal-account-pI1cWgsT.js';
3
+ import { a as PortalAppointment, b as PortalAppointmentsBody } from './portal-account.client-DPRRmfCJ.js';
4
4
 
5
5
  /** One bookable instant, collapsing the practitioners free at the same time. */
6
6
  interface TimeSlot {
@@ -22,7 +22,7 @@ import {
22
22
  releasePortalHold,
23
23
  rescheduleContextTypeId,
24
24
  reschedulePortalAppointmentAndReload
25
- } from "./chunk-BW7YKCKH.js";
25
+ } from "./chunk-BHVDY6SC.js";
26
26
  import "./chunk-MLKGABMK.js";
27
27
  export {
28
28
  AVAILABILITY_FAILED_COPY,
@@ -1372,6 +1372,9 @@ select.sk-identity__input[data-empty] {
1372
1372
  border: 1px solid var(--sk-flow-line, color-mix(in srgb, var(--sk-muted) 30%, transparent));
1373
1373
  border-radius: var(--sk-island-radius);
1374
1374
  }
1375
+ .sk-flow .sk-identity__ramp--failed {
1376
+ color: var(--sk-flow-danger, #b3261e);
1377
+ }
1375
1378
  .sk-identity__confirm {
1376
1379
  padding: calc(var(--sk-space) * 2.5);
1377
1380
  border: 1px solid var(--sk-flow-line, color-mix(in srgb, var(--sk-muted) 30%, transparent));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patientos/website-kit",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "PatientOS clinic website components and patient-facing interactive islands.",
5
5
  "type": "module",
6
6
  "sideEffects": [