@levo-so/site-runtime 0.3.1 → 0.3.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/CollectionField-C-6a1ud4.js +270 -0
- package/{CollectionInput-B1qV4QEH.js → CollectionInput-BJ__qcbk.js} +40 -40
- package/DateTimeWidget-hFjcn3o6.js +255 -0
- package/Dialog-dT7y641z.js +130 -0
- package/KBChatWidget-ClHFDgJ5.js +1026 -0
- package/LevoProvider-Bsjkcwc8.js +20 -0
- package/PhoneWidget-BmBO-kvA.js +99 -0
- package/{Popover-q5dL7y0W.js → Popover-3N88sRp4.js} +20 -20
- package/{PopupRenderer-Bncp54gB-DuCULkBK.js → PopupBody-DZVwDLkg-Cfy3lWGs.js} +201 -910
- package/PopupRenderer-BjW1jg70-W2y-PEPH.js +387 -0
- package/{RichTextWidget-D-mGlES0.js → RichTextWidget-DkKHEq4j.js} +142 -141
- package/ThemeProvider-DutrjSTF.js +116 -0
- package/{Tooltip-BIgrpetu.js → Tooltip-CQB0LyxK.js} +20 -20
- package/VerifyButton-BUT70lgz.js +192 -0
- package/{theme.cssm-2YTdd8Yh.js → createThemeExtension-4AUn51iJ.js} +2 -2
- package/dist-CRDgdAkQ.js +3631 -0
- package/dist-DPmVG7VB.js +79 -0
- package/index.d.ts +575 -3
- package/index.js +1217 -722
- package/inlineBaseTheme-BB9e6h5f.js +9 -0
- package/inlineCollectionTheme-CWcMCUti.js +19 -0
- package/{kbChat-AUJxjURc.js → kbChat-C00LVlxP.js} +53 -48
- package/{nodeAlignment-Cn6xNtOP.js → nodeAlignment-BnJljFlw.js} +13 -13
- package/package.json +9 -9
- package/pillChrome-BAu5AfCT.js +30 -0
- package/popupState-JmpeKzgM-qhNTV79U.js +229 -0
- package/popups.js +1 -1
- package/react-CV3jf2mc.js +74 -0
- package/rteTheme.cssm-xg0gJ28J.js +4 -0
- package/styles.css +1 -1
- package/theme.cssm-DUzmx76l.js +4 -0
- package/{inlineCollectionTheme-D2w17LHX.js → themeVars.cssm-ByhhC2Jm.js} +18 -33
- package/usePopupRedirect-BThP_YPW-COUseDik.js +80 -0
- package/CollectionField-CzS-34zx.js +0 -270
- package/DateTimeWidget-C1jHOtz7.js +0 -255
- package/Dialog-CzVhHLEY.js +0 -145
- package/KBChatWidget-D7F9LRwI.js +0 -1078
- package/PhoneWidget-_nw97rkI.js +0 -99
- package/ThemeProvider-BQmIB5tr.js +0 -116
- package/VerifyButton-BkP98H17.js +0 -191
- package/dist-CJknSbJK.js +0 -80
- package/dist-DBbiX2ST.js +0 -3556
- package/inlineBaseTheme-DS-AfUHi.js +0 -9
- package/pillChrome-AhXOWXIb.js +0 -20
- /package/{es-iCqKQf1c.js → es-CztjLuNy.js} +0 -0
package/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ILemaCollection } from '@levo-so/core';
|
|
2
2
|
import { ILevoClient } from '@levo-so/core';
|
|
3
3
|
import { ILevoInsights } from '@levo-so/insights';
|
|
4
|
+
import { ILevoMembership } from '@levo-so/core';
|
|
4
5
|
import { JSX } from 'react/jsx-runtime';
|
|
5
6
|
import { LevoQuery } from '@levo-so/core';
|
|
6
7
|
|
|
@@ -39,7 +40,7 @@ export declare const ColorModeProvider: React.FC<IColorModeProviderProps>;
|
|
|
39
40
|
export declare const createLevoHead: (site: ISiteJson) => (meta?: IPlatformMetaFile, dynamic?: ILevoDynamicHead) => (ctx?: IHeadCtx) => IComposedHead;
|
|
40
41
|
|
|
41
42
|
/**
|
|
42
|
-
* Build the one-line route loader (`loader: levoLoader(dataSources)`): prefetch the
|
|
43
|
+
* Build the one-line route loader (`loader: levoLoader(dataSources, meta)`): prefetch the
|
|
43
44
|
* page's declared data sources on the server so SSR ships fully-rendered HTML, and
|
|
44
45
|
* return them keyed by source key — that map is the route's `loaderData`, which
|
|
45
46
|
* `levoHead`'s dynamic config reads for per-record heads. An empty `dataSources` ({})
|
|
@@ -48,8 +49,20 @@ export declare const createLevoHead: (site: ISiteJson) => (meta?: IPlatformMetaF
|
|
|
48
49
|
*
|
|
49
50
|
* Takes the raw `site.json` — same single input as `createLevoHead` and
|
|
50
51
|
* `LevoSiteProvider` — and derives the client config itself.
|
|
52
|
+
*
|
|
53
|
+
* GATED PAGES PREFETCH NOTHING. Pass the page's meta file (the same one `levoHead` gets)
|
|
54
|
+
* and a page with enabled `access` rules skips prefetch entirely. The prefetch runs on the
|
|
55
|
+
* SERVER, where the visitor's session cookie isn't available — so it would fetch as an
|
|
56
|
+
* anonymous caller and stream the result into the SSR payload of a page that has not been
|
|
57
|
+
* cleared to show it. Per-collection visibility means a truly private collection returns
|
|
58
|
+
* nothing to that caller, but a members-only page over public content would still have
|
|
59
|
+
* shipped its records to anyone who viewed source. The page's hooks fetch client-side once
|
|
60
|
+
* the gate opens, which is the only point at which we know who is asking.
|
|
61
|
+
*
|
|
62
|
+
* `meta` is optional so sites generated before this shipped keep working unchanged — they
|
|
63
|
+
* simply prefetch as they always did (and have no gates to protect).
|
|
51
64
|
*/
|
|
52
|
-
export declare const createLevoLoader: (site: ISiteJson) => (sources: ILevoDataSources) => ({ context, params, }: {
|
|
65
|
+
export declare const createLevoLoader: (site: ISiteJson) => (sources: ILevoDataSources, meta?: IPlatformMetaFile) => ({ context, params, }: {
|
|
53
66
|
context: {
|
|
54
67
|
queryClient: IQueryClientLike;
|
|
55
68
|
};
|
|
@@ -65,6 +78,66 @@ export declare const createLevoLoader: (site: ISiteJson) => (sources: ILevoDataS
|
|
|
65
78
|
*/
|
|
66
79
|
export declare const createSiteClient: (config?: ILevoSiteConfig) => ILevoClient | null;
|
|
67
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Three layers, cheapest first:
|
|
83
|
+
*
|
|
84
|
+
* 1. NO GATES — granted synchronously, on the server too, with zero network. The path
|
|
85
|
+
* ~every page takes, so an ungated site pays nothing for the gate existing.
|
|
86
|
+
* 2. NOT SIGNED IN — decided locally from the session. Every gate kind implies a login
|
|
87
|
+
* (authentication by definition, profile explicitly, gating because entries are matched
|
|
88
|
+
* by their `_account`), so a signed-out visitor gets the sign-in card immediately rather
|
|
89
|
+
* than after a round-trip that could only have said the same thing.
|
|
90
|
+
* 3. SIGNED IN — the server's verdict. It reads the rules from the page ROW, never from
|
|
91
|
+
* anything the client sends, so collection lookups and profile conditions are evaluated
|
|
92
|
+
* where they can be trusted.
|
|
93
|
+
*/
|
|
94
|
+
export declare const decideAccess: ({ rules, invalid, pageId, hasClient, isReady, isLoggedIn, check, }: IAccessDecisionInput) => IAccessDecision;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* The gate's policy, as a pure function.
|
|
98
|
+
*
|
|
99
|
+
* Split from `useLevoAccess` on purpose: this is the most safety-critical logic in the
|
|
100
|
+
* feature — it decides whether a page renders — and as a hook it could only ever be
|
|
101
|
+
* exercised through React. Here it is a table of inputs to a verdict, readable top to bottom
|
|
102
|
+
* and testable without a renderer. The hook's remaining job is gathering the inputs.
|
|
103
|
+
*
|
|
104
|
+
* FAIL CLOSED. Every path that cannot produce a definite "yes" resolves to `blocked`. A
|
|
105
|
+
* gated page never falls open because something upstream was having a bad minute.
|
|
106
|
+
*/
|
|
107
|
+
/** What the check-access endpoint returns. */
|
|
108
|
+
export declare interface IAccessCheckResponse {
|
|
109
|
+
has_access: boolean;
|
|
110
|
+
code?: ILevoAccessServerCode;
|
|
111
|
+
message?: string;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export declare interface IAccessDecision {
|
|
115
|
+
state: ILevoAccessState;
|
|
116
|
+
code: ILevoAccessCode | null;
|
|
117
|
+
message: string | null;
|
|
118
|
+
rule: ILevoAccessRule | null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export declare interface IAccessDecisionInput {
|
|
122
|
+
/** Enabled, parseable rules on this page. Empty = ungated. */
|
|
123
|
+
rules: ILevoAccessRule[];
|
|
124
|
+
/** The page declared rules, but none of them parsed. */
|
|
125
|
+
invalid: boolean;
|
|
126
|
+
/** The platform page id from the meta file; `""` when unstamped. */
|
|
127
|
+
pageId: string;
|
|
128
|
+
/** The site is wired to a Levo backend. */
|
|
129
|
+
hasClient: boolean;
|
|
130
|
+
/** Hydrated AND the session question has been answered. False = undecided. */
|
|
131
|
+
isReady: boolean;
|
|
132
|
+
isLoggedIn: boolean;
|
|
133
|
+
/** The server check, passed through from the query. */
|
|
134
|
+
check: {
|
|
135
|
+
isError: boolean;
|
|
136
|
+
isSuccess: boolean;
|
|
137
|
+
data: IAccessCheckResponse | null;
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
68
141
|
export declare interface IColorModeProviderProps {
|
|
69
142
|
children: React.ReactNode;
|
|
70
143
|
/** Fallback when nothing is stored yet. */
|
|
@@ -191,11 +264,191 @@ export declare interface ILayersNode {
|
|
|
191
264
|
children: ILayersNode[];
|
|
192
265
|
}
|
|
193
266
|
|
|
267
|
+
/**
|
|
268
|
+
* `kind: "authentication"` — the visitor must be signed in, via one of `methods`.
|
|
269
|
+
* `primary_method` picks which passwordless form the login card leads with; the OAuth
|
|
270
|
+
* entries in `methods` become the buttons above it.
|
|
271
|
+
*/
|
|
272
|
+
export declare interface ILevoAccessAuthenticationOptions {
|
|
273
|
+
methods?: ILevoAuthMethod[];
|
|
274
|
+
primary_method?: ILevoPrimaryAuthMethod;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export declare type ILevoAccessCode = ILevoAccessServerCode | ILevoAccessRuntimeCode;
|
|
278
|
+
|
|
279
|
+
/** The `access` array in a page's `meta/<route>.json`. Every enabled rule must pass. */
|
|
280
|
+
export declare type ILevoAccessConfig = ILevoAccessRule[];
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* `kind: "gating"` — the visitor must own an entry in `collection` that satisfies
|
|
284
|
+
* `condition`. Ownership is by the entry's `_account`, so this is always login-implying.
|
|
285
|
+
* No entry → the site shows its entry form; entry that fails the condition → the
|
|
286
|
+
* "under review" message.
|
|
287
|
+
*/
|
|
288
|
+
export declare interface ILevoAccessGatingOptions {
|
|
289
|
+
/** Collection key the visitor's entry must live in. */
|
|
290
|
+
collection: string;
|
|
291
|
+
/** LevoQuery `where` the entry must satisfy. Absent/empty = any entry passes. */
|
|
292
|
+
condition?: LevoQuery.Where;
|
|
293
|
+
/** Field keys hidden in the entry form the site renders when no entry exists. */
|
|
294
|
+
hidden?: string[];
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* `kind: "profile"` — account access: signed in AND the visitor's OWN membership account
|
|
299
|
+
* satisfies `condition`. There is no collection here (the membership account is resolved
|
|
300
|
+
* server-side); failing accounts get the profile-completion form.
|
|
301
|
+
*/
|
|
302
|
+
export declare interface ILevoAccessProfileOptions {
|
|
303
|
+
/** "Profile is complete when" — a LevoQuery `where` over the account. Empty = always passes. */
|
|
304
|
+
condition?: LevoQuery.Where;
|
|
305
|
+
/** Extra account field keys to hide in the profile-completion form. */
|
|
306
|
+
hidden?: string[];
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** What `useLevoAccess` hands a page. */
|
|
310
|
+
export declare interface ILevoAccessResult {
|
|
311
|
+
state: ILevoAccessState;
|
|
312
|
+
/** Null only while `checking` (and on a page with no gates). */
|
|
313
|
+
code: ILevoAccessCode | null;
|
|
314
|
+
/** The server's human-readable reason, when it produced one. Cards may use it as a fallback. */
|
|
315
|
+
message: string | null;
|
|
316
|
+
/** The rule that blocked — the card reads its `options` (collection, hidden fields, …). */
|
|
317
|
+
rule: ILevoAccessRule | null;
|
|
318
|
+
/** Login methods for the sign-in card, resolved from this page's config. */
|
|
319
|
+
authMethods: ILevoAuthMethods;
|
|
320
|
+
/** Re-run the gate — pass as `onSuccess` to any card that can change the outcome. */
|
|
321
|
+
recheck: () => void;
|
|
322
|
+
/** A `recheck()` (or the very first check) is in flight. */
|
|
323
|
+
isChecking: boolean;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* One gate. `enabled` defaults to true when the key is absent — an author writing a rule
|
|
328
|
+
* down means it should apply; only an explicit `false` parks it.
|
|
329
|
+
*/
|
|
330
|
+
export declare type ILevoAccessRule = {
|
|
331
|
+
kind: "authentication";
|
|
332
|
+
enabled?: boolean;
|
|
333
|
+
options?: ILevoAccessAuthenticationOptions;
|
|
334
|
+
} | {
|
|
335
|
+
kind: "gating";
|
|
336
|
+
enabled?: boolean;
|
|
337
|
+
options: ILevoAccessGatingOptions;
|
|
338
|
+
} | {
|
|
339
|
+
kind: "profile";
|
|
340
|
+
enabled?: boolean;
|
|
341
|
+
options?: ILevoAccessProfileOptions;
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Codes the RUNTIME raises without asking the server. Namespaced `access.*` so they can
|
|
346
|
+
* never collide with a server code, present or future.
|
|
347
|
+
*
|
|
348
|
+
* - `CONFIG_INVALID` — the page has an `access` array we could not parse into a single
|
|
349
|
+
* valid rule. Fail-closed: a typo in hand-edited JSON must not silently un-gate a page.
|
|
350
|
+
* - `PAGE_NOT_IDENTIFIED` — the meta file carries no platform `id`, so there is nothing to
|
|
351
|
+
* ask the server about (a page whose row hasn't been stamped yet).
|
|
352
|
+
* - `UNWIRED` — the site has no Levo backend at all (`site.json` without `api_url`).
|
|
353
|
+
* - `CHECK_FAILED` — the check-access call itself failed (network, 5xx).
|
|
354
|
+
*/
|
|
355
|
+
export declare type ILevoAccessRuntimeCode = "access.CONFIG_INVALID" | "access.PAGE_NOT_IDENTIFIED" | "access.UNWIRED" | "access.CHECK_FAILED";
|
|
356
|
+
|
|
357
|
+
/** Codes returned by the server's check-access evaluation. */
|
|
358
|
+
export declare type ILevoAccessServerCode = "authentication.NOT_CONFIGURED" | "authentication.NOT_LOGGED_IN" | "authentication.SUCCESS" | "gating.NOT_CONFIGURED" | "gating.IDENTIFIER_NOT_FOUND" | "gating.ENTRY_NOT_FOUND" | "gating.ENTRY_CONDITION_NOT_FULFILLED" | "gating.SUCCESS" | "profile.NOT_LOGGED_IN" | "profile.CONDITION_NOT_FULFILLED" | "profile.SUCCESS";
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* The gate: reads a page's own `meta/<route>.json` and answers whether this visitor may see
|
|
362
|
+
* this page. The page hands the result to whichever card matches the code — this renders
|
|
363
|
+
* nothing itself.
|
|
364
|
+
*
|
|
365
|
+
* This hook only GATHERS (session, config, server check); the verdict is `decideAccess`, a
|
|
366
|
+
* pure function next door. Keeping them apart is what makes the policy readable and testable
|
|
367
|
+
* on its own.
|
|
368
|
+
*/
|
|
369
|
+
/**
|
|
370
|
+
* The page identity + gates this hook needs. A route's imported `meta/<route>.json`
|
|
371
|
+
* satisfies it as-is — `access` is typed `unknown` on purpose, because a JSON import widens
|
|
372
|
+
* string literals (`kind: string`, not `kind: "gating"`) and would never structurally match
|
|
373
|
+
* the rule union. Validation happens at runtime in `parseAccess`, which is where a
|
|
374
|
+
* hand-edited file has to be checked anyway.
|
|
375
|
+
*/
|
|
376
|
+
export declare interface ILevoAccessSource {
|
|
377
|
+
/** The platform page id, stamped into the meta file. Empty on a page whose row is unstamped. */
|
|
378
|
+
id?: string;
|
|
379
|
+
/** The page's `access` array, straight from the meta file. */
|
|
380
|
+
access?: unknown;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Where the gate currently stands.
|
|
385
|
+
*
|
|
386
|
+
* - `checking` — undecided. Always the state during SSR and the first client frame for a
|
|
387
|
+
* gated page, which is what keeps gated content out of the server-rendered HTML.
|
|
388
|
+
* - `granted` — render the page.
|
|
389
|
+
* - `blocked` — render the card for `code`.
|
|
390
|
+
*
|
|
391
|
+
* There is no fourth "errored" state on purpose: every way a check can fail resolves to
|
|
392
|
+
* `blocked` with an `access.*` code, so a caller that handles the three states handles
|
|
393
|
+
* everything.
|
|
394
|
+
*/
|
|
395
|
+
export declare type ILevoAccessState = "checking" | "granted" | "blocked";
|
|
396
|
+
|
|
397
|
+
export declare type ILevoAuthMethod = ILevoPrimaryAuthMethod | ILevoOAuthMethod;
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* The login methods a card should offer, resolved from the page's OWN config (never from
|
|
401
|
+
* the server response) so the card renders identically whether the block was decided
|
|
402
|
+
* locally or server-side.
|
|
403
|
+
*/
|
|
404
|
+
export declare interface ILevoAuthMethods {
|
|
405
|
+
/** The passwordless form to lead with. Falls back to `otp` when a page configures none. */
|
|
406
|
+
primary: ILevoPrimaryAuthMethod;
|
|
407
|
+
/** OAuth providers to offer above the primary form. Empty when none are configured. */
|
|
408
|
+
oauth: ILevoOAuthMethod[];
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
export declare interface ILevoAuthState {
|
|
412
|
+
/** The signed-in membership account, or null. */
|
|
413
|
+
account: ILevoMembership.Account | null;
|
|
414
|
+
isLoggedIn: boolean;
|
|
415
|
+
/**
|
|
416
|
+
* The session question has been answered. False during SSR, the first client frame, and
|
|
417
|
+
* while the first `getMe()` is in flight — treat it as "don't know yet", never as
|
|
418
|
+
* "signed out".
|
|
419
|
+
*/
|
|
420
|
+
isLoaded: boolean;
|
|
421
|
+
/** A session request is in flight (first load or a refresh). */
|
|
422
|
+
isLoading: boolean;
|
|
423
|
+
/** Re-read the session — call after any sign-in that happened outside this hook. */
|
|
424
|
+
refresh: () => Promise<void>;
|
|
425
|
+
signOut: () => Promise<void>;
|
|
426
|
+
isSigningOut: boolean;
|
|
427
|
+
}
|
|
428
|
+
|
|
194
429
|
export declare interface ILevoChatProps {
|
|
195
430
|
/** The site's root `site.json` — all chat props are derived from it. */
|
|
196
431
|
site: ISiteJson;
|
|
432
|
+
/**
|
|
433
|
+
* The visitor's current URL path, sourced from TanStack Router in
|
|
434
|
+
* `LevoSiteProvider` (`useRouterState` → `state.location.pathname`). Forwarded
|
|
435
|
+
* to the widget's boot call so a multi-agent v3 site resolves the agent bound
|
|
436
|
+
* to this path, and RE-resolves it when the path changes on client navigation
|
|
437
|
+
* — the launcher mounts once at `__root` and never remounts across route
|
|
438
|
+
* changes, so this prop is the only signal that the URL moved. A v3 site is
|
|
439
|
+
* code-routed (no `[visitor]/[workspace]` rewrite), so the router pathname is
|
|
440
|
+
* already the visitor-facing URL. Omitted → the BE treats the path as "/" and
|
|
441
|
+
* the whole-site catch-all agent answers.
|
|
442
|
+
*
|
|
443
|
+
* Example: land on /pricing → path="/pricing" → Sales. Client-navigate to
|
|
444
|
+
* /help → path="/help" → Support. One mount, agent swapped.
|
|
445
|
+
*/
|
|
446
|
+
path?: string;
|
|
197
447
|
}
|
|
198
448
|
|
|
449
|
+
/** How the verification code reaches the visitor. */
|
|
450
|
+
export declare type ILevoCodeMedium = "email" | "whatsapp";
|
|
451
|
+
|
|
199
452
|
/** The shape a page exports so its route loader can prefetch every binding it renders. */
|
|
200
453
|
export declare type ILevoDataSources = Record<string, ILevoSourceDef>;
|
|
201
454
|
|
|
@@ -217,6 +470,19 @@ export declare interface ILevoDynamicHead {
|
|
|
217
470
|
image?: string;
|
|
218
471
|
}
|
|
219
472
|
|
|
473
|
+
export declare interface ILevoEntryFormProps {
|
|
474
|
+
/** The gated collection's key — take it from the blocking rule's `options.collection`. */
|
|
475
|
+
collection: string;
|
|
476
|
+
/** Field keys to hide — the rule's `options.hidden`. */
|
|
477
|
+
hidden?: string[];
|
|
478
|
+
submitLabel?: string;
|
|
479
|
+
/** Called once the entry is saved. Wire it to the gate's `recheck` so the page re-evaluates. */
|
|
480
|
+
onSuccess?: () => void;
|
|
481
|
+
/** Per-form color/radius overrides. Rarely needed — the form already follows the site theme. */
|
|
482
|
+
theme?: ILevoFormTheme;
|
|
483
|
+
className?: string;
|
|
484
|
+
}
|
|
485
|
+
|
|
220
486
|
/**
|
|
221
487
|
* A form binding — the fields + submit for a collection. `LevoForm` renders it (the schema
|
|
222
488
|
* drives which inputs appear); submissions go to the collection. Forms only bind to
|
|
@@ -263,12 +529,18 @@ export declare interface ILevoFormResult {
|
|
|
263
529
|
};
|
|
264
530
|
}
|
|
265
531
|
|
|
532
|
+
/**
|
|
533
|
+
* The bridge between the collection form renderer's color contract and the generated site's
|
|
534
|
+
* semantic theme tokens. Shared by every form the runtime renders — the page's `<LevoForm>`,
|
|
535
|
+
* and the access cards' entry + profile forms — so a `theme.css` edit re-skins all of them
|
|
536
|
+
* together and none of them can drift into looking like a different product.
|
|
537
|
+
*/
|
|
266
538
|
/**
|
|
267
539
|
* Per-form color/radius overrides. Every value is any CSS color/length — pass a site token
|
|
268
540
|
* (`"var(--color-brand)"`) or a literal (`"#0ea5e9"`). Omitted keys fall through to the site
|
|
269
541
|
* theme (see `DEFAULT_FORM_TOKENS`), so a form auto-matches the brand without any theme prop.
|
|
270
542
|
*/
|
|
271
|
-
declare interface ILevoFormTheme {
|
|
543
|
+
export declare interface ILevoFormTheme {
|
|
272
544
|
colors?: Partial<{
|
|
273
545
|
/** Buttons, focus accents. */
|
|
274
546
|
primary: string;
|
|
@@ -291,6 +563,120 @@ declare interface ILevoFormTheme {
|
|
|
291
563
|
gap?: string;
|
|
292
564
|
}
|
|
293
565
|
|
|
566
|
+
export declare interface ILevoLoginActions {
|
|
567
|
+
/**
|
|
568
|
+
* Send a verification code. `identifier` is the email address (medium `"email"`) or the
|
|
569
|
+
* E.164 phone number (medium `"whatsapp"`) — normalize it with `normalizePhone` first.
|
|
570
|
+
*/
|
|
571
|
+
sendCode: (params: {
|
|
572
|
+
identifier: string;
|
|
573
|
+
medium?: ILevoCodeMedium;
|
|
574
|
+
}) => Promise<ILevoLoginOutcome>;
|
|
575
|
+
/** Same call as `sendCode`; separate so a form can show "Resending…" without touching the send button. */
|
|
576
|
+
resendCode: (params: {
|
|
577
|
+
identifier: string;
|
|
578
|
+
medium?: ILevoCodeMedium;
|
|
579
|
+
}) => Promise<ILevoLoginOutcome>;
|
|
580
|
+
/** Exchange the code for a session. On success the shared session cache updates immediately. */
|
|
581
|
+
verifyCode: (params: {
|
|
582
|
+
identifier: string;
|
|
583
|
+
code: string;
|
|
584
|
+
}) => Promise<ILevoLoginOutcome<ILevoMembership.Account | null>>;
|
|
585
|
+
/** Email a magic link back to the current URL. */
|
|
586
|
+
sendMagicLink: (email: string) => Promise<ILevoLoginOutcome>;
|
|
587
|
+
isSendingCode: boolean;
|
|
588
|
+
isResendingCode: boolean;
|
|
589
|
+
isVerifying: boolean;
|
|
590
|
+
isSendingMagicLink: boolean;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/** A failed action, flattened to what a form can render without knowing about LevoError. */
|
|
594
|
+
export declare interface ILevoLoginError {
|
|
595
|
+
code: string;
|
|
596
|
+
title: string;
|
|
597
|
+
message: string;
|
|
598
|
+
/** Per-field validation messages, keyed by field name. Empty when the error isn't a validation one. */
|
|
599
|
+
fieldErrors: Record<string, string>;
|
|
600
|
+
/** True when the visitor's account is awaiting approval — show the pending screen, not an error. */
|
|
601
|
+
isPendingApproval: boolean;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
export declare type ILevoLoginOutcome<T = void> = {
|
|
605
|
+
ok: true;
|
|
606
|
+
data: T;
|
|
607
|
+
} | {
|
|
608
|
+
ok: false;
|
|
609
|
+
error: ILevoLoginError;
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
export declare interface ILevoOAuthHandle {
|
|
613
|
+
provider: ILevoOAuthMethod;
|
|
614
|
+
/** Opens the provider's popup. Must be called straight from a click — browsers block otherwise. */
|
|
615
|
+
signIn: () => void;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
export declare type ILevoOAuthMethod = (typeof LEVO_OAUTH_METHODS)[number];
|
|
619
|
+
|
|
620
|
+
export declare interface ILevoOAuthState {
|
|
621
|
+
/**
|
|
622
|
+
* One handle per provider that is BOTH configured on the page and enabled in the
|
|
623
|
+
* workspace. Empty while the URLs load, so buttons appear only once they can work.
|
|
624
|
+
*/
|
|
625
|
+
providers: ILevoOAuthHandle[];
|
|
626
|
+
isLoading: boolean;
|
|
627
|
+
/** The provider whose popup is open, if any — for a per-button spinner. */
|
|
628
|
+
pendingProvider: ILevoOAuthMethod | null;
|
|
629
|
+
/** Last failure (loading the URLs, or the provider rejecting the sign-in). */
|
|
630
|
+
error: ILevoLoginError | null;
|
|
631
|
+
clearError: () => void;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
export declare interface ILevoOtpInputState {
|
|
635
|
+
slots: ILevoOtpSlot[];
|
|
636
|
+
/** Spread onto the element wrapping the boxes — announces them as one field. */
|
|
637
|
+
containerProps: {
|
|
638
|
+
role: "group";
|
|
639
|
+
"aria-label": string;
|
|
640
|
+
};
|
|
641
|
+
/** Clear every box and return focus to the first — for a "wrong code, try again" reset. */
|
|
642
|
+
clear: () => void;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* A segmented verification-code input, minus the markup.
|
|
647
|
+
*
|
|
648
|
+
* The site owns how the boxes LOOK; this owns how they BEHAVE — and the behaviour is where
|
|
649
|
+
* these go wrong. Auto-advance, backspace stepping back, arrow keys, paste, and the browser
|
|
650
|
+
* dropping an entire autofilled code into the first box are five separate bugs waiting to
|
|
651
|
+
* happen, and none of them are visible when you restyle a box. So they live here, where a
|
|
652
|
+
* design change can't reach them.
|
|
653
|
+
*
|
|
654
|
+
* The value is always LEFT-PACKED: `"12"` means boxes 1–2 are filled and 3–4 are empty, and
|
|
655
|
+
* there is no way to represent a gap. Focusing a box beyond the end snaps back to the first
|
|
656
|
+
* empty one, which is what keeps that invariant true no matter where the visitor clicks.
|
|
657
|
+
*/
|
|
658
|
+
export declare interface ILevoOtpSlot {
|
|
659
|
+
/** The digit in this box, or `""`. */
|
|
660
|
+
char: string;
|
|
661
|
+
/** This box has focus — for a ring or a caret bar. */
|
|
662
|
+
isActive: boolean;
|
|
663
|
+
/** Spread onto the box's `<input>`. Includes the ref, so don't set your own. */
|
|
664
|
+
inputProps: {
|
|
665
|
+
ref: (element: HTMLInputElement | null) => void;
|
|
666
|
+
value: string;
|
|
667
|
+
inputMode: "numeric";
|
|
668
|
+
autoComplete: "one-time-code" | "off";
|
|
669
|
+
type: "text";
|
|
670
|
+
"aria-label": string;
|
|
671
|
+
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
672
|
+
onKeyDown: (event: React.KeyboardEvent<HTMLInputElement>) => void;
|
|
673
|
+
onPaste: (event: React.ClipboardEvent<HTMLInputElement>) => void;
|
|
674
|
+
onFocus: () => void;
|
|
675
|
+
onBlur: () => void;
|
|
676
|
+
disabled?: boolean;
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
|
|
294
680
|
export declare interface ILevoPopupsProps {
|
|
295
681
|
/**
|
|
296
682
|
* The site's id (`site.json` `id`) — scopes the active-popups fetch. Absent → the
|
|
@@ -305,6 +691,21 @@ export declare interface ILevoPopupsProps {
|
|
|
305
691
|
pageId?: string;
|
|
306
692
|
}
|
|
307
693
|
|
|
694
|
+
export declare type ILevoPrimaryAuthMethod = (typeof LEVO_PRIMARY_AUTH_METHODS)[number];
|
|
695
|
+
|
|
696
|
+
export declare interface ILevoProfileFormProps {
|
|
697
|
+
/** Extra account field keys to hide — the blocking rule's `options.hidden`. */
|
|
698
|
+
hidden?: string[];
|
|
699
|
+
submitLabel?: string;
|
|
700
|
+
/** Called after the account updates. Wire it to the gate's `recheck`. */
|
|
701
|
+
onSuccess?: () => void;
|
|
702
|
+
/** Class for the inline submit-error line. Defaults to the theme's danger color. */
|
|
703
|
+
errorClassName?: string;
|
|
704
|
+
/** Per-form color/radius overrides. Rarely needed — the form already follows the site theme. */
|
|
705
|
+
theme?: ILevoFormTheme;
|
|
706
|
+
className?: string;
|
|
707
|
+
}
|
|
708
|
+
|
|
308
709
|
/** A single-record binding — one collection record / blog post / event by `slug` (a detail page). */
|
|
309
710
|
export declare interface ILevoRecordConfig {
|
|
310
711
|
module: "collection" | "blog" | "event";
|
|
@@ -435,6 +836,18 @@ export declare interface IPageSource {
|
|
|
435
836
|
label: string;
|
|
436
837
|
}
|
|
437
838
|
|
|
839
|
+
/** What `parseAccess` decided about a page's `access` block. */
|
|
840
|
+
export declare interface IParsedAccess {
|
|
841
|
+
/** Every enabled, usable rule. Empty when the page is ungated. */
|
|
842
|
+
rules: ILevoAccessRule[];
|
|
843
|
+
/**
|
|
844
|
+
* True when `access` held entries but not one of them parsed — a malformed block.
|
|
845
|
+
* The gate treats this as BLOCKED, never as ungated: silently serving a page whose
|
|
846
|
+
* author wrote a gate for it is the one failure mode worth being loud about.
|
|
847
|
+
*/
|
|
848
|
+
invalid: boolean;
|
|
849
|
+
}
|
|
850
|
+
|
|
438
851
|
export declare interface IPatchedHistoryFn {
|
|
439
852
|
(this: History, ...args: Parameters<IHistoryFn>): ReturnType<IHistoryFn>;
|
|
440
853
|
__inspectorPatched?: boolean;
|
|
@@ -453,6 +866,16 @@ export declare interface IPlatformMetaFile {
|
|
|
453
866
|
title?: string;
|
|
454
867
|
description?: string;
|
|
455
868
|
meta?: IPlatformPageMeta;
|
|
869
|
+
/**
|
|
870
|
+
* The page's access gates — see `./access/types`. FILE-owned like `meta`: the AI writes
|
|
871
|
+
* it, and the platform mirrors it into the page row, which is what the server evaluates.
|
|
872
|
+
*
|
|
873
|
+
* Typed `unknown` deliberately. A JSON import widens string literals (`kind: string`, not
|
|
874
|
+
* `kind: "gating"`), so a precise type here would reject every real meta file; the block
|
|
875
|
+
* is validated at runtime by `parseAccess` instead, which is where a hand-edited file has
|
|
876
|
+
* to be checked regardless.
|
|
877
|
+
*/
|
|
878
|
+
access?: unknown;
|
|
456
879
|
}
|
|
457
880
|
|
|
458
881
|
/** The platform's per-page SEO object — the `meta` key of `meta/<route>.json`. */
|
|
@@ -670,6 +1093,14 @@ export declare interface ISiteMeta extends IPageMeta {
|
|
|
670
1093
|
icon?: string;
|
|
671
1094
|
}
|
|
672
1095
|
|
|
1096
|
+
/**
|
|
1097
|
+
* Pending approval is not a failure to show in a red box — it means "your request landed,
|
|
1098
|
+
* a human has to act". The sign-in card swaps to its own screen for it, so every entry
|
|
1099
|
+
* point (OTP, magic link, OAuth) has to recognise it the same way. Matched loosely because
|
|
1100
|
+
* the code has been namespaced differently across services.
|
|
1101
|
+
*/
|
|
1102
|
+
export declare const isPendingApprovalError: (code?: string | null) => boolean;
|
|
1103
|
+
|
|
673
1104
|
export declare type IStagedEntry = IStagedStyleEntry | IStagedTextEntry | IStagedImageEntry;
|
|
674
1105
|
|
|
675
1106
|
declare interface IStagedImageEntry {
|
|
@@ -695,6 +1126,18 @@ export declare interface IStagedTextEntry {
|
|
|
695
1126
|
value: string;
|
|
696
1127
|
}
|
|
697
1128
|
|
|
1129
|
+
/**
|
|
1130
|
+
* Deliberately permissive: `something@something.tld`, no attempt to enumerate valid TLDs or
|
|
1131
|
+
* implement RFC 5322. The address is proven by the visitor receiving the code — the only
|
|
1132
|
+
* job here is catching a typo before we spend a round-trip on it.
|
|
1133
|
+
*/
|
|
1134
|
+
export declare const isValidEmail: (value: string) => boolean;
|
|
1135
|
+
|
|
1136
|
+
export declare const isValidOtp: (value: string) => boolean;
|
|
1137
|
+
|
|
1138
|
+
/** E.164 shape: a country code that can't start with 0, then 7–14 more digits. */
|
|
1139
|
+
export declare const isValidPhone: (value: string) => boolean;
|
|
1140
|
+
|
|
698
1141
|
/** The element-text-changed payload — see `commit`. */
|
|
699
1142
|
export declare interface ITextChangedElement {
|
|
700
1143
|
source: string | null;
|
|
@@ -705,6 +1148,62 @@ export declare interface ITextChangedElement {
|
|
|
705
1148
|
occurrences: number;
|
|
706
1149
|
}
|
|
707
1150
|
|
|
1151
|
+
export declare interface IUseLevoOAuthParams {
|
|
1152
|
+
/** Providers this page offers, from its access config. Anything else is ignored. */
|
|
1153
|
+
methods: ILevoOAuthMethod[];
|
|
1154
|
+
/** Popup window title — usually the site name. */
|
|
1155
|
+
title?: string;
|
|
1156
|
+
/** Fired after a successful sign-in; the session cache is already refreshed by then. */
|
|
1157
|
+
onSuccess?: () => void;
|
|
1158
|
+
/** Fired on failure. Check `error.isPendingApproval` before rendering it as an error. */
|
|
1159
|
+
onError?: (error: ILevoLoginError) => void;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
export declare interface IUseLevoOtpInputParams {
|
|
1163
|
+
value: string;
|
|
1164
|
+
onChange: (value: string) => void;
|
|
1165
|
+
/** Digits in the code. Defaults to the platform's length. */
|
|
1166
|
+
length?: number;
|
|
1167
|
+
/**
|
|
1168
|
+
* Fired the moment the last box fills, with the complete code. Use it to submit — waiting
|
|
1169
|
+
* for a button press after the final digit is a step nobody wants. The code is passed as an
|
|
1170
|
+
* argument because the caller's state hasn't re-rendered yet when this runs.
|
|
1171
|
+
*/
|
|
1172
|
+
onComplete?: (code: string) => void;
|
|
1173
|
+
/** Focus the first box on mount. */
|
|
1174
|
+
autoFocus?: boolean;
|
|
1175
|
+
disabled?: boolean;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
/** Every method a page may list in `options.methods`. */
|
|
1179
|
+
export declare const LEVO_AUTH_METHODS: ILevoAuthMethod[];
|
|
1180
|
+
|
|
1181
|
+
/**
|
|
1182
|
+
* The visitor's session, shared across every component on the page.
|
|
1183
|
+
*
|
|
1184
|
+
* Backed by TanStack Query rather than a provider: the site already mounts a QueryClient
|
|
1185
|
+
* for data sources, so one cache entry gives every card, navbar, and gate the same account
|
|
1186
|
+
* with one request — and any of them can invalidate it after a sign-in.
|
|
1187
|
+
*
|
|
1188
|
+
* CLIENT-ONLY BY CONSTRUCTION. The session lives in a cookie the SSR pass cannot see, so a
|
|
1189
|
+
* server-side `getMe()` would resolve "signed out" for a signed-in visitor and bake that
|
|
1190
|
+
* into the HTML. Gating it on `useMounted` means a gated page renders its `checking` state
|
|
1191
|
+
* on the server — which is also what keeps gated content out of the server-rendered HTML.
|
|
1192
|
+
*/
|
|
1193
|
+
export declare const LEVO_AUTH_QUERY_KEY: readonly ["levo-auth", "session"];
|
|
1194
|
+
|
|
1195
|
+
/** OAuth providers — rendered as buttons ALONGSIDE the primary form, any number of them. */
|
|
1196
|
+
export declare const LEVO_OAUTH_METHODS: readonly ["google", "microsoft", "linkedin"];
|
|
1197
|
+
|
|
1198
|
+
/** Digits in the verification code the platform sends. */
|
|
1199
|
+
export declare const LEVO_OTP_LENGTH = 4;
|
|
1200
|
+
|
|
1201
|
+
/** The error code the platform returns when the account exists but awaits admin approval. */
|
|
1202
|
+
export declare const LEVO_PENDING_APPROVAL_CODE = "membership.account.ACCOUNT_PENDING_APPROVAL";
|
|
1203
|
+
|
|
1204
|
+
/** Passwordless methods — exactly one of these is the login card's PRIMARY form. */
|
|
1205
|
+
export declare const LEVO_PRIMARY_AUTH_METHODS: readonly ["otp", "magiclink", "whatsapp"];
|
|
1206
|
+
|
|
708
1207
|
/**
|
|
709
1208
|
* Drops the site's AI chat widget onto every page, wired from `site.json`. Mounted once
|
|
710
1209
|
* from the scaffold's `__root` (via the `SiteChat` shim) alongside `<Inspector />`. Self-
|
|
@@ -714,6 +1213,22 @@ export declare interface ITextChangedElement {
|
|
|
714
1213
|
*/
|
|
715
1214
|
export declare const LevoChat: React.FC<ILevoChatProps>;
|
|
716
1215
|
|
|
1216
|
+
/**
|
|
1217
|
+
* The "request access" form for a `gating` rule — the collection's own fields, submitted as
|
|
1218
|
+
* an entry owned by the signed-in visitor.
|
|
1219
|
+
*
|
|
1220
|
+
* Ownership is what makes the gate work: the server matches entries by `_account`, so this
|
|
1221
|
+
* form only ever renders for a signed-in visitor and the submission carries their session.
|
|
1222
|
+
* The visitor's email/mobile prefill the schema's designated contact fields, which is both a
|
|
1223
|
+
* convenience and what keeps the entry findable by a human reviewing the collection.
|
|
1224
|
+
*
|
|
1225
|
+
* Distinct from the page-level `<LevoForm>` in one way that matters: the schema is fetched
|
|
1226
|
+
* client-side, because a gated page's route loader never prefetches it — the form only
|
|
1227
|
+
* exists on the blocked path, and prefetching it on every visit would tell the SSR pass
|
|
1228
|
+
* something about a page it is not allowed to render.
|
|
1229
|
+
*/
|
|
1230
|
+
export declare const LevoEntryForm: React.FC<ILevoEntryFormProps>;
|
|
1231
|
+
|
|
717
1232
|
/**
|
|
718
1233
|
* Self-contained event registration widget for generated Studio v3 sites — ticket
|
|
719
1234
|
* selection, coupons, attendee details, payment (Razorpay by default; Stripe Embedded
|
|
@@ -761,6 +1276,20 @@ export declare const LevoForm: React.FC<ILevoFormProps>;
|
|
|
761
1276
|
*/
|
|
762
1277
|
export declare const LevoPopups: React.FC<ILevoPopupsProps>;
|
|
763
1278
|
|
|
1279
|
+
/**
|
|
1280
|
+
* The profile-completion form for a `profile` rule.
|
|
1281
|
+
*
|
|
1282
|
+
* Submits through `membership.updateMe` — it edits the visitor's OWN account, and never
|
|
1283
|
+
* creates a collection entry (that's what `gating` does). Only visible, non-readonly fields
|
|
1284
|
+
* are sent: echoing back the whole form would push system fields and the locked identity
|
|
1285
|
+
* fields through an endpoint that has no reason to receive them.
|
|
1286
|
+
*
|
|
1287
|
+
* Renders its own submit error inline rather than handing it upward, because an error that
|
|
1288
|
+
* depends on a site component remembering to display it is an error that eventually isn't
|
|
1289
|
+
* displayed.
|
|
1290
|
+
*/
|
|
1291
|
+
export declare const LevoProfileForm: React.FC<ILevoProfileFormProps>;
|
|
1292
|
+
|
|
764
1293
|
/**
|
|
765
1294
|
* Mounts the Levo client + insights for a generated site, and the site-wide overlays that
|
|
766
1295
|
* ride on top of it (AI chat + popups). Rendered once from the scaffold's `__root` (via the
|
|
@@ -778,6 +1307,13 @@ export declare const LevoSiteProvider: React.FC<{
|
|
|
778
1307
|
children: React.ReactNode;
|
|
779
1308
|
}>;
|
|
780
1309
|
|
|
1310
|
+
/**
|
|
1311
|
+
* To E.164: strip every separator, keep one leading `+`. `"+91 98765 43210"` and
|
|
1312
|
+
* `"0091-98765-43210"` both normalize to `"+919876543210"` — the format the OTP endpoint
|
|
1313
|
+
* expects, and the one Studio's phone widget emits.
|
|
1314
|
+
*/
|
|
1315
|
+
export declare const normalizePhone: (value: string) => string;
|
|
1316
|
+
|
|
781
1317
|
/** `name` of the head tag carrying the page id. Written by `levoHead`, read by `readPageId`. */
|
|
782
1318
|
export declare const PAGE_ID_META = "levo:page-id";
|
|
783
1319
|
|
|
@@ -806,6 +1342,22 @@ export declare function PageHead({ meta, site }: {
|
|
|
806
1342
|
*/
|
|
807
1343
|
export declare const pageHead: (meta?: IPageMeta, site?: ISiteMeta) => IComposedHead;
|
|
808
1344
|
|
|
1345
|
+
/**
|
|
1346
|
+
* Read a page's `access` block defensively.
|
|
1347
|
+
*
|
|
1348
|
+
* The three outcomes are deliberately distinct:
|
|
1349
|
+
* - absent / `[]` / every rule `enabled: false` → `{rules: [], invalid: false}` = ungated.
|
|
1350
|
+
* All three are an author SAYING "no gate", so the page renders with no network call.
|
|
1351
|
+
* - at least one usable rule → `{rules: [...], invalid: false}` = gated.
|
|
1352
|
+
* - entries present, none usable → `{rules: [], invalid: true}` = blocked.
|
|
1353
|
+
* A typo (`kind: "athentication"`, a gating rule missing its collection) must not read
|
|
1354
|
+
* the same as "no gate" — that would turn one wrong character into a public page.
|
|
1355
|
+
*
|
|
1356
|
+
* Note that a rule explicitly disabled is NOT invalid: it parsed fine, the author just
|
|
1357
|
+
* turned it off. Only entries that fail to parse at all count toward `invalid`.
|
|
1358
|
+
*/
|
|
1359
|
+
export declare const parseAccess: (raw: unknown) => IParsedAccess;
|
|
1360
|
+
|
|
809
1361
|
/**
|
|
810
1362
|
* Tolerant extraction of `<script>` / `<meta>` / `<link>` tags from a raw head snippet.
|
|
811
1363
|
* Unsupported tags are DROPPED (documented v1 limitation) — silently at runtime; the
|
|
@@ -842,6 +1394,16 @@ export declare const prefetchLevoSources: ({ queryClient, config, sources, param
|
|
|
842
1394
|
*/
|
|
843
1395
|
export declare const readPageId: () => string | null;
|
|
844
1396
|
|
|
1397
|
+
/**
|
|
1398
|
+
* The login methods the sign-in card should offer for this page.
|
|
1399
|
+
*
|
|
1400
|
+
* Resolved from the page's own rules rather than the server's response so the card looks
|
|
1401
|
+
* the same whether the block was decided locally (not signed in) or server-side. A page
|
|
1402
|
+
* that gates on `profile` alone still needs a sign-in card — hence the fallback to email
|
|
1403
|
+
* OTP when no authentication rule names any method.
|
|
1404
|
+
*/
|
|
1405
|
+
export declare const resolveAuthMethods: (rules: ILevoAccessConfig) => ILevoAuthMethods;
|
|
1406
|
+
|
|
845
1407
|
/** What `system` resolves to — the class actually on `<html>`. */
|
|
846
1408
|
export declare type ResolvedColorMode = "dark" | "light";
|
|
847
1409
|
|
|
@@ -857,6 +1419,10 @@ export declare const siteConfigFromJson: (site: ISiteJson) => ILevoSiteConfig;
|
|
|
857
1419
|
/** Read/set the current color mode. Throws outside a `<ColorModeProvider>`. */
|
|
858
1420
|
export declare function useColorMode(): IColorModeState;
|
|
859
1421
|
|
|
1422
|
+
export declare const useLevoAccess: (source: ILevoAccessSource) => ILevoAccessResult;
|
|
1423
|
+
|
|
1424
|
+
export declare const useLevoAuth: () => ILevoAuthState;
|
|
1425
|
+
|
|
860
1426
|
/**
|
|
861
1427
|
* Load a collection's SCHEMA so `LevoForm` can render its fields. Like the other hooks the
|
|
862
1428
|
* config is a static literal (the editor binding); it reads the warm cache the route loader
|
|
@@ -868,6 +1434,12 @@ export declare const useLevoForm: (config: ILevoFormConfig) => ILevoFormResult;
|
|
|
868
1434
|
/** The site's insights (analytics/track), or `null` on an unwired site. */
|
|
869
1435
|
export declare const useLevoInsights: () => ILevoInsights | null;
|
|
870
1436
|
|
|
1437
|
+
export declare const useLevoLogin: () => ILevoLoginActions;
|
|
1438
|
+
|
|
1439
|
+
export declare const useLevoOAuth: ({ methods, title, onSuccess, onError, }: IUseLevoOAuthParams) => ILevoOAuthState;
|
|
1440
|
+
|
|
1441
|
+
export declare const useLevoOtpInput: ({ value, onChange, length, onComplete, autoFocus, disabled, }: IUseLevoOtpInputParams) => ILevoOtpInputState;
|
|
1442
|
+
|
|
871
1443
|
/**
|
|
872
1444
|
* Render ONE record by slug — a detail page. `slug` is a RUNTIME arg (the page's route
|
|
873
1445
|
* param), kept OUT of the config literal so the binding stays static and editable. No slug
|