@adonis-agora/authkit-server 1.0.0-rc.7 → 1.0.0-rc.9

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/build/host/views/account/apps.edge +1 -5
  3. package/build/host/views/account/extension.edge +77 -0
  4. package/build/host/views/account/mfa.edge +2 -0
  5. package/build/host/views/account/partials/extension_actions.edge +14 -0
  6. package/build/host/views/account/partials/extension_block.edge +197 -0
  7. package/build/host/views/account/partials/extension_value.edge +8 -0
  8. package/build/host/views/account/partials/nav.edge +14 -0
  9. package/build/host/views/account/security.edge +1 -5
  10. package/build/host/views/account/tokens.edge +2 -2
  11. package/build/host/views/partials/styles.edge +1 -1
  12. package/build/index.d.ts +2 -0
  13. package/build/index.js +1 -0
  14. package/build/providers/authkit_server_provider.js +5 -0
  15. package/build/src/account/extension.d.ts +323 -0
  16. package/build/src/account/extension.js +36 -0
  17. package/build/src/account/http.d.ts +71 -0
  18. package/build/src/account/http.js +369 -0
  19. package/build/src/account/mount.d.ts +35 -0
  20. package/build/src/account/mount.js +99 -0
  21. package/build/src/account/registry.d.ts +48 -0
  22. package/build/src/account/registry.js +229 -0
  23. package/build/src/account/runtime.d.ts +277 -0
  24. package/build/src/account/runtime.js +623 -0
  25. package/build/src/audit/audit_sink.d.ts +1 -1
  26. package/build/src/audit/audit_sink.js +4 -0
  27. package/build/src/console_switcher.d.ts +132 -0
  28. package/build/src/console_switcher.js +206 -0
  29. package/build/src/define_config.d.ts +18 -0
  30. package/build/src/define_config.js +4 -0
  31. package/build/src/host/admin_api/dto.d.ts +1 -1
  32. package/build/src/host/admin_console/admin_console_entry.d.ts +14 -0
  33. package/build/src/host/admin_console/admin_console_entry.js +80 -0
  34. package/build/src/host/admin_console/admin_shell_controller.js +8 -0
  35. package/build/src/host/admin_console/console_switcher_controller.d.ts +11 -0
  36. package/build/src/host/admin_console/console_switcher_controller.js +23 -0
  37. package/build/src/host/auth_host_config.d.ts +3 -0
  38. package/build/src/host/i18n.d.ts +36 -0
  39. package/build/src/host/i18n.js +38 -0
  40. package/build/src/host/rate_limit.d.ts +8 -0
  41. package/build/src/host/rate_limit.js +9 -0
  42. package/build/src/host/register_auth_host.d.ts +14 -0
  43. package/build/src/host/register_auth_host.js +140 -29
  44. package/build/src/host/renderers/edge_renderer.js +5 -0
  45. package/build/src/host/renderers/inertia_renderer.js +7 -1
  46. package/build/src/host/screen_props.d.ts +28 -0
  47. package/build/src/host/ui-dist/assets/index-Dq3dJVBv.js +67 -0
  48. package/build/src/host/ui-dist/assets/{index-DTSmD4RU.css → index-WNIyCEPA.css} +1 -1
  49. package/build/src/host/ui-dist/index.html +2 -2
  50. package/build/types.d.ts +3 -1
  51. package/package.json +3 -2
  52. package/build/src/host/ui-dist/assets/index-u0bMxkLg.js +0 -67
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @adonis-agora/authkit-server
2
2
 
3
+ ## 1.0.0-rc.9
4
+
5
+ ### Minor Changes
6
+
7
+ - [#470](https://github.com/DavideCarvalho/adonis-agora-authkit/pull/470) [`d8ee87a`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/d8ee87abd875e8c141cde051023f1035d8274513) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Account console extensions: other packages (and your app) can add pages to `/account/*`.
8
+
9
+ - New subpath `@adonis-agora/authkit-server/account-extension` with the stable contract (`AccountExtension`, blocks, actions) and the `authkit.accountExtensions` registry binding. Contributors register from their provider's `boot()`; AuthKit renders the pages (Edge or your Inertia page) behind the account sign-in, with CSRF, sudo for sensitive actions, a per-account rate limit, and audit of external redirects.
10
+ - Blocks: `notice`, `keyValue`, `list`, `table`, `meter`, `actions`, `link`, `toolPreview` (approve/reject previews) and `component` (a provider's card fields, scripts loaded with the response's CSP nonce, with a link fallback).
11
+ - `accountConsole` in `config/authkit.ts`: one `subject(account, { activeOrg, tenant })` mapping shared by every extension, host overrides to disable, rename or reorder pages, and `loadTimeoutMs`.
12
+ - The account screens share one navigation (`accountNav`) that lists the mounted screens and the extension pages; `AuthHostRouteMap.account.extensions` lists the pages.
13
+ - JSON API: `GET {prefix}/api/extensions`, `GET {prefix}/api/x/:pageId`, `POST {prefix}/api/x/:pageId/actions/:action`.
14
+ - authkit-react: `<AccountExtensionPage>`, `useAccountExtensions()`, the page/action query options and `client.account.extensions.*`.
15
+
16
+ ## 1.0.0-rc.8
17
+
18
+ ### Minor Changes
19
+
20
+ - [#467](https://github.com/DavideCarvalho/adonis-agora-authkit/pull/467) [`65dea93`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/65dea936568e24a450f64834cae8d1e5885dde57) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Admin console: switch between the `@adonis-agora` consoles. The admin console registers itself in the shared `agora.consoles` registry (title "Identity"); the sidebar brand becomes a menu of the other consoles the viewer may open, the Overview page shows them as a "Consoles" grid, and Ctrl/Cmd-K searches users and organizations plus every other console the viewer may open. New routes `GET {prefix}/api/consoles` and `GET {prefix}/api/consoles/search?q=`. `registerAgoraConsole` is exported for consoles you mount yourself, and `isAgoraProbe(ctx)` tells an auditing `authorize` that another console is only checking access (the structural `ctx.agoraProbe` marker). Nothing to configure.
21
+
3
22
  ## 1.0.0-rc.7
4
23
 
5
24
  ### Minor Changes
@@ -17,11 +17,7 @@
17
17
  </form>
18
18
  </div>
19
19
 
20
- <nav class="mb-6 flex gap-4 text-sm font-medium">
21
- <a href="{{ accountPaths?.tokens ?? '/account/tokens' }}" class="text-gray-500 hover:underline">{{ t('account.tokens.title') }}</a>
22
- <a href="{{ accountPaths?.security ?? '/account/security' }}" class="text-gray-500 hover:underline">{{ t('account.security.title') }}</a>
23
- <a href="{{ accountPaths?.apps ?? '/account/apps' }}" class="text-gray-900 underline">{{ t('account.apps.title') }}</a>
24
- </nav>
20
+ @include('authkit::account/partials/nav')
25
21
 
26
22
  @if(revoked)
27
23
  <div class="mb-6 rounded-lg border border-emerald-300 bg-emerald-50 p-4">
@@ -0,0 +1,77 @@
1
+ <!doctype html>
2
+ <html lang="{{ htmlLang ?? 'en' }}"><head><meta charset="utf-8"><title>{{ page.title }}</title>
3
+ @include('authkit::partials/styles')
4
+ @include('authkit::partials/submit_lock')
5
+ </head>
6
+ <body class="min-h-screen bg-gray-100 p-4">
7
+ <div class="mx-auto max-w-2xl" data-account-extension="{{ page.id }}">
8
+ <div class="flex items-center justify-between py-6">
9
+ <div>
10
+ <div class="text-xs font-semibold uppercase tracking-widest text-gray-400">{{ t('common.brand_eyebrow') }}</div>
11
+ <h1 class="text-xl font-semibold text-gray-900">{{ page.title }}</h1>
12
+ </div>
13
+ <form method="POST" action="{{ accountPaths?.logout ?? '/account/logout' }}">
14
+ <input type="hidden" name="_csrf" value="{{ csrfToken }}">
15
+ <button type="submit" class="text-sm text-gray-500 hover:underline">{{ t('account.extension.logout') }}</button>
16
+ </form>
17
+ </div>
18
+
19
+ @include('authkit::account/partials/nav')
20
+
21
+ @if(flash)
22
+ <div class="mb-6 rounded-lg border p-4 {{ flash.tone === 'danger' ? 'border-red-300 bg-red-50' : 'border-emerald-300 bg-emerald-50' }}" role="status">
23
+ <p class="text-sm font-medium {{ flash.tone === 'danger' ? 'text-red-900' : 'text-emerald-900' }}">{{ flash.text }}</p>
24
+ </div>
25
+ @end
26
+
27
+ @if(step)
28
+ {{-- Passo de confirmação de uma action (sem JS). --}}
29
+ <div class="rounded-xl bg-white p-6 shadow-xs ring-1 ring-black/5" data-block="confirm">
30
+ <h2 class="text-base font-semibold text-gray-900">{{ step.title }}</h2>
31
+ @if(step.text)
32
+ <p class="mt-2 text-sm text-gray-600">{{ step.text }}</p>
33
+ @end
34
+ <form method="POST" action="{{ step.href }}" class="mt-4 space-y-4" data-submit-lock>
35
+ <input type="hidden" name="_csrf" value="{{ csrfToken }}">
36
+ @if(step.target)
37
+ <input type="hidden" name="target" value="{{ step.target }}">
38
+ @end
39
+ @each(field in step.fields)
40
+ <label class="block text-sm">
41
+ <span class="font-medium text-gray-700">{{ field.label }}</span>
42
+ @if(field.kind === 'textarea')
43
+ <textarea name="field_{{ field.name }}" rows="3" class="mt-1 block w-full rounded-lg border border-gray-300 px-3 py-2 text-sm" {{ field.required ? 'required' : '' }} {{ field.maxLength ? 'maxlength=' + field.maxLength : '' }}>{{ field.value }}</textarea>
44
+ @elseif(field.kind === 'select')
45
+ <select name="field_{{ field.name }}" class="mt-1 block w-full rounded-lg border border-gray-300 px-3 py-2 text-sm" {{ field.required ? 'required' : '' }}>
46
+ @each(option in field.options)
47
+ <option value="{{ option.value }}">{{ option.label }}</option>
48
+ @end
49
+ </select>
50
+ @else
51
+ <input type="text" name="field_{{ field.name }}" value="{{ field.value }}" class="mt-1 block w-full rounded-lg border border-gray-300 px-3 py-2 text-sm" {{ field.required ? 'required' : '' }} {{ field.maxLength ? 'maxlength=' + field.maxLength : '' }}>
52
+ @end
53
+ </label>
54
+ @end
55
+ <div class="flex items-center gap-3">
56
+ <button type="submit" class="rounded-lg px-4 py-2 text-sm font-semibold text-white {{ step.tone === 'danger' ? 'bg-red-600 hover:bg-red-700' : 'bg-gray-900 hover:bg-gray-800' }}">{{ step.submitLabel }}</button>
57
+ <a href="{{ step.cancelHref }}" class="text-sm text-gray-500 hover:underline">{{ t('account.extension.cancel') }}</a>
58
+ </div>
59
+ </form>
60
+ </div>
61
+ @else
62
+ @if(page.tabs.length > 0)
63
+ <div class="mb-4 flex gap-4 border-b border-gray-200 text-sm font-medium" role="tablist" data-block="tabs">
64
+ @each(tab in page.tabs)
65
+ <a href="{{ tab.href }}" role="tab" aria-selected="{{ tab.active ? 'true' : 'false' }}" class="-mb-px border-b-2 pb-2 {{ tab.active ? 'border-gray-900 text-gray-900' : 'border-transparent text-gray-500 hover:text-gray-700' }}">{{ tab.label }}</a>
66
+ @end
67
+ </div>
68
+ @end
69
+ <div class="space-y-6">
70
+ @each(block in page.blocks)
71
+ @include('authkit::account/partials/extension_block')
72
+ @end
73
+ </div>
74
+ @end
75
+ </div>
76
+ </body>
77
+ </html>
@@ -16,6 +16,8 @@
16
16
  </form>
17
17
  </div>
18
18
 
19
+ @include('authkit::account/partials/nav')
20
+
19
21
  @if(error)
20
22
  <p class="mb-4 text-sm text-red-600">{{ error }}</p>
21
23
  @end
@@ -0,0 +1,14 @@
1
+ {{-- Botões de actions (variável `actions`). Com `confirm`/`fields` o botão abre o passo de confirmação. --}}
2
+ @each(action in actions)
3
+ @if(action.step)
4
+ <a href="{{ action.href }}" data-action="{{ action.action }}" class="rounded-lg border px-3 py-1.5 text-sm font-semibold {{ action.tone === 'danger' ? 'border-red-300 text-red-700 hover:bg-red-50' : 'border-gray-300 text-gray-700 hover:bg-gray-50' }}">{{ action.label }}</a>
5
+ @else
6
+ <form method="POST" action="{{ action.href }}" data-submit-lock>
7
+ <input type="hidden" name="_csrf" value="{{ csrfToken }}">
8
+ @if(action.target !== null)
9
+ <input type="hidden" name="target" value="{{ action.target }}">
10
+ @end
11
+ <button type="submit" data-action="{{ action.action }}" class="rounded-lg border px-3 py-1.5 text-sm font-semibold {{ action.tone === 'danger' ? 'border-red-300 text-red-700 hover:bg-red-50' : 'border-gray-300 text-gray-700 hover:bg-gray-50' }}">{{ action.label }}</button>
12
+ </form>
13
+ @end
14
+ @end
@@ -0,0 +1,197 @@
1
+ {{-- Um bloco de uma página de extension (já resolvido: textos traduzidos, valores formatados). Variável `block`. --}}
2
+ @if(block.kind === 'notice')
3
+ <div data-block="notice" data-tone="{{ block.tone }}" class="rounded-lg border p-4 text-sm {{ block.tone === 'danger' ? 'border-red-300 bg-red-50 text-red-900' : block.tone === 'warning' ? 'border-amber-300 bg-amber-50 text-amber-900' : block.tone === 'success' ? 'border-emerald-300 bg-emerald-50 text-emerald-900' : 'border-sky-300 bg-sky-50 text-sky-900' }}">{{ block.text }}</div>
4
+ @elseif(block.kind === 'keyValue')
5
+ <section data-block="keyValue" class="overflow-hidden rounded-xl bg-white shadow-xs ring-1 ring-black/5">
6
+ @if(block.title)
7
+ <h2 class="border-b border-gray-100 px-4 py-3 text-sm font-semibold text-gray-900">{{ block.title }}</h2>
8
+ @end
9
+ <dl class="divide-y divide-gray-100">
10
+ @each(row in block.rows)
11
+ <div class="flex items-center justify-between gap-4 px-4 py-3 text-sm">
12
+ <dt class="text-gray-500">{{ row.label }}</dt>
13
+ <dd class="text-right text-gray-900">
14
+ @!component('authkit::account/partials/extension_value', { value: row.value })
15
+ </dd>
16
+ </div>
17
+ @end
18
+ </dl>
19
+ @if(block.actions.length > 0)
20
+ <div class="flex flex-wrap gap-2 border-t border-gray-100 px-4 py-3">
21
+ @!component('authkit::account/partials/extension_actions', { actions: block.actions, csrfToken })
22
+ </div>
23
+ @end
24
+ </section>
25
+ @elseif(block.kind === 'list')
26
+ <section data-block="list" class="overflow-hidden rounded-xl bg-white shadow-xs ring-1 ring-black/5">
27
+ @if(block.title)
28
+ <h2 class="border-b border-gray-100 px-4 py-3 text-sm font-semibold text-gray-900">{{ block.title }}</h2>
29
+ @end
30
+ @if(block.items.length === 0)
31
+ <p class="p-6 text-sm text-gray-500">{{ block.empty }}</p>
32
+ @else
33
+ <ul class="divide-y divide-gray-100">
34
+ @each(item in block.items)
35
+ <li class="flex items-center justify-between gap-4 p-4">
36
+ <div class="min-w-0">
37
+ @if(item.href)
38
+ <a href="{{ item.href }}" class="text-sm font-medium text-gray-900 hover:underline" {{ item.external ? 'rel=noopener target=_blank' : '' }}>{{ item.title }}</a>
39
+ @else
40
+ <p class="text-sm font-medium text-gray-900">{{ item.title }}</p>
41
+ @end
42
+ @if(item.subtitle)
43
+ <p class="text-xs text-gray-500">{{ item.subtitle }}</p>
44
+ @end
45
+ @if(item.meta.length > 0)
46
+ <p class="mt-1 flex flex-wrap gap-3 text-xs text-gray-500">
47
+ @each(value in item.meta)
48
+ <span>
49
+ @!component('authkit::account/partials/extension_value', { value })
50
+ </span>
51
+ @end
52
+ </p>
53
+ @end
54
+ </div>
55
+ <div class="flex shrink-0 items-center gap-2">
56
+ @if(item.badge)
57
+ @!component('authkit::account/partials/extension_value', { value: item.badge })
58
+ @end
59
+ @!component('authkit::account/partials/extension_actions', { actions: item.actions, csrfToken })
60
+ </div>
61
+ </li>
62
+ @end
63
+ </ul>
64
+ @end
65
+ @if(block.nextHref)
66
+ <div class="border-t border-gray-100 px-4 py-3 text-right">
67
+ <a href="{{ block.nextHref }}" class="text-sm text-gray-700 hover:underline" rel="next">{{ t('account.extension.next_page') }}</a>
68
+ </div>
69
+ @end
70
+ </section>
71
+ @elseif(block.kind === 'table')
72
+ <section data-block="table" class="overflow-hidden rounded-xl bg-white shadow-xs ring-1 ring-black/5">
73
+ @if(block.title)
74
+ <h2 class="border-b border-gray-100 px-4 py-3 text-sm font-semibold text-gray-900">{{ block.title }}</h2>
75
+ @end
76
+ @if(block.rows.length === 0)
77
+ <p class="p-6 text-sm text-gray-500">{{ block.empty }}</p>
78
+ @else
79
+ <div class="overflow-x-auto">
80
+ <table class="min-w-full text-sm">
81
+ <thead class="bg-gray-50 text-left text-xs uppercase tracking-wide text-gray-500">
82
+ <tr>
83
+ @each(column in block.columns)
84
+ <th scope="col" class="px-4 py-2 font-medium">{{ column.label }}</th>
85
+ @end
86
+ @if(block.hasActions)
87
+ <th scope="col" class="px-4 py-2"></th>
88
+ @end
89
+ </tr>
90
+ </thead>
91
+ <tbody class="divide-y divide-gray-100">
92
+ @each(row in block.rows)
93
+ <tr>
94
+ @each(value in row.cells)
95
+ <td class="px-4 py-2 text-gray-900">
96
+ @!component('authkit::account/partials/extension_value', { value })
97
+ </td>
98
+ @end
99
+ @if(block.hasActions)
100
+ <td class="px-4 py-2 text-right">
101
+ <div class="flex justify-end gap-2">
102
+ @!component('authkit::account/partials/extension_actions', { actions: row.actions, csrfToken })
103
+ </div>
104
+ </td>
105
+ @end
106
+ </tr>
107
+ @end
108
+ </tbody>
109
+ </table>
110
+ </div>
111
+ @end
112
+ @if(block.nextHref)
113
+ <div class="border-t border-gray-100 px-4 py-3 text-right">
114
+ <a href="{{ block.nextHref }}" class="text-sm text-gray-700 hover:underline" rel="next">{{ t('account.extension.next_page') }}</a>
115
+ </div>
116
+ @end
117
+ </section>
118
+ @elseif(block.kind === 'meter')
119
+ <section data-block="meter" class="rounded-xl bg-white p-4 shadow-xs ring-1 ring-black/5">
120
+ <div class="flex items-center justify-between text-sm">
121
+ <span class="font-medium text-gray-900">{{ block.label }}</span>
122
+ <span class="text-gray-500">{{ block.text }}</span>
123
+ </div>
124
+ @if(block.percent !== null)
125
+ <progress class="mt-2 block h-2 w-full overflow-hidden rounded-full" max="100" value="{{ block.percent }}">{{ block.percent }}%</progress>
126
+ @end
127
+ @if(block.resetsAt)
128
+ <p class="mt-1 text-xs text-gray-500">{{ block.resetsAt.text }}</p>
129
+ @end
130
+ </section>
131
+ @elseif(block.kind === 'actions')
132
+ <div data-block="actions" class="flex flex-wrap gap-2">
133
+ @!component('authkit::account/partials/extension_actions', { actions: block.items, csrfToken })
134
+ </div>
135
+ @elseif(block.kind === 'link')
136
+ <p data-block="link">
137
+ <a href="{{ block.href }}" class="text-sm font-medium text-gray-900 underline" {{ block.external ? 'rel=noopener target=_blank' : '' }}>{{ block.label }}</a>
138
+ </p>
139
+ @elseif(block.kind === 'toolPreview')
140
+ <section data-block="toolPreview" class="overflow-hidden rounded-xl bg-white shadow-xs ring-1 ring-black/5">
141
+ <div class="border-b border-gray-100 px-4 py-3">
142
+ <h2 class="text-sm font-semibold text-gray-900">{{ block.title }}</h2>
143
+ @if(block.tool)
144
+ <p class="font-mono text-xs text-gray-500">{{ block.tool }}</p>
145
+ @end
146
+ @if(block.subtitle)
147
+ <p class="text-xs text-gray-500">{{ block.subtitle }}</p>
148
+ @end
149
+ </div>
150
+ @if(block.args.length > 0)
151
+ <dl class="divide-y divide-gray-100">
152
+ @each(arg in block.args)
153
+ <div class="flex items-start justify-between gap-4 px-4 py-2 text-sm">
154
+ <dt class="text-gray-500">{{ arg.label }}</dt>
155
+ <dd class="break-all text-right text-gray-900">
156
+ @!component('authkit::account/partials/extension_value', { value: arg.value })
157
+ </dd>
158
+ </div>
159
+ @end
160
+ </dl>
161
+ @end
162
+ @if(block.body)
163
+ <pre class="max-h-80 overflow-auto bg-gray-50 px-4 py-3 text-xs text-gray-800" data-format="{{ block.body.format }}">{{ block.body.content }}</pre>
164
+ @end
165
+ @if(block.actions.length > 0)
166
+ <div class="flex flex-wrap gap-2 border-t border-gray-100 px-4 py-3">
167
+ @!component('authkit::account/partials/extension_actions', { actions: block.actions, csrfToken })
168
+ </div>
169
+ @end
170
+ </section>
171
+ @elseif(block.kind === 'component')
172
+ <section class="rounded-xl bg-white p-4 shadow-xs ring-1 ring-black/5">
173
+ <div id="{{ block.mountId }}" data-block="component" data-provider="{{ block.provider }}" data-props="{{ block.mountId }}-props">
174
+ @if(block.submit)
175
+ <form method="POST" action="{{ block.submit.postHref }}" data-component-form>
176
+ <input type="hidden" name="_csrf" value="{{ csrfToken }}">
177
+ @if(block.submit.target)
178
+ <input type="hidden" name="target" value="{{ block.submit.target }}">
179
+ @end
180
+ </form>
181
+ @end
182
+ <div data-component-fallback class="text-sm text-gray-500">
183
+ @if(block.fallback)
184
+ <a href="{{ block.fallback.href }}" class="font-medium text-gray-900 underline" {{ block.fallback.external ? 'rel=noopener' : '' }}>{{ block.fallback.label }}</a>
185
+ @else
186
+ {{ t('account.extension.provider_loading') }}
187
+ @end
188
+ </div>
189
+ </div>
190
+ <script type="application/json" id="{{ block.mountId }}-props">{{{ block.propsJson }}}</script>
191
+ @each(script in block.scripts)
192
+ {{{ scriptTag(script) }}}
193
+ @end
194
+ </section>
195
+ @else
196
+ <div data-block="notice" data-tone="warning" class="rounded-lg border border-amber-300 bg-amber-50 p-4 text-sm text-amber-900">{{ t('account.extension.unknown_block') }}</div>
197
+ @end
@@ -0,0 +1,8 @@
1
+ {{-- Um valor formatado (variável `value`). --}}
2
+ @if(value.type === 'badge')
3
+ <span data-value="badge" data-tone="{{ value.tone }}" class="inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium {{ value.tone === 'success' ? 'bg-emerald-100 text-emerald-800' : value.tone === 'warning' ? 'bg-amber-100 text-amber-800' : value.tone === 'danger' ? 'bg-red-100 text-red-800' : 'bg-gray-100 text-gray-700' }}">{{ value.text }}</span>
4
+ @elseif(value.type === 'date' && value.iso)
5
+ <time datetime="{{ value.iso }}" data-value="date">{{ value.text }}</time>
6
+ @else
7
+ <span data-value="{{ value.type }}">{{ value.text }}</span>
8
+ @end
@@ -0,0 +1,14 @@
1
+ {{-- Navegação do console de conta: telas embutidas montadas + páginas de extensions visíveis (prop `accountNav`). --}}
2
+ @if(accountNav && accountNav.length > 0)
3
+ <nav class="mb-6 flex flex-wrap gap-x-4 gap-y-2 text-sm font-medium" data-account-nav>
4
+ @each(navEntry in accountNav)
5
+ <a href="{{ navEntry.href }}" class="{{ navEntry.active ? 'text-gray-900 underline' : 'text-gray-500 hover:underline' }}" aria-current="{{ navEntry.active ? 'page' : 'false' }}">{{ navEntry.label }}</a>
6
+ @end
7
+ </nav>
8
+ @elseif(accountNav === undefined)
9
+ <nav class="mb-6 flex gap-4 text-sm font-medium" data-account-nav>
10
+ <a href="{{ accountPaths?.tokens ?? '/account/tokens' }}" class="text-gray-500 hover:underline">{{ t('account.tokens.title') }}</a>
11
+ <a href="{{ accountPaths?.security ?? '/account/security' }}" class="text-gray-500 hover:underline">{{ t('account.security.title') }}</a>
12
+ <a href="{{ accountPaths?.apps ?? '/account/apps' }}" class="text-gray-500 hover:underline">{{ t('account.apps.title') }}</a>
13
+ </nav>
14
+ @end
@@ -19,11 +19,7 @@
19
19
  </form>
20
20
  </div>
21
21
 
22
- <nav class="mb-6 flex gap-4 text-sm font-medium">
23
- <a href="{{ accountPaths?.tokens ?? '/account/tokens' }}" class="text-gray-500 hover:underline">{{ t('account.tokens.title') }}</a>
24
- <a href="{{ accountPaths?.security ?? '/account/security' }}" class="text-gray-900 underline">{{ t('account.security.title') }}</a>
25
- <a href="{{ accountPaths?.apps ?? '/account/apps' }}" class="text-gray-500 hover:underline">{{ t('account.apps.title') }}</a>
26
- </nav>
22
+ @include('authkit::account/partials/nav')
27
23
 
28
24
  @if(profileUpdated)
29
25
  <div class="mb-6 rounded-lg border border-emerald-300 bg-emerald-50 p-4">
@@ -11,8 +11,6 @@
11
11
  <h1 class="text-xl font-semibold text-gray-900">{{ t('account.tokens.title') }}</h1>
12
12
  </div>
13
13
  <div class="flex items-center gap-4">
14
- <a href="{{ accountPaths?.security ?? '/account/security' }}" class="text-sm text-gray-500 hover:underline">{{ t('account.tokens.security') }}</a>
15
- <a href="{{ accountPaths?.apps ?? '/account/apps' }}" class="text-sm text-gray-500 hover:underline">{{ t('account.apps.title') }}</a>
16
14
  <form method="POST" action="{{ accountPaths?.logout ?? '/account/logout' }}">
17
15
  <input type="hidden" name="_csrf" value="{{ csrfToken }}">
18
16
  <button type="submit" class="text-sm text-gray-500 hover:underline">{{ t('account.tokens.logout') }}</button>
@@ -20,6 +18,8 @@
20
18
  </div>
21
19
  </div>
22
20
 
21
+ @include('authkit::account/partials/nav')
22
+
23
23
  @if(createdToken)
24
24
  <div class="mb-6 rounded-lg border border-emerald-300 bg-emerald-50 p-4">
25
25
  <p class="text-sm font-medium text-emerald-900">
@@ -1,3 +1,3 @@
1
1
  {{-- Gerado por scripts/build_host_css.mjs — não editar à mão. --}}
2
2
  <style>/*! tailwindcss v4.3.5 | MIT License | https://tailwindcss.com */
3
- @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:block))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-100:oklch(93.6% .032 17.717);--color-red-200:oklch(88.5% .062 18.334);--color-red-300:oklch(80.8% .114 19.571);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-red-800:oklch(44.4% .177 26.899);--color-red-900:oklch(39.6% .141 25.723);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-100:oklch(96.2% .059 95.617);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-600:oklch(66.6% .179 58.318);--color-amber-800:oklch(47.3% .137 46.201);--color-green-50:oklch(98.2% .018 155.826);--color-green-700:oklch(52.7% .154 150.069);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-100:oklch(95% .052 163.051);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-300:oklch(84.5% .143 164.978);--color-emerald-600:oklch(59.6% .145 163.225);--color-emerald-700:oklch(50.8% .118 165.612);--color-emerald-800:oklch(43.2% .095 166.913);--color-emerald-900:oklch(37.8% .077 168.94);--color-blue-50:oklch(97% .014 254.604);--color-blue-200:oklch(88.2% .059 254.128);--color-blue-300:oklch(80.9% .105 251.813);--color-blue-800:oklch(42.4% .199 265.638);--color-blue-900:oklch(37.9% .146 265.522);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-gray-900:oklch(21% .034 264.665);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-2xl:42rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-medium:500;--font-weight-semibold:600;--tracking-wide:.025em;--tracking-widest:.1em;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}button:not(:disabled),[role=button]:not(:disabled){cursor:pointer}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.absolute{position:absolute}.relative{position:relative}.top-1\/2{top:50%}.right-2{right:calc(var(--spacing) * 2)}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.mx-auto{margin-inline:auto}.my-4{margin-block:calc(var(--spacing) * 4)}.my-6{margin-block:calc(var(--spacing) * 6)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mb-1{margin-bottom:var(--spacing)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.h-4{height:calc(var(--spacing) * 4)}.h-6{height:calc(var(--spacing) * 6)}.h-8{height:calc(var(--spacing) * 8)}.h-12{height:calc(var(--spacing) * 12)}.h-16{height:calc(var(--spacing) * 16)}.h-48{height:calc(var(--spacing) * 48)}.h-px{height:1px}.min-h-screen{min-height:100vh}.w-4{width:calc(var(--spacing) * 4)}.w-6{width:calc(var(--spacing) * 6)}.w-8{width:calc(var(--spacing) * 8)}.w-12{width:calc(var(--spacing) * 12)}.w-16{width:calc(var(--spacing) * 16)}.w-48{width:calc(var(--spacing) * 48)}.w-fit{width:fit-content}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.flex-1{flex:1}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.cursor-pointer{cursor:pointer}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-gray-100>:not(:last-child)){border-color:var(--color-gray-100)}.overflow-hidden{overflow:hidden}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-full{border-radius:2147483647px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-blue-300{border-color:var(--color-blue-300)}.border-emerald-300{border-color:var(--color-emerald-300)}.border-gray-100{border-color:var(--color-gray-100)}.border-gray-200{border-color:var(--color-gray-200)}.border-gray-300{border-color:var(--color-gray-300)}.border-gray-900{border-color:var(--color-gray-900)}.border-red-200{border-color:var(--color-red-200)}.border-red-300{border-color:var(--color-red-300)}.bg-amber-50{background-color:var(--color-amber-50)}.bg-amber-100{background-color:var(--color-amber-100)}.bg-blue-50{background-color:var(--color-blue-50)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-emerald-100{background-color:var(--color-emerald-100)}.bg-gray-50{background-color:var(--color-gray-50)}.bg-gray-100{background-color:var(--color-gray-100)}.bg-gray-200{background-color:var(--color-gray-200)}.bg-gray-800{background-color:var(--color-gray-800)}.bg-gray-900{background-color:var(--color-gray-900)}.bg-green-50{background-color:var(--color-green-50)}.bg-red-50{background-color:var(--color-red-50)}.bg-red-100{background-color:var(--color-red-100)}.bg-red-600{background-color:var(--color-red-600)}.bg-white{background-color:var(--color-white)}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-6{padding-block:calc(var(--spacing) * 6)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[11px\]{font-size:11px}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.4em\]{--tw-tracking:.4em;letter-spacing:.4em}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-all{word-break:break-all}.text-amber-600{color:var(--color-amber-600)}.text-amber-800{color:var(--color-amber-800)}.text-blue-800{color:var(--color-blue-800)}.text-blue-900{color:var(--color-blue-900)}.text-emerald-600{color:var(--color-emerald-600)}.text-emerald-700{color:var(--color-emerald-700)}.text-emerald-800{color:var(--color-emerald-800)}.text-emerald-900{color:var(--color-emerald-900)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-gray-700{color:var(--color-gray-700)}.text-gray-800{color:var(--color-gray-800)}.text-gray-900{color:var(--color-gray-900)}.text-green-700{color:var(--color-green-700)}.text-red-600{color:var(--color-red-600)}.text-red-700{color:var(--color-red-700)}.text-red-800{color:var(--color-red-800)}.text-red-900{color:var(--color-red-900)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.underline{text-decoration-line:underline}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xs{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset, ) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-amber-200{--tw-ring-color:var(--color-amber-200)}.ring-black\/5{--tw-ring-color:#0000000d}@supports (color:color-mix(in lab, red, red)){.ring-black\/5{--tw-ring-color:color-mix(in oklab, var(--color-black) 5%, transparent)}}.ring-blue-200{--tw-ring-color:var(--color-blue-200)}.ring-emerald-200{--tw-ring-color:var(--color-emerald-200)}.ring-gray-900{--tw-ring-color:var(--color-gray-900)}.ring-red-200{--tw-ring-color:var(--color-red-200)}.outline-hidden{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.outline-hidden{outline-offset:2px;outline:2px solid #0000}}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.select-none{-webkit-user-select:none;user-select:none}.last\:border-0:last-child{border-style:var(--tw-border-style);border-width:0}@media (hover:hover){.hover\:bg-gray-50:hover{background-color:var(--color-gray-50)}.hover\:bg-gray-700:hover{background-color:var(--color-gray-700)}.hover\:bg-red-50:hover{background-color:var(--color-red-50)}.hover\:bg-red-700:hover{background-color:var(--color-red-700)}.hover\:text-gray-600:hover{color:var(--color-gray-600)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}}.focus\:border-gray-900:focus{border-color:var(--color-gray-900)}.focus\:border-red-600:focus{border-color:var(--color-red-600)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset, ) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-gray-900:focus{--tw-ring-color:var(--color-gray-900)}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}</style>
3
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:block))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-100:oklch(93.6% .032 17.717);--color-red-200:oklch(88.5% .062 18.334);--color-red-300:oklch(80.8% .114 19.571);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-red-800:oklch(44.4% .177 26.899);--color-red-900:oklch(39.6% .141 25.723);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-100:oklch(96.2% .059 95.617);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-600:oklch(66.6% .179 58.318);--color-amber-800:oklch(47.3% .137 46.201);--color-amber-900:oklch(41.4% .112 45.904);--color-green-50:oklch(98.2% .018 155.826);--color-green-700:oklch(52.7% .154 150.069);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-100:oklch(95% .052 163.051);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-300:oklch(84.5% .143 164.978);--color-emerald-600:oklch(59.6% .145 163.225);--color-emerald-700:oklch(50.8% .118 165.612);--color-emerald-800:oklch(43.2% .095 166.913);--color-emerald-900:oklch(37.8% .077 168.94);--color-sky-50:oklch(97.7% .013 236.62);--color-sky-300:oklch(82.8% .111 230.318);--color-sky-900:oklch(39.1% .09 240.876);--color-blue-50:oklch(97% .014 254.604);--color-blue-200:oklch(88.2% .059 254.128);--color-blue-300:oklch(80.9% .105 251.813);--color-blue-800:oklch(42.4% .199 265.638);--color-blue-900:oklch(37.9% .146 265.522);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-gray-900:oklch(21% .034 264.665);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-2xl:42rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-medium:500;--font-weight-semibold:600;--tracking-wide:.025em;--tracking-widest:.1em;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}button:not(:disabled),[role=button]:not(:disabled){cursor:pointer}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.absolute{position:absolute}.relative{position:relative}.top-1\/2{top:50%}.right-2{right:calc(var(--spacing) * 2)}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.mx-auto{margin-inline:auto}.my-4{margin-block:calc(var(--spacing) * 4)}.my-6{margin-block:calc(var(--spacing) * 6)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-8{margin-top:calc(var(--spacing) * 8)}.-mb-px{margin-bottom:-1px}.mb-1{margin-bottom:var(--spacing)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.h-2{height:calc(var(--spacing) * 2)}.h-4{height:calc(var(--spacing) * 4)}.h-6{height:calc(var(--spacing) * 6)}.h-8{height:calc(var(--spacing) * 8)}.h-12{height:calc(var(--spacing) * 12)}.h-16{height:calc(var(--spacing) * 16)}.h-48{height:calc(var(--spacing) * 48)}.h-px{height:1px}.max-h-80{max-height:calc(var(--spacing) * 80)}.min-h-screen{min-height:100vh}.w-4{width:calc(var(--spacing) * 4)}.w-6{width:calc(var(--spacing) * 6)}.w-8{width:calc(var(--spacing) * 8)}.w-12{width:calc(var(--spacing) * 12)}.w-16{width:calc(var(--spacing) * 16)}.w-48{width:calc(var(--spacing) * 48)}.w-fit{width:fit-content}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.min-w-0{min-width:0}.min-w-full{min-width:100%}.flex-1{flex:1}.shrink-0{flex-shrink:0}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.cursor-pointer{cursor:pointer}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-y-2{row-gap:calc(var(--spacing) * 2)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-gray-100>:not(:last-child)){border-color:var(--color-gray-100)}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-full{border-radius:2147483647px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-amber-300{border-color:var(--color-amber-300)}.border-blue-300{border-color:var(--color-blue-300)}.border-emerald-300{border-color:var(--color-emerald-300)}.border-gray-100{border-color:var(--color-gray-100)}.border-gray-200{border-color:var(--color-gray-200)}.border-gray-300{border-color:var(--color-gray-300)}.border-gray-900{border-color:var(--color-gray-900)}.border-red-200{border-color:var(--color-red-200)}.border-red-300{border-color:var(--color-red-300)}.border-sky-300{border-color:var(--color-sky-300)}.border-transparent{border-color:#0000}.bg-amber-50{background-color:var(--color-amber-50)}.bg-amber-100{background-color:var(--color-amber-100)}.bg-blue-50{background-color:var(--color-blue-50)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-emerald-100{background-color:var(--color-emerald-100)}.bg-gray-50{background-color:var(--color-gray-50)}.bg-gray-100{background-color:var(--color-gray-100)}.bg-gray-200{background-color:var(--color-gray-200)}.bg-gray-800{background-color:var(--color-gray-800)}.bg-gray-900{background-color:var(--color-gray-900)}.bg-green-50{background-color:var(--color-green-50)}.bg-red-50{background-color:var(--color-red-50)}.bg-red-100{background-color:var(--color-red-100)}.bg-red-600{background-color:var(--color-red-600)}.bg-sky-50{background-color:var(--color-sky-50)}.bg-white{background-color:var(--color-white)}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-6{padding-block:calc(var(--spacing) * 6)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[11px\]{font-size:11px}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.4em\]{--tw-tracking:.4em;letter-spacing:.4em}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-all{word-break:break-all}.text-amber-600{color:var(--color-amber-600)}.text-amber-800{color:var(--color-amber-800)}.text-amber-900{color:var(--color-amber-900)}.text-blue-800{color:var(--color-blue-800)}.text-blue-900{color:var(--color-blue-900)}.text-emerald-600{color:var(--color-emerald-600)}.text-emerald-700{color:var(--color-emerald-700)}.text-emerald-800{color:var(--color-emerald-800)}.text-emerald-900{color:var(--color-emerald-900)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-gray-700{color:var(--color-gray-700)}.text-gray-800{color:var(--color-gray-800)}.text-gray-900{color:var(--color-gray-900)}.text-green-700{color:var(--color-green-700)}.text-red-600{color:var(--color-red-600)}.text-red-700{color:var(--color-red-700)}.text-red-800{color:var(--color-red-800)}.text-red-900{color:var(--color-red-900)}.text-sky-900{color:var(--color-sky-900)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.underline{text-decoration-line:underline}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xs{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset, ) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-amber-200{--tw-ring-color:var(--color-amber-200)}.ring-black\/5{--tw-ring-color:#0000000d}@supports (color:color-mix(in lab, red, red)){.ring-black\/5{--tw-ring-color:color-mix(in oklab, var(--color-black) 5%, transparent)}}.ring-blue-200{--tw-ring-color:var(--color-blue-200)}.ring-emerald-200{--tw-ring-color:var(--color-emerald-200)}.ring-gray-900{--tw-ring-color:var(--color-gray-900)}.ring-red-200{--tw-ring-color:var(--color-red-200)}.outline-hidden{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.outline-hidden{outline-offset:2px;outline:2px solid #0000}}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.select-none{-webkit-user-select:none;user-select:none}.last\:border-0:last-child{border-style:var(--tw-border-style);border-width:0}@media (hover:hover){.hover\:bg-gray-50:hover{background-color:var(--color-gray-50)}.hover\:bg-gray-700:hover{background-color:var(--color-gray-700)}.hover\:bg-gray-800:hover{background-color:var(--color-gray-800)}.hover\:bg-red-50:hover{background-color:var(--color-red-50)}.hover\:bg-red-700:hover{background-color:var(--color-red-700)}.hover\:text-gray-600:hover{color:var(--color-gray-600)}.hover\:text-gray-700:hover{color:var(--color-gray-700)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}}.focus\:border-gray-900:focus{border-color:var(--color-gray-900)}.focus\:border-red-600:focus{border-color:var(--color-red-600)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset, ) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-gray-900:focus{--tw-ring-color:var(--color-gray-900)}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}</style>
package/build/index.d.ts CHANGED
@@ -25,6 +25,8 @@ export type { AuditEvent, AuditEventType, AuditPage, AuditSink, ListAuditParams,
25
25
  export { lucidAuditSink } from './src/audit/lucid_audit_sink.js';
26
26
  export type { ConsoleAuthorize, ConsoleAuthorizeResult, ConsoleAuthorizer, ConsoleAuthorizerClass, } from './src/console_authorize.js';
27
27
  export { authorizeByToken } from './src/console_authorize.js';
28
+ export type { AgoraConsoleDecision, AgoraConsoleEntry, AgoraConsoleIcon, AgoraConsoleRegistry, AgoraConsoleSearchHit, } from './src/console_switcher.js';
29
+ export { AGORA_CONSOLES_BINDING, isAgoraProbe, registerAgoraConsole, } from './src/console_switcher.js';
28
30
  export type { AdminApiConfigInput, AdminConfigInput, AuthHostRenderer, AuthMethodsConfigInput, AuthServerConfigInput, AuthSocialConfig, DynamicRegistrationConfigInput, LoginConfigInput, OrganizationsConfigInput, PasswordlessConfigInput, RateLimitBucket, RateLimitConfigInput, RegistrationConfigInput, ResolvedAdminApiConfig, ResolvedAdminConfig, ResolvedAuthMethodsConfig, ResolvedDynamicRegistrationConfig, ResolvedLoginConfig, ResolvedNotificationsConfig, ResolvedOrganizationsConfig, ResolvedPasswordlessConfig, ResolvedRateLimitConfig, ResolvedRegistrationConfig, ResolvedServerConfig, ResolvedWebauthnConfig, WebauthnConfigInput, } from './src/define_config.js';
29
31
  export { adapters, defineConfig, resolveAdmin, resolveAdminApi, resolveAuthMethodsConfig, resolveDynamicRegistration, resolveLogin, resolveNotifications, resolveOrganizations, resolvePasswordless, resolveRateLimit, resolveRegistration, resolveWebauthn, toSeconds, } from './src/define_config.js';
30
32
  export type { EventsConfigInput, ResolvedEventsConfig } from './src/events/dispatcher.js';
package/build/index.js CHANGED
@@ -14,6 +14,7 @@ export { pact, pactProtocol } from './src/agents/protocol.js';
14
14
  export { personalAgentExtensionRuntime, } from './src/agents/runtime.js';
15
15
  export { lucidAuditSink } from './src/audit/lucid_audit_sink.js';
16
16
  export { authorizeByToken } from './src/console_authorize.js';
17
+ export { AGORA_CONSOLES_BINDING, isAgoraProbe, registerAgoraConsole, } from './src/console_switcher.js';
17
18
  export { adapters, defineConfig, resolveAdmin, resolveAdminApi, resolveAuthMethodsConfig, resolveDynamicRegistration, resolveLogin, resolveNotifications, resolveOrganizations, resolvePasswordless, resolveRateLimit, resolveRegistration, resolveWebauthn, toSeconds, } from './src/define_config.js';
18
19
  export { buildWebhookBody, composeAuditSink, resolveEvents, signWebhookBody, } from './src/events/dispatcher.js';
19
20
  export { inProcessAccessTokenVerifier, remoteAccessTokenVerifier, } from './src/host/access_token_verifier.js';
@@ -16,6 +16,7 @@ import { fileURLToPath } from 'node:url';
16
16
  import { configProvider } from '@adonisjs/core';
17
17
  import { RuntimeException } from '@adonisjs/core/exceptions';
18
18
  import { setBootedApp } from '../services/booted_app.js';
19
+ import { accountExtensionRegistry } from '../src/account/mount.js';
19
20
  import { defaultEncryptForStore } from '../src/define_config.js';
20
21
  import { authkitDoctorChecks } from '../src/doctor/agora_checks.js';
21
22
  import { registerDoctorChecks } from '../src/doctor/agora_doctor.js';
@@ -136,6 +137,7 @@ export default class AuthkitServerProvider {
136
137
  routes: typeof config.routes === 'object' ? config.routes : undefined,
137
138
  lockedRouteOptions: config.lockedRouteOptions,
138
139
  consoleNeedsLoginUrl: config.accountSession?.acceptIdpSession === false && config.authMethods?.password === false,
140
+ accountConsole: config.accountConsole,
139
141
  personalAgents: config.personalAgents
140
142
  ? {
141
143
  prefix: config.personalAgents.prefix,
@@ -191,6 +193,9 @@ export default class AuthkitServerProvider {
191
193
  // que o `bin/server` bootou — dual-package hazard do core (ver
192
194
  // `services/booted_app.ts`).
193
195
  setBootedApp(this.app);
196
+ // Account console extensions: other packages register pages here from their `boot()`. No
197
+ // config to resolve, so `hasBinding` + `make` never boots the auth server.
198
+ this.app.container.singleton('authkit.accountExtensions', async () => accountExtensionRegistry());
194
199
  this.app.container.singleton('authkit.server', async () => {
195
200
  const configProviderValue = this.app.config.get('authkit');
196
201
  const config = (await configProvider.resolve(this.app, configProviderValue));