@burdenoff/microfe-proserviceworld 2026.1009.1 → 2026.1014.1

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 (56) hide show
  1. package/dist/generated/wspace-types.d.ts +98750 -26838
  2. package/dist/generated/wspace-types.d.ts.map +1 -1
  3. package/dist/proserviceworld/ProServiceWorldRoot.d.ts.map +1 -1
  4. package/dist/proserviceworld/ProServiceWorldRoot.js +6 -0
  5. package/dist/proserviceworld/ProServiceWorldRoot.js.map +1 -1
  6. package/dist/proserviceworld/ProServiceWorldRoutes.d.ts.map +1 -1
  7. package/dist/proserviceworld/ProServiceWorldRoutes.js +42 -35
  8. package/dist/proserviceworld/ProServiceWorldRoutes.js.map +1 -1
  9. package/dist/proserviceworld/components/CredentialDirectory.d.ts +3 -0
  10. package/dist/proserviceworld/components/CredentialDirectory.d.ts.map +1 -0
  11. package/dist/proserviceworld/components/CredentialDirectory.js +253 -0
  12. package/dist/proserviceworld/components/CredentialDirectory.js.map +1 -0
  13. package/dist/proserviceworld/components/CredentialEvidencePicker.d.ts +9 -0
  14. package/dist/proserviceworld/components/CredentialEvidencePicker.d.ts.map +1 -0
  15. package/dist/proserviceworld/components/CredentialEvidencePicker.js +161 -0
  16. package/dist/proserviceworld/components/CredentialEvidencePicker.js.map +1 -0
  17. package/dist/proserviceworld/components/CredentialRecordForm.d.ts +24 -0
  18. package/dist/proserviceworld/components/CredentialRecordForm.d.ts.map +1 -0
  19. package/dist/proserviceworld/components/CredentialRecordForm.js +251 -0
  20. package/dist/proserviceworld/components/CredentialRecordForm.js.map +1 -0
  21. package/dist/proserviceworld/components/CredentialReferencePicker.d.ts +22 -0
  22. package/dist/proserviceworld/components/CredentialReferencePicker.d.ts.map +1 -0
  23. package/dist/proserviceworld/components/CredentialReferencePicker.js +122 -0
  24. package/dist/proserviceworld/components/CredentialReferencePicker.js.map +1 -0
  25. package/dist/proserviceworld/components/CredentialReminderPanel.d.ts +5 -0
  26. package/dist/proserviceworld/components/CredentialReminderPanel.d.ts.map +1 -0
  27. package/dist/proserviceworld/components/CredentialReminderPanel.js +141 -0
  28. package/dist/proserviceworld/components/CredentialReminderPanel.js.map +1 -0
  29. package/dist/proserviceworld/components/credentialFormDefinitions.d.ts +4 -0
  30. package/dist/proserviceworld/components/credentialFormDefinitions.d.ts.map +1 -0
  31. package/dist/proserviceworld/components/credentialFormDefinitions.js +344 -0
  32. package/dist/proserviceworld/components/credentialFormDefinitions.js.map +1 -0
  33. package/dist/proserviceworld/hooks/credentialWrites.d.ts +16 -0
  34. package/dist/proserviceworld/hooks/credentialWrites.d.ts.map +1 -0
  35. package/dist/proserviceworld/hooks/credentialWrites.js +38 -0
  36. package/dist/proserviceworld/hooks/credentialWrites.js.map +1 -0
  37. package/dist/proserviceworld/hooks/usePractitionerCredentials.d.ts +41 -0
  38. package/dist/proserviceworld/hooks/usePractitionerCredentials.d.ts.map +1 -0
  39. package/dist/proserviceworld/hooks/usePractitionerCredentials.js +105 -0
  40. package/dist/proserviceworld/hooks/usePractitionerCredentials.js.map +1 -0
  41. package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts +1 -0
  42. package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts.map +1 -1
  43. package/dist/proserviceworld/hooks/useProServiceWorldApi.js +3 -2
  44. package/dist/proserviceworld/hooks/useProServiceWorldApi.js.map +1 -1
  45. package/dist/proserviceworld/pages/PractitionerCredentialsPage.d.ts +2 -0
  46. package/dist/proserviceworld/pages/PractitionerCredentialsPage.d.ts.map +1 -0
  47. package/dist/proserviceworld/pages/PractitionerCredentialsPage.js +268 -0
  48. package/dist/proserviceworld/pages/PractitionerCredentialsPage.js.map +1 -0
  49. package/dist/proserviceworld/utils/credentialSourceLink.d.ts +3 -0
  50. package/dist/proserviceworld/utils/credentialSourceLink.d.ts.map +1 -0
  51. package/dist/proserviceworld/utils/credentialSourceLink.js +17 -0
  52. package/dist/proserviceworld/utils/credentialSourceLink.js.map +1 -0
  53. package/dist/proserviceworld/utils/native.d.ts +2 -6
  54. package/dist/proserviceworld/utils/native.d.ts.map +1 -1
  55. package/dist/proserviceworld/utils/native.js.map +1 -1
  56. package/package.json +21 -5
@@ -0,0 +1,268 @@
1
+ import { useProServiceWorld as e } from "../providers/ProServiceWorldProvider.js";
2
+ import { Banner as t, Empty as n, ErrorState as r, LoadingBlock as i, PageHeader as a, SectionCard as o, TableWrap as s, Td as c, Th as l, humanize as u } from "../components/ui.js";
3
+ import { CredentialReminderPanel as d } from "../components/CredentialReminderPanel.js";
4
+ import { useCredentialReviews as f, usePractitionerCredentials as p } from "../hooks/usePractitionerCredentials.js";
5
+ import { credentialSourceLink as m } from "../utils/credentialSourceLink.js";
6
+ import { CredentialDirectory as h } from "../components/CredentialDirectory.js";
7
+ import { CredentialRecordForm as g } from "../components/CredentialRecordForm.js";
8
+ import { CREDENTIAL_FORMS as _ } from "../components/credentialFormDefinitions.js";
9
+ import { useState as v } from "react";
10
+ import { BadgeCheck as y, RefreshCw as b } from "lucide-react";
11
+ import { Fragment as x, jsx as S, jsxs as C } from "react/jsx-runtime";
12
+ import { Button as w } from "@burdenoff/fe-libs/ui";
13
+ //#region src/proserviceworld/pages/PractitionerCredentialsPage.tsx
14
+ function T() {
15
+ let { workspaceId: T, tenantId: E, currentUser: D } = e(), O = JSON.stringify([
16
+ E,
17
+ T,
18
+ D?.id
19
+ ]), [k, A] = v({
20
+ scope: O,
21
+ offset: 0
22
+ }), [j, M] = v(null), N = k.scope === O ? k.offset : 0, P = p(N), F = P.data?.items ?? [], I = j?.scope === O ? F.find((e) => e.id === j.id) : void 0, [L, R] = v(null), z = L?.scope === O && L.credentialId === I?.id ? L.offset : 0, B = f(I?.id, z, j?.scope === O ? j.asOf : void 0), V = B.data?.items ?? [], H = !!(E && T && D?.id), [U, W] = v(0), [G, K] = v(null), q = _[U] ?? _[0];
23
+ return /* @__PURE__ */ C("div", {
24
+ className: "space-y-6",
25
+ children: [
26
+ /* @__PURE__ */ S(a, {
27
+ title: "Practitioner credentials",
28
+ subtitle: "Issuers, jurisdictions and source observations recorded by your firm.",
29
+ icon: /* @__PURE__ */ S(y, { className: "h-6 w-6" }),
30
+ actions: /* @__PURE__ */ C(w, {
31
+ variant: "outline",
32
+ disabled: !H || P.isFetching,
33
+ onClick: () => void P.refetch(),
34
+ children: [/* @__PURE__ */ S(b, { className: "mr-2 h-4 w-4" }), "Refresh"]
35
+ })
36
+ }),
37
+ /* @__PURE__ */ S(t, {
38
+ tone: "info",
39
+ children: "Recorded evidence and source reviews do not certify legal authority to practise."
40
+ }),
41
+ H && /* @__PURE__ */ C(x, { children: [
42
+ /* @__PURE__ */ S(h, {}, `directory:${O}`),
43
+ /* @__PURE__ */ S(d, { preparedId: G?.scope === O ? G.id : void 0 }, `reminder:${O}:${G?.scope === O ? G.id : ""}`),
44
+ /* @__PURE__ */ C("label", {
45
+ className: "block text-sm font-medium",
46
+ children: ["Record an action", /* @__PURE__ */ S("select", {
47
+ className: "mt-1 block w-full rounded border border-border bg-bg-surface p-2",
48
+ value: U,
49
+ onChange: (e) => W(Number(e.target.value)),
50
+ children: _.map((e, t) => /* @__PURE__ */ S("option", {
51
+ value: t,
52
+ children: e.title
53
+ }, e.operation))
54
+ })]
55
+ }),
56
+ q && /* @__PURE__ */ S(g, {
57
+ scope: O,
58
+ definition: q,
59
+ onPreparedReminder: (e) => K({
60
+ scope: O,
61
+ id: e
62
+ })
63
+ }, `${O}:${q.operation}`)
64
+ ] }),
65
+ H ? P.isLoading ? /* @__PURE__ */ S(i, {}) : P.error ? /* @__PURE__ */ S(r, {
66
+ error: P.error,
67
+ onRetry: () => void P.refetch()
68
+ }) : F.length === 0 ? /* @__PURE__ */ S(n, {
69
+ title: "No credential records",
70
+ description: "This firm has no recorded practitioner credentials on this page."
71
+ }) : /* @__PURE__ */ C(o, {
72
+ title: `${P.data?.totalCount ?? F.length} recorded credentials`,
73
+ children: [/* @__PURE__ */ C(s, { children: [/* @__PURE__ */ S("thead", { children: /* @__PURE__ */ C("tr", { children: [
74
+ /* @__PURE__ */ S(l, { children: "Credential" }),
75
+ /* @__PURE__ */ S(l, { children: "Jurisdiction" }),
76
+ /* @__PURE__ */ S(l, { children: "Practice scope" }),
77
+ /* @__PURE__ */ S(l, { children: "Recorded validity" }),
78
+ /* @__PURE__ */ S(l, { children: "Recorded expiry" }),
79
+ /* @__PURE__ */ S(l, { children: "Reviews" })
80
+ ] }) }), /* @__PURE__ */ S("tbody", { children: F.map((e) => /* @__PURE__ */ C("tr", { children: [
81
+ /* @__PURE__ */ C(c, { children: [e.identifier, /* @__PURE__ */ C("span", {
82
+ className: "block break-all text-xs",
83
+ children: [
84
+ "ID: ",
85
+ e.id,
86
+ " · Revision ",
87
+ e.revision
88
+ ]
89
+ })] }),
90
+ /* @__PURE__ */ S(c, { children: e.jurisdiction }),
91
+ /* @__PURE__ */ S(c, { children: e.practiceScope }),
92
+ /* @__PURE__ */ S(c, { children: u(e.validityKind) }),
93
+ /* @__PURE__ */ C(c, { children: [e.expiresAt ?? (e.validityKind === "NO_EXPIRY_REPORTED" ? "No expiry reported" : "Unknown"), /* @__PURE__ */ C("span", {
94
+ className: "block text-xs text-text-tertiary",
95
+ children: ["Source zone: ", e.sourceTimezone]
96
+ })] }),
97
+ /* @__PURE__ */ S(c, { children: /* @__PURE__ */ S(w, {
98
+ size: "sm",
99
+ variant: "outline",
100
+ onClick: () => M({
101
+ scope: O,
102
+ id: e.id,
103
+ asOf: (/* @__PURE__ */ new Date()).toISOString()
104
+ }),
105
+ children: "Status and history"
106
+ }) })
107
+ ] }, e.id)) })] }), /* @__PURE__ */ C("div", {
108
+ className: "mt-4 flex flex-wrap items-center justify-between gap-3",
109
+ children: [
110
+ /* @__PURE__ */ S(w, {
111
+ variant: "outline",
112
+ disabled: N === 0 || P.isFetching,
113
+ onClick: () => A({
114
+ scope: O,
115
+ offset: Math.max(0, N - 25)
116
+ }),
117
+ children: "Previous"
118
+ }),
119
+ /* @__PURE__ */ C("span", {
120
+ className: "text-sm text-text-secondary",
121
+ children: ["Page ", Math.floor(N / 25) + 1]
122
+ }),
123
+ /* @__PURE__ */ S(w, {
124
+ variant: "outline",
125
+ disabled: !P.data?.hasMore || P.isFetching,
126
+ onClick: () => A({
127
+ scope: O,
128
+ offset: N + 25
129
+ }),
130
+ children: "Next"
131
+ })
132
+ ]
133
+ })]
134
+ }) : /* @__PURE__ */ S(n, {
135
+ title: "Choose a workspace",
136
+ description: "Sign in and choose the firm workspace to view its credential records."
137
+ }),
138
+ I && /* @__PURE__ */ C(o, {
139
+ title: `Recorded status and history: ${I.identifier}`,
140
+ children: [
141
+ B.data?.readiness && /* @__PURE__ */ C("div", {
142
+ className: "mb-4 space-y-2",
143
+ children: [
144
+ /* @__PURE__ */ S("p", {
145
+ className: "font-semibold",
146
+ children: u(B.data.readiness.recordedState)
147
+ }),
148
+ /* @__PURE__ */ C("p", {
149
+ className: "text-sm",
150
+ children: [
151
+ "As of ",
152
+ B.data.readiness.asOf,
153
+ " · Credential revision",
154
+ " ",
155
+ B.data.readiness.revision
156
+ ]
157
+ }),
158
+ /* @__PURE__ */ C("p", { children: [
159
+ "Source observation: ",
160
+ u(B.data.readiness.observation),
161
+ " ·",
162
+ " ",
163
+ B.data.readiness.reviewIsForCurrentRevision ? "Review matches current recorded facts" : "Current facts need a source review"
164
+ ] }),
165
+ /* @__PURE__ */ S("p", {
166
+ className: "text-sm",
167
+ children: "Legal authorization is not certified. No automatic source-freshness interval is assumed."
168
+ }),
169
+ /* @__PURE__ */ S(w, {
170
+ variant: "outline",
171
+ disabled: B.isFetching,
172
+ onClick: () => M({
173
+ scope: O,
174
+ id: I.id,
175
+ asOf: (/* @__PURE__ */ new Date()).toISOString()
176
+ }),
177
+ children: "Refresh recorded status"
178
+ })
179
+ ]
180
+ }),
181
+ B.isLoading ? /* @__PURE__ */ S(i, {}) : B.error ? /* @__PURE__ */ S(r, {
182
+ error: B.error,
183
+ onRetry: () => void B.refetch()
184
+ }) : V.length === 0 ? /* @__PURE__ */ S("p", { children: "No source review has been recorded. Authority remains unknown." }) : /* @__PURE__ */ S("div", {
185
+ className: "space-y-4",
186
+ children: V.map((e) => {
187
+ let t = m(e.sourceUrl);
188
+ return /* @__PURE__ */ C("article", {
189
+ className: "min-w-0 rounded-xl border border-border p-4",
190
+ children: [
191
+ /* @__PURE__ */ S("h3", {
192
+ className: "font-semibold",
193
+ children: u(e.observation)
194
+ }),
195
+ /* @__PURE__ */ C("p", {
196
+ className: "text-sm text-text-secondary",
197
+ children: [
198
+ "Observed ",
199
+ e.checkedAt,
200
+ " · Revision ",
201
+ e.credentialRevision,
202
+ e.credentialRevision === I.revision ? "" : " · Previous credential facts"
203
+ ]
204
+ }),
205
+ /* @__PURE__ */ S("p", {
206
+ className: "mt-2 whitespace-pre-wrap break-words",
207
+ children: e.note
208
+ }),
209
+ t ? /* @__PURE__ */ C("a", {
210
+ href: t,
211
+ target: "_blank",
212
+ rel: "noopener noreferrer",
213
+ className: "mt-2 block break-all underline",
214
+ children: ["Source reference: ", new URL(t).hostname]
215
+ }) : /* @__PURE__ */ S("p", {
216
+ className: "mt-2 text-sm",
217
+ children: "Source reference unavailable."
218
+ }),
219
+ /* @__PURE__ */ C("p", {
220
+ className: "mt-2 break-all text-xs text-text-secondary",
221
+ children: ["Evidence version: ", e.evidenceVersionId]
222
+ }),
223
+ /* @__PURE__ */ C("p", {
224
+ className: "break-all text-xs text-text-secondary",
225
+ children: ["SHA-256: ", e.evidenceSha256]
226
+ })
227
+ ]
228
+ }, e.id);
229
+ })
230
+ }),
231
+ /* @__PURE__ */ C("div", {
232
+ className: "mt-4 flex flex-wrap items-center justify-between gap-3",
233
+ children: [
234
+ /* @__PURE__ */ S(w, {
235
+ variant: "outline",
236
+ disabled: z === 0 || B.isFetching,
237
+ onClick: () => R({
238
+ scope: O,
239
+ credentialId: I.id,
240
+ offset: Math.max(0, z - 25)
241
+ }),
242
+ children: "Previous reviews"
243
+ }),
244
+ /* @__PURE__ */ C("span", {
245
+ className: "text-sm text-text-secondary",
246
+ children: ["Review page ", Math.floor(z / 25) + 1]
247
+ }),
248
+ /* @__PURE__ */ S(w, {
249
+ variant: "outline",
250
+ disabled: !B.data?.hasMore || B.isFetching,
251
+ onClick: () => R({
252
+ scope: O,
253
+ credentialId: I.id,
254
+ offset: z + 25
255
+ }),
256
+ children: "Next reviews"
257
+ })
258
+ ]
259
+ })
260
+ ]
261
+ })
262
+ ]
263
+ });
264
+ }
265
+ //#endregion
266
+ export { T as PractitionerCredentialsPage };
267
+
268
+ //# sourceMappingURL=PractitionerCredentialsPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PractitionerCredentialsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/PractitionerCredentialsPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { BadgeCheck, RefreshCw } from 'lucide-react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { CredentialReminderPanel } from '../components/CredentialReminderPanel';\nimport { CredentialDirectory } from '../components/CredentialDirectory';\nimport { CredentialRecordForm } from '../components/CredentialRecordForm';\nimport { CREDENTIAL_FORMS } from '../components/credentialFormDefinitions';\nimport { credentialSourceLink } from '../utils/credentialSourceLink';\nimport { useProServiceWorld } from '../providers/ProServiceWorldProvider';\nimport {\n usePractitionerCredentials,\n useCredentialReviews,\n} from '../hooks/usePractitionerCredentials';\nimport {\n Banner,\n Empty,\n ErrorState,\n LoadingBlock,\n PageHeader,\n SectionCard,\n TableWrap,\n Th,\n Td,\n humanize,\n} from '../components/ui';\n\nexport function PractitionerCredentialsPage() {\n const { workspaceId, tenantId, currentUser } = useProServiceWorld();\n const scope = JSON.stringify([tenantId, workspaceId, currentUser?.id]);\n const [page, setPage] = useState({ scope, offset: 0 });\n const [selection, setSelection] = useState<{ scope: string; id: string; asOf: string } | null>(\n null\n );\n const offset = page.scope === scope ? page.offset : 0;\n const query = usePractitionerCredentials(offset);\n const items = query.data?.items ?? [];\n const selected =\n selection?.scope === scope ? items.find((item) => item.id === selection.id) : undefined;\n const [reviewPage, setReviewPage] = useState<{\n scope: string;\n credentialId: string;\n offset: number;\n } | null>(null);\n const reviewOffset =\n reviewPage?.scope === scope && reviewPage.credentialId === selected?.id ? reviewPage.offset : 0;\n const history = useCredentialReviews(\n selected?.id,\n reviewOffset,\n selection?.scope === scope ? selection.asOf : undefined\n );\n const reviews = history.data?.items ?? [];\n const ready = Boolean(tenantId && workspaceId && currentUser?.id);\n const [formSelection, setFormSelection] = useState(0);\n const [preparedReminder, setPreparedReminder] = useState<{ scope: string; id: string } | null>(\n null\n );\n const definition = CREDENTIAL_FORMS[formSelection] ?? CREDENTIAL_FORMS[0];\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title=\"Practitioner credentials\"\n subtitle=\"Issuers, jurisdictions and source observations recorded by your firm.\"\n icon={<BadgeCheck className=\"h-6 w-6\" />}\n actions={\n <Button\n variant=\"outline\"\n disabled={!ready || query.isFetching}\n onClick={() => void query.refetch()}\n >\n <RefreshCw className=\"mr-2 h-4 w-4\" />\n Refresh\n </Button>\n }\n />\n <Banner tone=\"info\">\n Recorded evidence and source reviews do not certify legal authority to practise.\n </Banner>\n {ready && (\n <>\n <CredentialDirectory key={`directory:${scope}`} />\n <CredentialReminderPanel\n key={`reminder:${scope}:${preparedReminder?.scope === scope ? preparedReminder.id : ''}`}\n preparedId={preparedReminder?.scope === scope ? preparedReminder.id : undefined}\n />\n <label className=\"block text-sm font-medium\">\n Record an action\n <select\n className=\"mt-1 block w-full rounded border border-border bg-bg-surface p-2\"\n value={formSelection}\n onChange={(event) => setFormSelection(Number(event.target.value))}\n >\n {CREDENTIAL_FORMS.map((form, index) => (\n <option key={form.operation} value={index}>\n {form.title}\n </option>\n ))}\n </select>\n </label>\n {definition && (\n <CredentialRecordForm\n key={`${scope}:${definition.operation}`}\n scope={scope}\n definition={definition}\n onPreparedReminder={(id) => setPreparedReminder({ scope, id })}\n />\n )}\n </>\n )}\n {!ready ? (\n <Empty\n title=\"Choose a workspace\"\n description=\"Sign in and choose the firm workspace to view its credential records.\"\n />\n ) : query.isLoading ? (\n <LoadingBlock />\n ) : query.error ? (\n <ErrorState error={query.error} onRetry={() => void query.refetch()} />\n ) : items.length === 0 ? (\n <Empty\n title=\"No credential records\"\n description=\"This firm has no recorded practitioner credentials on this page.\"\n />\n ) : (\n <SectionCard title={`${query.data?.totalCount ?? items.length} recorded credentials`}>\n <TableWrap>\n <thead>\n <tr>\n <Th>Credential</Th>\n <Th>Jurisdiction</Th>\n <Th>Practice scope</Th>\n <Th>Recorded validity</Th>\n <Th>Recorded expiry</Th>\n <Th>Reviews</Th>\n </tr>\n </thead>\n <tbody>\n {items.map((item) => (\n <tr key={item.id}>\n <Td>\n {item.identifier}\n <span className=\"block break-all text-xs\">\n ID: {item.id} · Revision {item.revision}\n </span>\n </Td>\n <Td>{item.jurisdiction}</Td>\n <Td>{item.practiceScope}</Td>\n <Td>{humanize(item.validityKind)}</Td>\n <Td>\n {item.expiresAt ??\n (item.validityKind === 'NO_EXPIRY_REPORTED'\n ? 'No expiry reported'\n : 'Unknown')}\n <span className=\"block text-xs text-text-tertiary\">\n Source zone: {item.sourceTimezone}\n </span>\n </Td>\n <Td>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() =>\n setSelection({ scope, id: item.id, asOf: new Date().toISOString() })\n }\n >\n Status and history\n </Button>\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n <div className=\"mt-4 flex flex-wrap items-center justify-between gap-3\">\n <Button\n variant=\"outline\"\n disabled={offset === 0 || query.isFetching}\n onClick={() => setPage({ scope, offset: Math.max(0, offset - 25) })}\n >\n Previous\n </Button>\n <span className=\"text-sm text-text-secondary\">Page {Math.floor(offset / 25) + 1}</span>\n <Button\n variant=\"outline\"\n disabled={!query.data?.hasMore || query.isFetching}\n onClick={() => setPage({ scope, offset: offset + 25 })}\n >\n Next\n </Button>\n </div>\n </SectionCard>\n )}\n {selected && (\n <SectionCard title={`Recorded status and history: ${selected.identifier}`}>\n {history.data?.readiness && (\n <div className=\"mb-4 space-y-2\">\n <p className=\"font-semibold\">{humanize(history.data.readiness.recordedState)}</p>\n <p className=\"text-sm\">\n As of {history.data.readiness.asOf} · Credential revision{' '}\n {history.data.readiness.revision}\n </p>\n <p>\n Source observation: {humanize(history.data.readiness.observation)} ·{' '}\n {history.data.readiness.reviewIsForCurrentRevision\n ? 'Review matches current recorded facts'\n : 'Current facts need a source review'}\n </p>\n <p className=\"text-sm\">\n Legal authorization is not certified. No automatic source-freshness interval is\n assumed.\n </p>\n <Button\n variant=\"outline\"\n disabled={history.isFetching}\n onClick={() =>\n setSelection({ scope, id: selected.id, asOf: new Date().toISOString() })\n }\n >\n Refresh recorded status\n </Button>\n </div>\n )}\n {history.isLoading ? (\n <LoadingBlock />\n ) : history.error ? (\n <ErrorState error={history.error} onRetry={() => void history.refetch()} />\n ) : reviews.length === 0 ? (\n <p>No source review has been recorded. Authority remains unknown.</p>\n ) : (\n <div className=\"space-y-4\">\n {reviews.map((review) => {\n const href = credentialSourceLink(review.sourceUrl);\n return (\n <article key={review.id} className=\"min-w-0 rounded-xl border border-border p-4\">\n <h3 className=\"font-semibold\">{humanize(review.observation)}</h3>\n <p className=\"text-sm text-text-secondary\">\n Observed {review.checkedAt} · Revision {review.credentialRevision}\n {review.credentialRevision !== selected.revision\n ? ' · Previous credential facts'\n : ''}\n </p>\n <p className=\"mt-2 whitespace-pre-wrap break-words\">{review.note}</p>\n {href ? (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mt-2 block break-all underline\"\n >\n Source reference: {new URL(href).hostname}\n </a>\n ) : (\n <p className=\"mt-2 text-sm\">Source reference unavailable.</p>\n )}\n <p className=\"mt-2 break-all text-xs text-text-secondary\">\n Evidence version: {review.evidenceVersionId}\n </p>\n <p className=\"break-all text-xs text-text-secondary\">\n SHA-256: {review.evidenceSha256}\n </p>\n </article>\n );\n })}\n </div>\n )}\n <div className=\"mt-4 flex flex-wrap items-center justify-between gap-3\">\n <Button\n variant=\"outline\"\n disabled={reviewOffset === 0 || history.isFetching}\n onClick={() =>\n setReviewPage({\n scope,\n credentialId: selected.id,\n offset: Math.max(0, reviewOffset - 25),\n })\n }\n >\n Previous reviews\n </Button>\n <span className=\"text-sm text-text-secondary\">\n Review page {Math.floor(reviewOffset / 25) + 1}\n </span>\n <Button\n variant=\"outline\"\n disabled={!history.data?.hasMore || history.isFetching}\n onClick={() =>\n setReviewPage({ scope, credentialId: selected.id, offset: reviewOffset + 25 })\n }\n >\n Next reviews\n </Button>\n </div>\n </SectionCard>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /** A source reference is a bounded human-opened HTTPS link, never fetched by this feature. */
2
+ export declare function credentialSourceLink(value: string): string | null;
3
+ //# sourceMappingURL=credentialSourceLink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentialSourceLink.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/utils/credentialSourceLink.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAejE"}
@@ -0,0 +1,17 @@
1
+ //#region src/proserviceworld/utils/credentialSourceLink.ts
2
+ function e(e) {
3
+ if (e.length > 2048 || Array.from(e).some((e) => {
4
+ let t = e.charCodeAt(0);
5
+ return t <= 31 || t === 127;
6
+ })) return null;
7
+ try {
8
+ let t = new URL(e);
9
+ return t.protocol === "https:" && !t.username && !t.password ? t.href : null;
10
+ } catch {
11
+ return null;
12
+ }
13
+ }
14
+ //#endregion
15
+ export { e as credentialSourceLink };
16
+
17
+ //# sourceMappingURL=credentialSourceLink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentialSourceLink.js","names":[],"sources":["../../../src/proserviceworld/utils/credentialSourceLink.ts"],"sourcesContent":["/** A source reference is a bounded human-opened HTTPS link, never fetched by this feature. */\nexport function credentialSourceLink(value: string): string | null {\n if (\n value.length > 2048 ||\n Array.from(value).some((character) => {\n const code = character.charCodeAt(0);\n return code <= 31 || code === 127;\n })\n )\n return null;\n try {\n const url = new URL(value);\n return url.protocol === 'https:' && !url.username && !url.password ? url.href : null;\n } catch {\n return null;\n }\n}\n"],"mappings":";AACA,SAAgB,EAAqB,GAA8B;CACjE,IACE,EAAM,SAAS,QACf,MAAM,KAAK,CAAK,CAAC,CAAC,MAAM,MAAc;EACpC,IAAM,IAAO,EAAU,WAAW,CAAC;EACnC,OAAO,KAAQ,MAAM,MAAS;CAChC,CAAC,GAED,OAAO;CACT,IAAI;EACF,IAAM,IAAM,IAAI,IAAI,CAAK;EACzB,OAAO,EAAI,aAAa,YAAY,CAAC,EAAI,YAAY,CAAC,EAAI,WAAW,EAAI,OAAO;CAClF,QAAQ;EACN,OAAO;CACT;AACF"}
@@ -1,3 +1,4 @@
1
+ import { BurdenoffNativeBridge } from '@burdenoff/fe-libs/shared/native';
1
2
  /**
2
3
  * ProServiceWorld native-bridge helpers.
3
4
  *
@@ -8,12 +9,7 @@
8
9
  export type HapticImpactStyle = 'light' | 'medium' | 'heavy';
9
10
  declare global {
10
11
  interface Window {
11
- __burdenoffNativeBridge?: {
12
- impact?: (style: HapticImpactStyle) => Promise<void>;
13
- notify?: (type: 'success' | 'warning' | 'error') => Promise<void>;
14
- toast?: (message: string, duration?: 'short' | 'long') => Promise<boolean>;
15
- isNativePlatform?: () => boolean;
16
- };
12
+ __burdenoffNativeBridge?: BurdenoffNativeBridge;
17
13
  }
18
14
  }
19
15
  export declare function impactFeedback(style?: HapticImpactStyle): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/utils/native.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE7D,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,uBAAuB,CAAC,EAAE;YACxB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;YACrD,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;YAClE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;YAC3E,gBAAgB,CAAC,EAAE,MAAM,OAAO,CAAC;SAClC,CAAC;KACH;CACF;AAOD,wBAAsB,cAAc,CAAC,KAAK,GAAE,iBAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAQtF;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAQzF;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,OAAO,GAAG,MAAgB,GACnC,OAAO,CAAC,IAAI,CAAC,CAQf;AAED,wBAAgB,gBAAgB,IAAI,OAAO,CAG1C"}
1
+ {"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/utils/native.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE7D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAE9E,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QAEd,uBAAuB,CAAC,EAAE,qBAAqB,CAAC;KACjD;CACF;AAOD,wBAAsB,cAAc,CAAC,KAAK,GAAE,iBAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAQtF;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAQzF;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,OAAO,GAAG,MAAgB,GACnC,OAAO,CAAC,IAAI,CAAC,CAQf;AAED,wBAAgB,gBAAgB,IAAI,OAAO,CAG1C"}
@@ -1 +1 @@
1
- {"version":3,"file":"native.js","names":[],"sources":["../../../src/proserviceworld/utils/native.ts"],"sourcesContent":["/**\n * ProServiceWorld native-bridge helpers.\n *\n * The host app shell owns the Capacitor bridge and exposes it at\n * `window.__burdenoffNativeBridge`. This module provides typed, safe wrappers\n * that no-op gracefully on web or when the bridge is unavailable.\n */\n\nexport type HapticImpactStyle = 'light' | 'medium' | 'heavy';\n\ndeclare global {\n interface Window {\n __burdenoffNativeBridge?: {\n impact?: (style: HapticImpactStyle) => Promise<void>;\n notify?: (type: 'success' | 'warning' | 'error') => Promise<void>;\n toast?: (message: string, duration?: 'short' | 'long') => Promise<boolean>;\n isNativePlatform?: () => boolean;\n };\n }\n}\n\nfunction getBridge() {\n if (typeof window === 'undefined') return undefined;\n return window.__burdenoffNativeBridge;\n}\n\nexport async function impactFeedback(style: HapticImpactStyle = 'light'): Promise<void> {\n const bridge = getBridge();\n if (!bridge?.impact) return;\n try {\n await bridge.impact(style);\n } catch {\n /* no-op on web / unsupported */\n }\n}\n\nexport async function notifyFeedback(type: 'success' | 'warning' | 'error'): Promise<void> {\n const bridge = getBridge();\n if (!bridge?.notify) return;\n try {\n await bridge.notify(type);\n } catch {\n /* no-op */\n }\n}\n\nexport async function nativeToast(\n message: string,\n duration: 'short' | 'long' = 'short'\n): Promise<void> {\n const bridge = getBridge();\n if (!bridge?.toast) return;\n try {\n await bridge.toast(message, duration);\n } catch {\n /* no-op */\n }\n}\n\nexport function isNativePlatform(): boolean {\n const bridge = getBridge();\n return bridge?.isNativePlatform?.() ?? false;\n}\n"],"mappings":";AAqBA,SAAS,IAAY;CACf,aAAO,SAAW,MACtB,OAAO,OAAO;AAChB;AAEA,eAAsB,EAAe,IAA2B,SAAwB;CACtF,IAAM,IAAS,EAAU;CACpB,OAAQ,QACb,IAAI;EACF,MAAM,EAAO,OAAO,CAAK;CAC3B,QAAQ,CAER;AACF"}
1
+ {"version":3,"file":"native.js","names":[],"sources":["../../../src/proserviceworld/utils/native.ts"],"sourcesContent":["/**\n * ProServiceWorld native-bridge helpers.\n *\n * The host app shell owns the Capacitor bridge and exposes it at\n * `window.__burdenoffNativeBridge`. This module provides typed, safe wrappers\n * that no-op gracefully on web or when the bridge is unavailable.\n */\n\nexport type HapticImpactStyle = 'light' | 'medium' | 'heavy';\n\nimport type { BurdenoffNativeBridge } from '@burdenoff/fe-libs/shared/native';\n\ndeclare global {\n interface Window {\n // Typed by the shell package so both declarations agree (TS2717 otherwise).\n __burdenoffNativeBridge?: BurdenoffNativeBridge;\n }\n}\n\nfunction getBridge() {\n if (typeof window === 'undefined') return undefined;\n return window.__burdenoffNativeBridge;\n}\n\nexport async function impactFeedback(style: HapticImpactStyle = 'light'): Promise<void> {\n const bridge = getBridge();\n if (!bridge?.impact) return;\n try {\n await bridge.impact(style);\n } catch {\n /* no-op on web / unsupported */\n }\n}\n\nexport async function notifyFeedback(type: 'success' | 'warning' | 'error'): Promise<void> {\n const bridge = getBridge();\n if (!bridge?.notify) return;\n try {\n await bridge.notify(type);\n } catch {\n /* no-op */\n }\n}\n\nexport async function nativeToast(\n message: string,\n duration: 'short' | 'long' = 'short'\n): Promise<void> {\n const bridge = getBridge();\n if (!bridge?.toast) return;\n try {\n await bridge.toast(message, duration);\n } catch {\n /* no-op */\n }\n}\n\nexport function isNativePlatform(): boolean {\n const bridge = getBridge();\n return bridge?.isNativePlatform?.() ?? false;\n}\n"],"mappings":";AAmBA,SAAS,IAAY;CACf,aAAO,SAAW,MACtB,OAAO,OAAO;AAChB;AAEA,eAAsB,EAAe,IAA2B,SAAwB;CACtF,IAAM,IAAS,EAAU;CACpB,OAAQ,QACb,IAAI;EACF,MAAM,EAAO,OAAO,CAAK;CAC3B,QAAQ,CAER;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-proserviceworld",
3
- "version": "2026.1009.1",
3
+ "version": "2026.1014.1",
4
4
  "description": "Burdenoff ProServiceWorld Microfrontend",
5
5
  "type": "module",
6
6
  "files": [
@@ -88,7 +88,7 @@
88
88
  "eslint-plugin-react-refresh": "^0.4.26",
89
89
  "jsdom": "^25.0.1",
90
90
  "lefthook": "^2.1.1",
91
- "postcss": "^8.4.49",
91
+ "postcss": "8.5.29",
92
92
  "prettier": "^3.4.2",
93
93
  "storybook": "^8.6.0",
94
94
  "tailwindcss": "^4.0.0",
@@ -96,7 +96,9 @@
96
96
  "typescript-eslint": "^8.54.0",
97
97
  "vite": "8.1.4",
98
98
  "vite-plugin-dts": "3.9.1",
99
- "vitest": "^3.2.4"
99
+ "vitest": "^3.2.4",
100
+ "braces": "3.0.3",
101
+ "tinypool": "1.1.1"
100
102
  },
101
103
  "peerDependencies": {
102
104
  "@apollo/client": "^4.0.11",
@@ -114,7 +116,7 @@
114
116
  "fast-xml-parser": ">=4.5.5",
115
117
  "@xmldom/xmldom": ">=0.8.12",
116
118
  "swiper": ">=12.1.2",
117
- "brace-expansion": ">=1.1.13",
119
+ "brace-expansion": "5.0.12",
118
120
  "follow-redirects": ">=1.15.12",
119
121
  "smol-toml": ">=1.6.1",
120
122
  "axios": ">=1.15.0",
@@ -122,6 +124,20 @@
122
124
  "yaml": ">=2.8.3",
123
125
  "picomatch": ">=2.3.2",
124
126
  "immutable": ">=3.8.3",
125
- "minimatch": ">=3.1.3"
127
+ "minimatch": ">=3.1.3",
128
+ "@fastify/busboy": "3.2.3",
129
+ "@graphql-tools/utils": "12.0.4",
130
+ "@graphql-tools/executor-legacy-ws": "1.1.38",
131
+ "browserslist": "4.29.3",
132
+ "js-yaml": "4.3.2",
133
+ "nanoid": "3.3.20",
134
+ "postcss": "8.5.29",
135
+ "shell-quote": "1.12.0",
136
+ "source-map-js": "1.2.2",
137
+ "braces": "3.0.3"
138
+ },
139
+ "patchedDependencies": {
140
+ "braces@3.0.3": "patches/braces@3.0.3.patch",
141
+ "tinypool@1.1.1": "patches/tinypool@1.1.1.patch"
126
142
  }
127
143
  }