@undefineds.co/xpod 0.4.25 → 0.4.27

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 (155) hide show
  1. package/dist/api/ApiServer.d.ts +1 -0
  2. package/dist/api/ApiServer.js +38 -0
  3. package/dist/api/ai-config/AiConfigStore.js +18 -6
  4. package/dist/api/ai-gateway/connect/index.d.ts +1 -0
  5. package/dist/api/ai-gateway/connect/index.js +39 -18
  6. package/dist/api/ai-gateway/models/ProviderModelsAdapter.js +5 -2
  7. package/dist/api/container/common.js +8 -2
  8. package/dist/api/container/index.js +2 -2
  9. package/dist/api/container/local.js +6 -3
  10. package/dist/api/handlers/AiGatewayHandler.d.ts +1 -0
  11. package/dist/api/handlers/AiGatewayHandler.js +53 -3
  12. package/dist/api/handlers/AiGatewayManagementHandler.js +9 -0
  13. package/dist/api/handlers/TaskHandler.js +15 -10
  14. package/dist/api/network/NetworkEnvironmentConfigurationStore.js +1 -1
  15. package/dist/api/runs/ManagedRunWorker.d.ts +0 -1
  16. package/dist/api/runs/ManagedRunWorker.js +2 -14
  17. package/dist/api/runs/PiAgentRuntimeDriver.d.ts +0 -8
  18. package/dist/api/runs/PiAgentRuntimeDriver.js +65 -21
  19. package/dist/api/runs/RunStateCenter.js +1 -0
  20. package/dist/api/runs/store.d.ts +1 -0
  21. package/dist/api/runs/store.js +13 -0
  22. package/dist/api/tasks/TaskMaterializer.js +13 -6
  23. package/dist/api/tasks/TaskResumeDiagnostics.d.ts +28 -0
  24. package/dist/api/tasks/TaskResumeDiagnostics.js +148 -0
  25. package/dist/api/tasks/TaskService.js +40 -23
  26. package/dist/storage/conditions/StorageETagHandler.d.ts +1 -1
  27. package/dist/storage/conditions/StorageETagHandler.js +13 -4
  28. package/dist/util/task-model-diagnostics.d.ts +67 -0
  29. package/dist/util/task-model-diagnostics.js +118 -0
  30. package/node_modules/@undefineds.co/ai-connections/dist/AiApiKeyPool.d.ts +1 -0
  31. package/node_modules/@undefineds.co/ai-connections/dist/AiApiKeyPool.js +2 -1
  32. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectDialog.d.ts +1 -0
  33. package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.d.ts +1 -0
  34. package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.js +10 -10
  35. package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeyRow.d.ts +3 -1
  36. package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeyRow.js +2 -2
  37. package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.js +77 -23
  38. package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.d.ts +1 -0
  39. package/node_modules/@undefineds.co/ai-connections/dist/AiSortableCredentialList.js +59 -59
  40. package/node_modules/@undefineds.co/ai-connections/dist/collection-runtime.js +2 -0
  41. package/node_modules/@undefineds.co/ai-connections/dist/collections.js +14 -6
  42. package/node_modules/@undefineds.co/ai-connections/dist/contract/ai-connections-client.d.ts +2 -1
  43. package/node_modules/@undefineds.co/ai-connections/dist/contract/ai-connections-client.js +1 -0
  44. package/node_modules/@undefineds.co/ai-connections/dist/contract/client/gateway-model-roles.d.ts +11 -0
  45. package/node_modules/@undefineds.co/ai-connections/dist/contract/client/gateway-model-roles.js +11 -0
  46. package/node_modules/@undefineds.co/ai-connections/dist/contract/client/normalize.d.ts +2 -1
  47. package/node_modules/@undefineds.co/ai-connections/dist/contract/client/normalize.js +12 -5
  48. package/node_modules/@undefineds.co/ai-connections/dist/contract/client/request.js +10 -2
  49. package/node_modules/@undefineds.co/ai-connections/dist/contract/client/types.d.ts +10 -0
  50. package/node_modules/@undefineds.co/ai-connections/package.json +1 -1
  51. package/node_modules/@undefineds.co/extension-sdk/dist/web.d.ts +1 -0
  52. package/node_modules/@undefineds.co/extension-sdk/package.json +1 -1
  53. package/node_modules/@undefineds.co/pod-collections/dist/index.cjs +60 -13
  54. package/node_modules/@undefineds.co/pod-collections/dist/mapping.d.ts +16 -1
  55. package/node_modules/@undefineds.co/pod-collections/dist/mapping.js +51 -0
  56. package/node_modules/@undefineds.co/pod-collections/dist/mutations.js +14 -18
  57. package/node_modules/@undefineds.co/pod-collections/package.json +1 -1
  58. package/node_modules/@undefineds.co/shared-ui/dist/list.d.ts +8 -1
  59. package/node_modules/@undefineds.co/shared-ui/dist/list.js +4 -1
  60. package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/IdpChrome.d.ts +1 -1
  61. package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/IdpChrome.js +2 -2
  62. package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/IdpViews.js +2 -2
  63. package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/PodSignInFrame.d.ts +3 -3
  64. package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/PodSignInFrame.js +5 -5
  65. package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/parts.d.ts +5 -5
  66. package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/parts.js +5 -5
  67. package/node_modules/@undefineds.co/shared-ui/dist/section-header.js +1 -1
  68. package/node_modules/@undefineds.co/shared-ui/dist/theme.css +5 -32
  69. package/node_modules/@undefineds.co/shared-ui/package.json +1 -1
  70. package/node_modules/@undefineds.co/solid-sdk/package.json +1 -1
  71. package/package.json +2 -2
  72. package/static/app/assets/main.css +1 -1
  73. package/static/app/assets/main.js +1 -1
  74. package/static/dashboard/assets/AccountAuthBoundary-Dv52SZc6.js +1 -0
  75. package/static/dashboard/assets/DesktopOidcCallback-DaT_Rumf.js +1 -0
  76. package/static/dashboard/assets/DevicePages-HjclpIVm.js +2 -0
  77. package/static/dashboard/assets/ModelsPage-Be2TPd-x.js +11 -0
  78. package/static/dashboard/assets/{PaneListHeader-Dn5O0mwy.js → PaneListHeader-DtvnRmFq.js} +1 -1
  79. package/static/dashboard/assets/{PodDeletionAuthorizationPanel-D3NOG6ZM.js → PodDeletionAuthorizationPanel-BJk_8rJq.js} +3 -3
  80. package/static/dashboard/assets/PodPage-C4gzEspV.js +1 -0
  81. package/static/dashboard/assets/{SystemSettingsPage-BNQP_Yuc.js → SystemSettingsPage-HaNrP1H1.js} +1 -1
  82. package/static/dashboard/assets/TasksPage-BdO5K2L7.js +1 -0
  83. package/static/dashboard/assets/{WebDesktopEntry-vnb4CZWp.js → WebDesktopEntry-Cj9_ZfJU.js} +1 -1
  84. package/static/dashboard/assets/XpodAiConnectionsPodStore-B7gmXBmC.js +3 -0
  85. package/static/dashboard/assets/XpodShellApp-D_KY4nCW.js +4 -0
  86. package/static/dashboard/assets/{account-session-DCUmCop1.js → account-session-DlcKNG7k.js} +1 -1
  87. package/static/dashboard/assets/{button-By5Bgvmb.js → button-wslF55uZ.js} +1 -1
  88. package/static/dashboard/assets/collection-runtime-uxxgEu13.js +1 -0
  89. package/static/dashboard/assets/{createLucideIcon-bunMzPms.js → createLucideIcon-BJQl82Qk.js} +1 -1
  90. package/static/dashboard/assets/dashboard-CbJ-JkrI.css +1 -0
  91. package/static/dashboard/assets/{dashboard-mlsg3yaw.js → dashboard-Or0gnkou.js} +2 -2
  92. package/static/dashboard/assets/index-BqFeOML9.js +1 -0
  93. package/static/dashboard/assets/{index-DvMG5pHk.js → index-DgKn1twH.js} +2 -2
  94. package/static/dashboard/assets/{label-Bj03L9xs.js → label-CS6Sx6Zb.js} +1 -1
  95. package/static/dashboard/assets/list-UyhlCFKk.js +1 -0
  96. package/static/dashboard/assets/{nav-item-style-BNqWQY6p.js → nav-item-style-CW1Nnorq.js} +1 -1
  97. package/static/dashboard/assets/{pod-collections-host-KnnGFZHL.js → pod-collections-host-DjK2xf-b.js} +6 -6
  98. package/static/dashboard/assets/{safe-continuation-D9AhcWiB.js → safe-continuation-ClWAhcma.js} +1 -1
  99. package/static/dashboard/assets/{section-header-CLCzbOp_.js → section-header-CEIEcco-.js} +1 -1
  100. package/static/dashboard/assets/{setting-row-DTCec8A2.js → setting-row-CaYv3dfF.js} +1 -1
  101. package/static/dashboard/assets/xpod-remembered-login-BUF9fin1.js +310 -0
  102. package/static/dashboard/dashboard.html +2 -2
  103. package/static/settings/assets/{AccountAuthBoundary-C0og_gIA.js → AccountAuthBoundary-Chqd38oU.js} +1 -1
  104. package/static/settings/assets/{DesktopOidcCallback-C5q4oFZ0.js → DesktopOidcCallback-VUrOSM_q.js} +1 -1
  105. package/static/settings/assets/DevicePages-C6qwvWwu.js +2 -0
  106. package/static/settings/assets/ModelsPage-Ry_dObRQ.js +11 -0
  107. package/static/settings/assets/{PaneListHeader-DqVlMe2D.js → PaneListHeader-B5RkRqr4.js} +1 -1
  108. package/static/settings/assets/{PodDeletionAuthorizationPanel-DgVvarVY.js → PodDeletionAuthorizationPanel-DPM-5Izt.js} +3 -3
  109. package/static/settings/assets/PodPage-CxND6wwc.js +1 -0
  110. package/static/settings/assets/{SystemSettingsPage-Crzm_DrI.js → SystemSettingsPage-C8EdMkW7.js} +1 -1
  111. package/static/settings/assets/TasksPage-DuqptEm8.js +1 -0
  112. package/static/settings/assets/{WebDesktopEntry-BGC5eRF2.js → WebDesktopEntry-BRcyktkv.js} +1 -1
  113. package/static/settings/assets/XpodAiConnectionsPodStore-CyA_BJVC.js +3 -0
  114. package/static/settings/assets/XpodShellApp-CsivHJl0.js +4 -0
  115. package/static/settings/assets/XpodThemeProvider-CbJ-JkrI.css +1 -0
  116. package/static/settings/assets/{XpodThemeProvider-CB6LepTA.js → XpodThemeProvider-DK3pIdRG.js} +2 -2
  117. package/static/settings/assets/{account-session-BcLjCj0x.js → account-session-DJOZ03xr.js} +1 -1
  118. package/static/settings/assets/auth-callback-GIBYEz_7.js +1 -0
  119. package/static/settings/assets/{button-BObT8pTE.js → button-D3yW-2o1.js} +1 -1
  120. package/static/settings/assets/collection-runtime-DfGo25mh.js +1 -0
  121. package/static/settings/assets/{createLucideIcon-BVsUxXpZ.js → createLucideIcon-CacwLsmB.js} +1 -1
  122. package/static/settings/assets/{index-ktjMkj7-.js → index-r5KRYsKC.js} +1 -1
  123. package/static/settings/assets/{label-BrqO8_m_.js → label-MJjUmvzG.js} +1 -1
  124. package/static/settings/assets/list-Ce-5k1MX.js +1 -0
  125. package/static/settings/assets/{nav-item-style-Di2CxkDU.js → nav-item-style-ZUbL8KOZ.js} +1 -1
  126. package/static/settings/assets/{pod-collections-host-KnnGFZHL.js → pod-collections-host-DjK2xf-b.js} +6 -6
  127. package/static/settings/assets/{safe-continuation-Dx6ceJpY.js → safe-continuation-vlBZFSlU.js} +1 -1
  128. package/static/settings/assets/{section-header-Dtl7yjVr.js → section-header-DGJdEvQw.js} +1 -1
  129. package/static/settings/assets/{setting-row-BL6Hhe8N.js → setting-row-C7tuFiho.js} +1 -1
  130. package/static/settings/assets/{settings-DaRBxoZk.js → settings-CyQPih1O.js} +1 -1
  131. package/static/settings/assets/xpod-remembered-login-D-TzzT5K.js +567 -0
  132. package/static/settings/auth-callback.html +3 -3
  133. package/static/settings/settings.html +3 -3
  134. package/static/dashboard/assets/AccountAuthBoundary-BvoDydRz.js +0 -1
  135. package/static/dashboard/assets/DesktopOidcCallback-BwIj874x.js +0 -1
  136. package/static/dashboard/assets/DevicePages-jOjMcvsr.js +0 -2
  137. package/static/dashboard/assets/ModelsPage-CMTdfqBR.js +0 -11
  138. package/static/dashboard/assets/PodPage-BueBdJ9_.js +0 -1
  139. package/static/dashboard/assets/TasksPage-CxtLJiSF.js +0 -1
  140. package/static/dashboard/assets/XpodAiConnectionsPodStore-wx3Ttupm.js +0 -18
  141. package/static/dashboard/assets/XpodShellApp-5FWY8-d5.js +0 -4
  142. package/static/dashboard/assets/collection-runtime-BnomuB0E.js +0 -1
  143. package/static/dashboard/assets/dashboard-C64R553B.css +0 -1
  144. package/static/dashboard/assets/xpod-remembered-login-Dr69A0Rv.js +0 -295
  145. package/static/settings/assets/DevicePages-fyHjjucT.js +0 -2
  146. package/static/settings/assets/ModelsPage-EyOByLyE.js +0 -11
  147. package/static/settings/assets/PodPage-DY4Oi9wg.js +0 -1
  148. package/static/settings/assets/TasksPage-CfXJbnlt.js +0 -1
  149. package/static/settings/assets/XpodAiConnectionsPodStore-CXcmgKmQ.js +0 -3
  150. package/static/settings/assets/XpodShellApp-D1PS3Iut.js +0 -4
  151. package/static/settings/assets/XpodThemeProvider-C64R553B.css +0 -1
  152. package/static/settings/assets/auth-callback-DSPQ28ar.js +0 -1
  153. package/static/settings/assets/collection-runtime-DzNbdZGe.js +0 -1
  154. package/static/settings/assets/index-browser-3WfrNbcG.js +0 -273
  155. package/static/settings/assets/xpod-remembered-login-Q66DH12t.js +0 -295
@@ -1,5 +1,5 @@
1
1
  import { PodCollectionError } from './types.js';
2
- import { descriptorRowToColumnValues, fieldBindings, isUriArrayField, projectionFieldOrder, } from './mapping.js';
2
+ import { descriptorRowToColumnValues, fieldBindings, isUriArrayField, normalizeMutationRow, normalizeUriArray, projectionFieldOrder, } from './mapping.js';
3
3
  import { documentOfIri, resourceIdForRow, subjectIriForRow } from './layout.js';
4
4
  import { sessionFetchOf } from './read.js';
5
5
  import { projectionCovers, projectionHash } from './diff.js';
@@ -109,13 +109,6 @@ export function reconcilePendingWrites(pending, next, hashOf, writeOnly = EMPTY_
109
109
  }
110
110
  /** 默认「没有只写字段」,与 `projectionCovers()` 的默认值同义。 */
111
111
  const EMPTY_WRITE_ONLY = new Set();
112
- function absoluteUri(value, base) {
113
- if (typeof value !== 'string' || value.length === 0)
114
- return undefined;
115
- if (/^[a-z][a-z0-9+.-]*:/iu.test(value))
116
- return value;
117
- return new URL(value, base).toString();
118
- }
119
112
  /**
120
113
  * `array: true` + `type: 'uri'` 字段的唯一写入口(§4.1):一次 SPARQL PATCH,
121
114
  * 先删旧值再插新值。`array + uri` 之外字段不允许走这里。
@@ -126,12 +119,8 @@ export async function writeField(context, fieldName, options) {
126
119
  throw new PodCollectionError('write_field_not_uri_array', `field ${fieldName} is not array+uri; it must go through the ORM`);
127
120
  }
128
121
  const documentUrl = documentOfIri(context.document);
129
- const previous = (Array.isArray(options.previous) ? options.previous : [options.previous])
130
- .map((value) => absoluteUri(value, documentUrl))
131
- .filter((value) => value !== undefined);
132
- const next = (Array.isArray(options.next) ? options.next : [options.next])
133
- .map((value) => absoluteUri(value, documentUrl))
134
- .filter((value) => value !== undefined);
122
+ const previous = normalizeUriArray(options.previous, documentUrl);
123
+ const next = normalizeUriArray(options.next, documentUrl);
135
124
  const triples = (iris) => iris
136
125
  .map((iri) => `<${options.subjectIri}> <${field.predicate}> <${iri}> .`)
137
126
  .join('\n');
@@ -183,10 +172,14 @@ export function createMutationHandlers(context) {
183
172
  return {
184
173
  onInsert: async ({ transaction }) => {
185
174
  for (const mutation of transaction.mutations) {
186
- const row = mutation.modified;
187
175
  const key = String(mutation.key);
188
176
  const resourceId = resourceIdForRow(descriptor, context.document, context.podUrl, key);
189
177
  const subjectIri = subjectIriForRow(descriptor, context.document, key);
178
+ const row = normalizeMutationRow(descriptor, table, mutation.modified, {
179
+ database: context.database, podUrl: context.podUrl, document: context.document, resourceId,
180
+ });
181
+ // TanStack keeps modified as its optimistic/committed transaction row.
182
+ Object.assign(mutation.modified, row);
190
183
  pending.register({
191
184
  key,
192
185
  intent: row,
@@ -207,10 +200,13 @@ export function createMutationHandlers(context) {
207
200
  for (const mutation of transaction.mutations) {
208
201
  const key = String(mutation.key);
209
202
  const original = mutation.original;
210
- const modified = mutation.modified;
211
203
  const changes = mutation.changes;
212
204
  const resourceId = resourceIdForRow(descriptor, context.document, context.podUrl, key);
213
205
  const subjectIri = subjectIriForRow(descriptor, context.document, key);
206
+ const modified = normalizeMutationRow(descriptor, table, mutation.modified, {
207
+ database: context.database, podUrl: context.podUrl, document: context.document, resourceId,
208
+ });
209
+ Object.assign(mutation.modified, modified);
214
210
  const beforeHash = original && Object.keys(original).length > 0 ? hashOf(original) : undefined;
215
211
  pending.register({
216
212
  key,
@@ -220,13 +216,13 @@ export function createMutationHandlers(context) {
220
216
  });
221
217
  await runWrite(key, async () => {
222
218
  const columnChanges = {};
223
- for (const [field, value] of Object.entries(changes)) {
219
+ for (const field of Object.keys(changes)) {
224
220
  if (uriArrayFieldNames.has(field))
225
221
  continue;
226
222
  const column = columnOf(field);
227
223
  if (column === undefined)
228
224
  continue;
229
- columnChanges[column] = value;
225
+ columnChanges[column] = modified[field];
230
226
  }
231
227
  if (Object.keys(columnChanges).length > 0) {
232
228
  const updated = await context.database.updateById(table, resourceId, columnChanges);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@undefineds.co/pod-collections",
3
- "version": "0.1.1",
3
+ "version": "0.1.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -1,5 +1,12 @@
1
1
  import * as React from 'react';
2
- export type ListSurfaceProps = React.HTMLAttributes<HTMLDivElement>;
2
+ export interface ListSurfaceProps extends React.HTMLAttributes<HTMLDivElement> {
3
+ /**
4
+ * Render the surface as the single child element (e.g. a real `ul` or an
5
+ * existing sortable container) so native semantics, ref and events stay on
6
+ * that element without adding a wrapper.
7
+ */
8
+ asChild?: boolean;
9
+ }
3
10
  /**
4
11
  * Bordered, divided container for a group of rows. Presentation only: it adds
5
12
  * no list role, navigation or focus behaviour of its own.
@@ -6,7 +6,10 @@ import { cn } from './utils.js';
6
6
  * Bordered, divided container for a group of rows. Presentation only: it adds
7
7
  * no list role, navigation or focus behaviour of its own.
8
8
  */
9
- export const ListSurface = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn('divide-y rounded-xl border border-border bg-card', className), ...props })));
9
+ export const ListSurface = React.forwardRef(({ className, asChild = false, children, ...props }, ref) => {
10
+ const Component = asChild ? Slot : 'div';
11
+ return (_jsx(Component, { ref: ref, className: cn('divide-y rounded-xl border border-border bg-card', className), ...props, children: children }));
12
+ });
10
13
  ListSurface.displayName = 'ListSurface';
11
14
  /**
12
15
  * Pure row composition. A non-interactive row is a semantic container; nested
@@ -11,5 +11,5 @@ export interface IdpChromeProps {
11
11
  serviceLabel?: string;
12
12
  locale?: PodSignInLocale;
13
13
  }
14
- /** Service identity stays readable above the form, even on a narrow host. */
14
+ /** 44px tinted bar at the top of every sign-in-service page (B group). */
15
15
  export declare function IdpChrome({ serviceName, serviceHost, icon, serviceLabel, locale }: IdpChromeProps): import("react").JSX.Element;
@@ -1,8 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { resolvePodSignInCopy } from './copy.js';
3
3
  import { XpodMark } from './XpodMark.js';
4
- /** Service identity stays readable above the form, even on a narrow host. */
4
+ /** 44px tinted bar at the top of every sign-in-service page (B group). */
5
5
  export function IdpChrome({ serviceName, serviceHost, icon, serviceLabel, locale }) {
6
6
  const label = serviceLabel ?? resolvePodSignInCopy(locale).serviceLabel;
7
- return (_jsxs("div", { "data-pod-sign-in": "idp-chrome", className: "flex min-h-14 shrink-0 items-center gap-3 border-b border-border bg-[hsl(var(--sunken))] px-6 py-2 text-[13px] text-foreground min-[400px]:px-8", children: [_jsx("span", { className: "flex shrink-0 items-center justify-center", children: icon ?? _jsx(XpodMark, { size: 24 }) }), _jsxs("span", { className: "min-w-0 max-w-[50%] shrink-0 truncate font-medium", children: [serviceName, " \u00B7 ", label] }), serviceHost ? _jsx("span", { className: "ml-auto truncate font-mono text-xs text-muted-foreground", children: serviceHost }) : null] }));
7
+ return (_jsxs("div", { "data-pod-sign-in": "idp-chrome", className: "flex h-11 shrink-0 items-center gap-2 border-b border-border bg-[hsl(var(--sunken))] px-4 text-[13px] text-foreground", children: [_jsx("span", { className: "flex shrink-0 items-center justify-center", children: icon ?? _jsx(XpodMark, { size: 24 }) }), _jsxs("span", { className: "min-w-0 truncate font-medium", children: [serviceName, " \u00B7 ", label] }), serviceHost ? _jsx("span", { className: "ml-auto truncate font-mono text-xs text-muted-foreground", children: serviceHost }) : null] }));
8
8
  }
@@ -31,7 +31,7 @@ export function IdpSignInView(props) {
31
31
  if (!pending)
32
32
  onSubmit({ email: email.trim(), password });
33
33
  };
34
- return (_jsxs(ScreenLayout, { "data-pod-sign-in-state": "idp-sign-in", chrome: _jsx(IdpFrameHeader, { ...props }), onSubmit: submit, actions: (_jsxs(_Fragment, { children: [error ? _jsx("p", { role: "alert", className: "text-[13px] text-destructive", children: error }) : null, _jsx(ActionButton, { type: "submit", className: primaryButtonClass, busy: pending, children: copy.signIn }), _jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [onRegister || registerHref ? (_jsxs("span", { className: "flex min-w-0 flex-wrap items-center gap-x-1 gap-y-0", children: [_jsx("span", { className: "whitespace-nowrap text-xs text-muted-foreground", children: copy.noAccount }), _jsx(TextAction, { href: registerHref, disabled: pending, onClick: onRegister, children: copy.registerLink })] })) : _jsx("span", {}), onUseOtherSolid ? (_jsx("button", { type: "button", className: cn(textButtonClass, 'text-primary hover:underline'), disabled: pending, onClick: onUseOtherSolid, children: copy.useOtherSolid })) : null] })] })), children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("h1", { className: "text-[17px] font-semibold text-foreground", children: formatCopy(copy.signInTitle, { service: serviceName }) }), returnToAppName ? (_jsx("p", { className: "text-sm text-muted-foreground", children: formatCopy(copy.returnToApp, { app: returnToAppName }) })) : null] }), _jsxs("div", { "data-pod-sign-in": "fields", className: "flex flex-col gap-5", children: [_jsx(Field, { label: copy.email, error: fieldErrors?.email, children: (fieldProps) => (_jsx(EmailInput, { ...fieldProps, name: "email", autoComplete: "username", autoCapitalize: "none", spellCheck: false, className: inputClass, value: email, disabled: pending, onChange: (event) => {
34
+ return (_jsxs(ScreenLayout, { "data-pod-sign-in-state": "idp-sign-in", chrome: _jsx(IdpFrameHeader, { ...props }), onSubmit: submit, actions: (_jsxs(_Fragment, { children: [error ? _jsx("p", { role: "alert", className: "text-[13px] text-destructive", children: error }) : null, _jsx(ActionButton, { type: "submit", className: primaryButtonClass, busy: pending, children: copy.signIn }), _jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [onRegister || registerHref ? (_jsxs("span", { className: "flex min-w-0 flex-wrap items-center gap-x-1 gap-y-0", children: [_jsx("span", { className: "whitespace-nowrap text-xs text-muted-foreground", children: copy.noAccount }), _jsx(TextAction, { href: registerHref, disabled: pending, onClick: onRegister, children: copy.registerLink })] })) : _jsx("span", {}), onUseOtherSolid ? (_jsx("button", { type: "button", className: cn(textButtonClass, 'text-primary hover:underline'), disabled: pending, onClick: onUseOtherSolid, children: copy.useOtherSolid })) : null] })] })), children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("h1", { className: "text-[17px] font-semibold text-foreground", children: formatCopy(copy.signInTitle, { service: serviceName }) }), returnToAppName ? (_jsx("p", { className: "text-sm text-muted-foreground", children: formatCopy(copy.returnToApp, { app: returnToAppName }) })) : null] }), _jsxs("div", { "data-pod-sign-in": "fields", className: "flex flex-col gap-4", children: [_jsx(Field, { label: copy.email, error: fieldErrors?.email, children: (fieldProps) => (_jsx(EmailInput, { ...fieldProps, name: "email", autoComplete: "username", autoCapitalize: "none", spellCheck: false, className: inputClass, value: email, disabled: pending, onChange: (event) => {
35
35
  setEmail(event.target.value);
36
36
  onFieldChange?.('email', event.target.value);
37
37
  } })) }), _jsx(Field, { label: copy.password, error: fieldErrors?.password, labelAside: onForgot || forgotHref ? (_jsx(TextAction, { className: "min-h-7 text-[13px]", href: forgotHref, onClick: onForgot, children: copy.forgotPassword })) : undefined, children: (fieldProps) => (_jsx(Input, { ...fieldProps, name: "password", type: "password", autoComplete: "current-password", className: inputClass, value: password, disabled: pending, onChange: (event) => {
@@ -56,7 +56,7 @@ export function IdpRegisterView(props) {
56
56
  password,
57
57
  });
58
58
  };
59
- return (_jsxs(ScreenLayout, { "data-pod-sign-in-state": "idp-register", chrome: _jsx(IdpFrameHeader, { ...props }), onSubmit: submit, actions: (_jsxs(_Fragment, { children: [error ? _jsx("p", { role: "alert", className: "text-[13px] text-destructive", children: error }) : null, _jsx(ActionButton, { type: "submit", className: primaryButtonClass, busy: pending, children: copy.registerSubmit }), onSignIn ? (_jsx("button", { type: "button", className: cn(textButtonClass, 'self-center text-primary hover:underline'), disabled: pending, onClick: onSignIn, children: copy.haveAccount })) : null] })), children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("h1", { className: "text-[17px] font-semibold text-foreground", children: formatCopy(copy.registerTitle, { service: serviceName }) }), returnToAppName ? (_jsx("p", { className: "text-sm text-muted-foreground", children: formatCopy(copy.returnToApp, { app: returnToAppName }) })) : null] }), _jsxs("div", { className: "flex flex-col gap-5", children: [requireUsername ? (_jsx(Field, { label: copy.username, error: fieldErrors?.username, hint: usernamePreview ? _jsx("span", { role: "status", className: "font-mono text-xs", children: usernamePreview }) : undefined, children: (fieldProps) => (_jsx(Input, { ...fieldProps, name: "username", type: "text", autoComplete: "username", autoCapitalize: "none", spellCheck: false, className: inputClass, value: username, disabled: pending, onChange: (event) => {
59
+ return (_jsxs(ScreenLayout, { "data-pod-sign-in-state": "idp-register", chrome: _jsx(IdpFrameHeader, { ...props }), onSubmit: submit, actions: (_jsxs(_Fragment, { children: [error ? _jsx("p", { role: "alert", className: "text-[13px] text-destructive", children: error }) : null, _jsx(ActionButton, { type: "submit", className: primaryButtonClass, busy: pending, children: copy.registerSubmit }), onSignIn ? (_jsx("button", { type: "button", className: cn(textButtonClass, 'self-center text-primary hover:underline'), disabled: pending, onClick: onSignIn, children: copy.haveAccount })) : null] })), children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("h1", { className: "text-[17px] font-semibold text-foreground", children: formatCopy(copy.registerTitle, { service: serviceName }) }), returnToAppName ? (_jsx("p", { className: "text-sm text-muted-foreground", children: formatCopy(copy.returnToApp, { app: returnToAppName }) })) : null] }), _jsxs("div", { className: "flex flex-col gap-4", children: [requireUsername ? (_jsx(Field, { label: copy.username, error: fieldErrors?.username, hint: usernamePreview ? _jsx("span", { role: "status", className: "font-mono text-xs", children: usernamePreview }) : undefined, children: (fieldProps) => (_jsx(Input, { ...fieldProps, name: "username", type: "text", autoComplete: "username", autoCapitalize: "none", spellCheck: false, className: inputClass, value: username, disabled: pending, onChange: (event) => {
60
60
  setUsername(event.target.value);
61
61
  onFieldChange?.('username', event.target.value);
62
62
  } })) })) : null, _jsx(Field, { label: copy.email, error: fieldErrors?.email, children: (fieldProps) => (_jsx(EmailInput, { ...fieldProps, name: "email", autoComplete: "email", autoCapitalize: "none", spellCheck: false, className: inputClass, value: email, disabled: pending, onChange: (event) => {
@@ -9,7 +9,7 @@ export interface PodSignInFrameProps {
9
9
  * service name.
10
10
  */
11
11
  appIntro?: ReactNode;
12
- /** A responsive body, up to 480px wide. */
12
+ /** The 360px wide body. */
13
13
  children: ReactNode;
14
14
  /**
15
15
  * `dialog` only. `true` (default) draws a modal layer over the document;
@@ -25,7 +25,7 @@ export interface PodSignInFrameProps {
25
25
  }
26
26
  /**
27
27
  * Outer frame of every sign-in surface. `window` fills the host window,
28
- * `dialog` is a 480px layer, `page` is two columns. All three share the same
29
- * responsive body, so narrower hosts keep the same controls and hierarchy.
28
+ * `dialog` is a 400px layer, `page` is two columns. All three share the same
29
+ * 360px body, so a state looks the same wherever the host places it.
30
30
  */
31
31
  export declare function PodSignInFrame({ presentation, ariaLabel, appIntro, children, modal, onClose, closeLabel, dataAttributes, }: PodSignInFrameProps): import("react").JSX.Element;
@@ -90,11 +90,11 @@ function useModalFocus(active, onClose) {
90
90
  }, [active]);
91
91
  return ref;
92
92
  }
93
- const bodyClass = 'flex min-h-0 w-full max-w-[480px] flex-1 flex-col';
93
+ const bodyClass = 'flex min-h-0 w-full max-w-[360px] flex-1 flex-col';
94
94
  /**
95
95
  * Outer frame of every sign-in surface. `window` fills the host window,
96
- * `dialog` is a 480px layer, `page` is two columns. All three share the same
97
- * responsive body, so narrower hosts keep the same controls and hierarchy.
96
+ * `dialog` is a 400px layer, `page` is two columns. All three share the same
97
+ * 360px body, so a state looks the same wherever the host places it.
98
98
  */
99
99
  export function PodSignInFrame({ presentation, ariaLabel, appIntro, children, modal = true, onClose, closeLabel, dataAttributes, }) {
100
100
  const isModal = presentation === 'dialog' && modal;
@@ -104,8 +104,8 @@ export function PodSignInFrame({ presentation, ariaLabel, appIntro, children, mo
104
104
  return (_jsx("div", { role: "region", "aria-label": ariaLabel, "data-pod-sign-in-frame": "window", ...dataAttributes, className: "pod-sign-in flex h-full min-h-0 w-full min-w-0 justify-center overflow-hidden bg-background text-foreground", children: _jsx("div", { className: bodyClass, children: children }) }));
105
105
  }
106
106
  if (presentation === 'page') {
107
- return (_jsxs("div", { role: "region", "aria-label": ariaLabel, "data-pod-sign-in-frame": "page", ...dataAttributes, className: "pod-sign-in grid min-h-[100dvh] w-full bg-background text-foreground md:grid-cols-2", children: [intro ? (_jsx("aside", { "data-pod-sign-in": "intro", className: "hidden flex-col justify-center gap-6 bg-[hsl(var(--sunken))] px-12 py-10 md:flex", children: intro })) : null, _jsx("div", { className: cn('flex min-w-0 items-center justify-center px-4 py-8', intro ? '' : 'md:col-span-2'), children: _jsx("div", { className: cn(bodyClass, 'min-h-[520px]'), children: children }) })] }));
107
+ return (_jsxs("div", { role: "region", "aria-label": ariaLabel, "data-pod-sign-in-frame": "page", ...dataAttributes, className: "pod-sign-in grid min-h-[100dvh] w-full bg-background text-foreground md:grid-cols-2", children: [intro ? (_jsx("aside", { "data-pod-sign-in": "intro", className: "hidden flex-col justify-center gap-6 bg-[hsl(var(--sunken))] px-12 py-10 md:flex", children: intro })) : null, _jsx("div", { className: cn('flex min-w-0 items-center justify-center px-4 py-8', intro ? '' : 'md:col-span-2'), children: _jsx("div", { className: bodyClass, children: children }) })] }));
108
108
  }
109
- const card = (_jsxs("div", { ref: dialogRef, role: isModal ? 'dialog' : 'region', "aria-modal": isModal ? true : undefined, "aria-label": ariaLabel, tabIndex: -1, "data-pod-sign-in-frame": "dialog", ...dataAttributes, className: cn('pod-sign-in relative flex min-h-[min(440px,90dvh)] max-h-[90dvh] w-[min(480px,calc(100vw-2rem))] flex-col overflow-hidden rounded-xl border border-border bg-card text-card-foreground shadow-lg focus:outline-none motion-safe:animate-in motion-safe:fade-in-0'), children: [isModal && onClose && closeLabel ? (_jsx("button", { type: "button", "aria-label": closeLabel, className: "absolute right-2 top-2 flex h-9 w-9 items-center justify-center rounded-lg text-muted-foreground hover:bg-accent", onClick: onClose, children: _jsx("span", { "aria-hidden": "true", children: "\u00D7" }) })) : null, _jsx("div", { className: cn(bodyClass, 'mx-auto'), children: children })] }));
109
+ const card = (_jsxs("div", { ref: dialogRef, role: isModal ? 'dialog' : 'region', "aria-modal": isModal ? true : undefined, "aria-label": ariaLabel, tabIndex: -1, "data-pod-sign-in-frame": "dialog", ...dataAttributes, className: cn('pod-sign-in relative flex max-h-[90dvh] w-[min(400px,calc(100vw-2rem))] flex-col overflow-hidden rounded-xl border border-border bg-card text-card-foreground shadow-lg focus:outline-none motion-safe:animate-in motion-safe:fade-in-0'), children: [isModal && onClose && closeLabel ? (_jsx("button", { type: "button", "aria-label": closeLabel, className: "absolute right-2 top-2 flex h-9 w-9 items-center justify-center rounded-lg text-muted-foreground hover:bg-accent", onClick: onClose, children: _jsx("span", { "aria-hidden": "true", children: "\u00D7" }) })) : null, _jsx("div", { className: cn(bodyClass, 'mx-auto'), children: children })] }));
110
110
  return isModal ? (_jsx("div", { className: "fixed inset-0 z-[var(--layer-modal)] flex items-center justify-center bg-background/80 p-4", children: card })) : (_jsx("div", { className: "flex w-full items-center justify-center p-4", children: card }));
111
111
  }
@@ -2,11 +2,11 @@ import { type ReactNode } from 'react';
2
2
  import { type ButtonProps } from '../button.js';
3
3
  import { type FormFieldProps } from '../form-field.js';
4
4
  import type { StorageLocation } from './types.js';
5
- /** Screen-level controls leave room for readable text and touch targets. */
6
- export declare const primaryButtonClass = "h-auto min-h-12 w-full whitespace-normal break-normal rounded-lg py-2 text-base font-medium leading-snug";
7
- export declare const outlineButtonClass = "h-auto min-h-12 w-full whitespace-normal break-normal rounded-lg py-2 text-base font-medium leading-snug";
8
- export declare const textButtonClass = "h-9 rounded-lg px-2 text-sm font-medium";
9
- export declare const fieldClass = "h-12 w-full rounded-lg border border-input bg-card px-4 text-base text-foreground placeholder:text-muted-foreground disabled:opacity-60";
5
+ /** Minimum hit targets (spec §5); content may grow when text is enlarged or wraps. */
6
+ export declare const primaryButtonClass = "h-auto min-h-11 w-full whitespace-normal break-normal rounded-lg py-2 text-sm font-medium leading-snug";
7
+ export declare const outlineButtonClass = "h-auto min-h-11 w-full whitespace-normal break-normal rounded-lg py-2 text-sm font-medium leading-snug";
8
+ export declare const textButtonClass = "h-auto min-h-9 max-w-full whitespace-normal break-normal rounded-lg px-2 py-1 text-sm font-medium leading-snug";
9
+ export declare const fieldClass = "h-11 w-full rounded-lg border border-input bg-card px-3 text-sm text-foreground placeholder:text-muted-foreground disabled:opacity-60";
10
10
  export declare function Spinner({ className }: {
11
11
  className?: string;
12
12
  }): import("react").JSX.Element;
@@ -7,11 +7,11 @@ import { cn } from '../utils.js';
7
7
  import { FormField } from '../form-field.js';
8
8
  import { Checkbox } from '../checkbox.js';
9
9
  import { StorageBadge } from './StorageBadge.js';
10
- /** Screen-level controls leave room for readable text and touch targets. */
11
- export const primaryButtonClass = 'h-auto min-h-12 w-full whitespace-normal break-normal rounded-lg py-2 text-base font-medium leading-snug';
10
+ /** Minimum hit targets (spec §5); content may grow when text is enlarged or wraps. */
11
+ export const primaryButtonClass = 'h-auto min-h-11 w-full whitespace-normal break-normal rounded-lg py-2 text-sm font-medium leading-snug';
12
12
  export const outlineButtonClass = primaryButtonClass;
13
- export const textButtonClass = 'h-9 rounded-lg px-2 text-sm font-medium';
14
- export const fieldClass = 'h-12 w-full rounded-lg border border-input bg-card px-4 text-base text-foreground placeholder:text-muted-foreground disabled:opacity-60';
13
+ export const textButtonClass = 'h-auto min-h-9 max-w-full whitespace-normal break-normal rounded-lg px-2 py-1 text-sm font-medium leading-snug';
14
+ export const fieldClass = 'h-11 w-full rounded-lg border border-input bg-card px-3 text-sm text-foreground placeholder:text-muted-foreground disabled:opacity-60';
15
15
  export function Spinner({ className }) {
16
16
  return _jsx(Loader2, { "aria-hidden": "true", className: cn('h-4 w-4 shrink-0 animate-spin motion-reduce:animate-none', className) });
17
17
  }
@@ -55,7 +55,7 @@ export function usePastDelay(delayMs) {
55
55
  * Pass `onSubmit` to make the whole screen one form (actions submit it).
56
56
  */
57
57
  export function ScreenLayout({ chrome, children, actions, onSubmit, mainClassName, ...state }) {
58
- const inner = (_jsxs(_Fragment, { children: [chrome, _jsx("div", { "data-pod-sign-in": "main", className: cn('flex min-h-0 flex-1 flex-col gap-7 overflow-y-auto px-6 pb-3 pt-7 min-[400px]:px-8 min-[400px]:pt-8', mainClassName), children: children }), actions ? _jsx("div", { "data-pod-sign-in": "actions", className: "flex shrink-0 flex-col gap-4 px-6 pb-7 pt-5 min-[400px]:px-8 min-[400px]:pb-8", children: actions }) : null] }));
58
+ const inner = (_jsxs(_Fragment, { children: [chrome, _jsx("div", { "data-pod-sign-in": "main", className: cn('flex min-h-0 flex-1 flex-col gap-5 overflow-y-auto px-6 pb-2 pt-5', mainClassName), children: children }), actions ? _jsx("div", { "data-pod-sign-in": "actions", className: "flex shrink-0 flex-col gap-3 px-6 pb-6 pt-3", children: actions }) : null] }));
59
59
  const className = 'flex min-h-0 flex-1 flex-col';
60
60
  return onSubmit
61
61
  ? _jsx("form", { ...state, onSubmit: onSubmit, className: className, noValidate: true, children: inner })
@@ -6,5 +6,5 @@ import { cn } from './utils.js';
6
6
  */
7
7
  export function SectionHeader({ title, description, actions, level = 2, titleClassName, className, ...props }) {
8
8
  const headingClassName = cn('text-sm leading-normal text-foreground', titleClassName);
9
- return (_jsxs("div", { ...props, className: cn('flex flex-wrap items-start justify-between gap-3', className), children: [_jsxs("div", { className: "min-w-0", children: [level === 3 ? (_jsx("h3", { className: headingClassName, children: title })) : level === 4 ? (_jsx("h4", { className: headingClassName, children: title })) : (_jsx("h2", { className: headingClassName, children: title })), description ? _jsx("p", { className: "mt-1 text-xs leading-normal text-muted-foreground", children: description }) : null] }), actions ? _jsx("div", { className: "flex shrink-0 flex-wrap items-center gap-2", children: actions }) : null] }));
9
+ return (_jsxs("div", { ...props, className: cn('flex flex-wrap items-start justify-between gap-3', className), children: [_jsxs("div", { className: "min-w-0", children: [level === 3 ? (_jsx("h3", { className: headingClassName, children: title })) : level === 4 ? (_jsx("h4", { className: headingClassName, children: title })) : (_jsx("h2", { className: headingClassName, children: title })), description ? _jsx("p", { className: "mt-1 text-xs leading-normal text-muted-foreground", children: description }) : null] }), actions ? _jsx("div", { className: "flex min-w-0 max-w-full flex-wrap items-center gap-2", children: actions }) : null] }));
10
10
  }
@@ -314,33 +314,6 @@
314
314
  line-height: 22px;
315
315
  }
316
316
 
317
- .pod-sign-in h1 {
318
- font-size: 22px;
319
- line-height: 1.4;
320
- }
321
-
322
- /* Keep the choices visible at the native window's minimum height. */
323
- @media (max-height: 559px) {
324
- .pod-sign-in[data-pod-sign-in-frame='window'] [data-pod-sign-in='main'] {
325
- gap: 1rem;
326
- padding-top: 1rem;
327
- padding-bottom: 0.5rem;
328
- }
329
-
330
- .pod-sign-in[data-pod-sign-in-frame='window'] [data-pod-sign-in='actions'] {
331
- gap: 0.75rem;
332
- padding-top: 0.75rem;
333
- padding-bottom: 1rem;
334
- }
335
- }
336
-
337
- /* Taller native windows keep the submit action close to the form. */
338
- @media (min-width: 400px) and (min-height: 560px) {
339
- .pod-sign-in[data-pod-sign-in-frame='window'] [data-pod-sign-in='actions'] {
340
- padding-bottom: 5rem;
341
- }
342
- }
343
-
344
317
  /*
345
318
  * Front-door focus for links, buttons and summary. Form controls are excluded:
346
319
  * the shared control primitive owns their focus outline, so a control never
@@ -364,21 +337,21 @@
364
337
  [data-pod-sign-in-frame="window"] [data-pod-sign-in-state="idp-sign-in"] [data-pod-sign-in="main"] {
365
338
  flex: 1 0 auto;
366
339
  overflow: visible;
367
- gap: 8px;
368
- padding: 8px 16px;
340
+ gap: 6px;
341
+ padding: 4px 16px 2px;
369
342
  }
370
343
 
371
344
  [data-pod-sign-in-frame="window"] [data-pod-sign-in-state="idp-sign-in"] [data-pod-sign-in="fields"] {
372
- gap: 8px;
345
+ gap: 6px;
373
346
  }
374
347
 
375
348
  [data-pod-sign-in-frame="window"] [data-pod-sign-in-state="idp-sign-in"] [data-pod-sign-in="field"] {
376
- gap: 2px;
349
+ gap: 1px;
377
350
  }
378
351
 
379
352
  [data-pod-sign-in-frame="window"] [data-pod-sign-in-state="idp-sign-in"] [data-pod-sign-in="actions"] {
380
353
  gap: 0;
381
- padding: 8px 16px;
354
+ padding: 4px 16px 6px;
382
355
  }
383
356
 
384
357
  @media (prefers-reduced-motion: reduce) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@undefineds.co/shared-ui",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@undefineds.co/solid-sdk",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "sideEffects": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@undefineds.co/xpod",
3
- "version": "0.4.25",
3
+ "version": "0.4.27",
4
4
  "description": "Xpod is an extended Community Solid Server, offering rich-feature, production-level Solid Pod and identity management.",
5
5
  "repository": "https://github.com/undefinedsco/xpod",
6
6
  "author": "developer@undefineds.co",
@@ -387,7 +387,7 @@
387
387
  }
388
388
  },
389
389
  "optionalDependencies": {
390
- "@undefineds.co/xpod-darwin-arm64": "0.4.25"
390
+ "@undefineds.co/xpod-darwin-arm64": "0.4.27"
391
391
  },
392
392
  "resolutions": {
393
393
  "@inrupt/solid-client-authn-browser": "^3.1.1",