@wssto2/vue-core 0.14.0 → 0.15.0

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 (94) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +2 -2
  3. package/bin/architecture/engine.mjs +11 -1
  4. package/bin/architecture/rules.mjs +95 -0
  5. package/bin/commands/check-architecture.mjs +8 -1
  6. package/bin/config.mjs +2 -0
  7. package/dist/{AccessGate.vue_vue_type_script_setup_true_lang-DEzXovsY.js → AccessGate.vue_vue_type_script_setup_true_lang-BH3f0hda.js} +1 -1
  8. package/dist/{Activity-C0HUEDUz.js → Activity-MOAIv6s4.js} +3 -3
  9. package/dist/{Changes-CSaHgVuz.js → Changes-Bu7D0dhY.js} +2 -2
  10. package/dist/{CollectionPage.vue_vue_type_script_setup_true_lang-dIrdS_Gn.js → CollectionPage.vue_vue_type_script_setup_true_lang-D5HsYIck.js} +2 -2
  11. package/dist/{DeadLetters-CHX4Ypgy.js → DeadLetters-DsujMnLG.js} +4 -4
  12. package/dist/FormGroup.vue_vue_type_script_setup_true_lang-CTVuhEbW.js +428 -0
  13. package/dist/{FormView.vue_vue_type_script_setup_true_lang-DvbPEiNQ.js → FormView.vue_vue_type_script_setup_true_lang-Cfvh7rF6.js} +1 -1
  14. package/dist/{General-v_24-zZw.js → General-Dswj1oXt.js} +6 -6
  15. package/dist/{IncidentRecord-BwSBNE37.js → IncidentRecord-DcmqpziF.js} +7 -7
  16. package/dist/{IncidentsList-BqzRU5cZ.js → IncidentsList-BRNqHZdU.js} +3 -3
  17. package/dist/{NewRolePage-Dt0O0VSI.js → NewRolePage-dFLznJGH.js} +2 -2
  18. package/dist/{PersonAccess.vue_vue_type_script_setup_true_lang-CWCt9_dM.js → PersonAccess.vue_vue_type_script_setup_true_lang-D3yp43o5.js} +4 -4
  19. package/dist/{ProfilePage-DApTxq8C.js → ProfilePage-BnHR3xGB.js} +8 -8
  20. package/dist/{RoleEditor.vue_vue_type_script_setup_true_lang-d_aaeXTT.js → RoleEditor.vue_vue_type_script_setup_true_lang-DNF9wzE9.js} +4 -4
  21. package/dist/{RolePage-noy-wmNc.js → RolePage-BtM2rFLm.js} +5 -5
  22. package/dist/{RolesPage-NRRainCw.js → RolesPage-MO1gAfdT.js} +3 -3
  23. package/dist/{SectionNavigator.vue_vue_type_script_setup_true_lang-D_08MS1-.js → SectionNavigator.vue_vue_type_script_setup_true_lang-TMdsmYAg.js} +1 -1
  24. package/dist/ServiceAccountDialog.vue_vue_type_script_setup_true_lang-Bo3phlqB.js +127 -0
  25. package/dist/{ServiceAccountRecord-D_HduQoK.js → ServiceAccountRecord-C1M-dcju.js} +6 -6
  26. package/dist/{ServiceAccountsList-CdSsqTGt.js → ServiceAccountsList-zfyS2WJB.js} +4 -4
  27. package/dist/{Sessions-CTjzMfNg.js → Sessions-BYBUSqHI.js} +3 -3
  28. package/dist/{SettingsPage-CpqASf_D.js → SettingsPage-C9Kp2ddX.js} +5 -5
  29. package/dist/{SignIn-D6tWsKf0.js → SignIn-HBYLSZ1M.js} +4 -4
  30. package/dist/{SignInPage-BCNGI871.js → SignInPage-CEoz3fWE.js} +3 -3
  31. package/dist/{SignIns-BxGGA99u.js → SignIns-BAz7V4vy.js} +2 -2
  32. package/dist/{UserRecord-B0kG0-Tm.js → UserRecord-DkyhGma-.js} +8 -8
  33. package/dist/{UsersList-KMgImERy.js → UsersList-CsW-jU0m.js} +3 -3
  34. package/dist/access/RestrictedPanel.vue.d.ts +20 -0
  35. package/dist/access/index.d.ts +1 -0
  36. package/dist/access/index.js +91 -31
  37. package/dist/app/application.d.ts +2 -2
  38. package/dist/app/current.d.ts +6 -0
  39. package/dist/app/index.d.ts +1 -1
  40. package/dist/app/index.js +17 -16
  41. package/dist/{application-CrXtiGdw.js → application-2gHiwAVy.js} +5 -5
  42. package/dist/client/client.d.ts +6 -0
  43. package/dist/client/index.js +1 -1
  44. package/dist/client-Do8v1I5l.js +193 -0
  45. package/dist/collection/index.js +4 -4
  46. package/dist/config/index.d.ts +21 -1
  47. package/dist/content/StatSummary.vue.d.ts +40 -0
  48. package/dist/content/index.d.ts +1 -0
  49. package/dist/content/index.js +245 -176
  50. package/dist/{contributions-obnyn03x.js → contributions-9CPT-Z5v.js} +1 -1
  51. package/dist/{current-B0lHKTWr.js → current-CslcEPXp.js} +8 -4
  52. package/dist/eslint/index.js +2 -2
  53. package/dist/form/index.js +8 -8
  54. package/dist/form/useForm.d.ts +1 -1
  55. package/dist/{guards-DGcSfTEh.js → guards-6fJxfUtk.js} +1 -1
  56. package/dist/{http-DOEfFCDA.js → http-D6qOS6xs.js} +1 -1
  57. package/dist/i18n/index.d.ts +5 -1
  58. package/dist/i18n/index.js +14 -13
  59. package/dist/i18n/serverMessages.d.ts +15 -1
  60. package/dist/identity/index.js +2 -2
  61. package/dist/incidents/index.js +1 -1
  62. package/dist/{index-D-2NNye6.js → index--AF_DNhE.js} +20 -20
  63. package/dist/{index-DNeIZpXo.js → index-DYva-K_4.js} +4 -4
  64. package/dist/{index-Crz-j_Hu.js → index-Dlu-PA4W.js} +105 -105
  65. package/dist/index.d.ts +1 -1
  66. package/dist/index.js +1 -1
  67. package/dist/{navigation-CctcxT51.js → navigation-DMJ6akat.js} +1 -1
  68. package/dist/{neighbors-Csfan8Ho.js → neighbors-DrEahe7B.js} +1 -1
  69. package/dist/notifications/index.js +1 -1
  70. package/dist/onboarding/index.js +1 -1
  71. package/dist/page/index.js +1 -1
  72. package/dist/phone/index.d.ts +1 -1
  73. package/dist/phone/index.js +153 -141
  74. package/dist/phone/phone.d.ts +6 -0
  75. package/dist/platform/index.js +3 -3
  76. package/dist/{platform-DtISOEt7.js → platform-ORzRR3Tw.js} +1 -1
  77. package/dist/resource/index.js +1 -1
  78. package/dist/router/index.js +3 -3
  79. package/dist/{sections-fkW_IJLc.js → sections-DI_JhgQG.js} +1 -1
  80. package/dist/serverMessages-Ce8-MK4e.js +30 -0
  81. package/dist/shell/index.js +4 -4
  82. package/dist/{state-CXMexi0l.js → state-QDaxntgR.js} +1 -1
  83. package/dist/styles.css +1 -1
  84. package/dist/testing/index.js +2 -2
  85. package/dist/{useCommand-Ch_nx1AQ.js → useCommand-BvcU3AlW.js} +1 -1
  86. package/dist/{useGroupSheet-CPjHydQV.js → useGroupSheet-BGIntPKD.js} +1 -1
  87. package/dist/{usePreferences-B8LIZp_f.js → usePreferences-BfMXVbSO.js} +1 -1
  88. package/dist/{useRecordDialog-DdkauXnU.js → useRecordDialog-q_BNXdb7.js} +1 -1
  89. package/dist/{useResourceForm-Dl6YFYyz.js → useResourceForm-C1S628UI.js} +1 -1
  90. package/package.json +1 -1
  91. package/dist/FormGroup.vue_vue_type_script_setup_true_lang-D6jYfNjW.js +0 -427
  92. package/dist/ServiceAccountDialog.vue_vue_type_script_setup_true_lang-DDcaju7L.js +0 -127
  93. package/dist/client-Dg303Pmc.js +0 -193
  94. package/dist/serverMessages-DnTqVS3h.js +0 -25
@@ -10,15 +10,15 @@ import { coreMessages as le, createMessageRuntime as Xe } from "./i18n/index.js"
10
10
  import { i as Ye, a as Ze } from "./Icon.vue_vue_type_script_lang-BhhsFYwp.js";
11
11
  import { i as et, b as tt } from "./bottomDock-BZEiOPYZ.js";
12
12
  import { i as st, p as ot } from "./chrome-nUcmVu8G.js";
13
- import { i as rt, g as at } from "./platform-DtISOEt7.js";
13
+ import { i as rt, g as at } from "./platform-ORzRR3Tw.js";
14
14
  import { c as nt, A as it, r as ue } from "./access-DmAceEo5.js";
15
15
  import { c as ct, _ as lt } from "./NoAccess.vue_vue_type_script_setup_true_lang-BHzZtZ50.js";
16
- import { i as ut } from "./guards-DGcSfTEh.js";
17
- import { b as ft, c as dt, n as fe } from "./navigation-CctcxT51.js";
18
- import { c as pt, s as de } from "./contributions-obnyn03x.js";
16
+ import { i as ut } from "./guards-6fJxfUtk.js";
17
+ import { b as ft, c as dt, n as fe } from "./navigation-DMJ6akat.js";
18
+ import { c as pt, s as de } from "./contributions-9CPT-Z5v.js";
19
19
  import { a as pe } from "./environment-Dva-SG8D.js";
20
20
  import { b as me, c as he } from "./describeError-B-NMa--w.js";
21
- import { b as mt } from "./current-B0lHKTWr.js";
21
+ import { b as mt } from "./current-CslcEPXp.js";
22
22
  import { _ as ht } from "./Button.vue_vue_type_script_setup_true_lang-C74hcb0N.js";
23
23
  import { _ as gt } from "./EmptyState.vue_vue_type_script_setup_true_lang-DbZiO2RF.js";
24
24
  import { i as wt } from "./feature-DdUAfyi4.js";
@@ -6,6 +6,12 @@ import { type Transport } from "./transport";
6
6
  export interface RequestOptions {
7
7
  query?: Readonly<Record<string, QueryValue>>;
8
8
  headers?: HeadersInit;
9
+ /**
10
+ * The key of this attempt at a change, sent as the `Idempotency-Key` header (it wins over a header of that name): the server does
11
+ * it once however many times the same key arrives. Make it once per attempt (a form holds one until it succeeds) and give it
12
+ * to every retry; the client's own renew-and-retry after a 401 sends it again.
13
+ */
14
+ idempotencyKey?: string;
9
15
  /** Cancels the request; it then fails with kind `aborted` (see `isAborted`), it never resolves half-way. */
10
16
  signal?: AbortSignal;
11
17
  /** False for calls that establish or end the session (sign-in, `/auth/me`), where a 401 is an answer, not an expiry. Default true. */
@@ -1,4 +1,4 @@
1
- import { R, a as i, c as p, f as E } from "../client-Dg303Pmc.js";
1
+ import { R, a as i, c as p, f as E } from "../client-Do8v1I5l.js";
2
2
  import { A as f, i as l, a as b } from "../error-CD7x0Jrz.js";
3
3
  import { r as u } from "../route-goWMxDUN.js";
4
4
  function a(r, e) {
@@ -0,0 +1,193 @@
1
+ import { A as S, k as O, a as q } from "./error-CD7x0Jrz.js";
2
+ function B(e) {
3
+ if (!e) return "";
4
+ const t = new URLSearchParams();
5
+ for (const [s, r] of Object.entries(e))
6
+ if (!(r == null || r === ""))
7
+ if (Array.isArray(r)) for (const o of r) t.append(s, String(o));
8
+ else t.append(s, String(r));
9
+ return t.toString();
10
+ }
11
+ const E = (e) => typeof Blob < "u" && e instanceof Blob;
12
+ function _(e) {
13
+ const t = new FormData();
14
+ for (const [s, r] of Object.entries(e))
15
+ if (r != null)
16
+ if (Array.isArray(r))
17
+ for (const o of r) t.append(`${s}[]`, j(o));
18
+ else
19
+ t.append(s, j(r));
20
+ return t;
21
+ }
22
+ function j(e) {
23
+ return E(e) ? e : e instanceof Date ? e.toISOString() : typeof e == "object" && e !== null ? JSON.stringify(e) : String(e);
24
+ }
25
+ function F(e) {
26
+ if (e === void 0) return { body: void 0, contentType: null };
27
+ if (typeof e == "string" || e instanceof FormData || e instanceof URLSearchParams || e instanceof ArrayBuffer || ArrayBuffer.isView(e) || E(e))
28
+ return { body: e, contentType: null };
29
+ if (typeof e == "object" && e !== null && !Array.isArray(e)) {
30
+ const t = e;
31
+ if (Object.values(t).some((s) => E(s) || Array.isArray(s) && s.some(E)))
32
+ return { body: _(t), contentType: null };
33
+ }
34
+ return { body: JSON.stringify(e), contentType: "application/json" };
35
+ }
36
+ function N() {
37
+ const e = new Uint8Array(16);
38
+ return globalThis.crypto.getRandomValues(e), Array.from(e, (t) => t.toString(16).padStart(2, "0")).join("");
39
+ }
40
+ const T = "X-Request-ID", I = (e) => typeof e == "object" && e !== null && !Array.isArray(e), A = (e) => typeof e == "string" && e !== "" ? e : null;
41
+ function P(e) {
42
+ const t = e?.errors ?? e?.fields;
43
+ if (!I(t)) return {};
44
+ const s = {};
45
+ for (const [r, o] of Object.entries(t))
46
+ Array.isArray(o) ? s[r] = o.map(String) : o != null && (s[r] = [String(o)]);
47
+ return s;
48
+ }
49
+ async function H(e) {
50
+ const t = await e.text();
51
+ if (t.trim() === "") return { payload: null, readable: !0 };
52
+ try {
53
+ return { payload: JSON.parse(t), readable: !0 };
54
+ } catch {
55
+ return { payload: null, readable: !1 };
56
+ }
57
+ }
58
+ async function k(e, t) {
59
+ const s = e.headers.get(T) ?? t, { payload: r, readable: o } = await H(e), c = I(r) ? r : null;
60
+ if (!e.ok) {
61
+ const b = P(c), p = c?.params;
62
+ throw new S({
63
+ kind: O(e.status, Object.keys(b).length > 0),
64
+ message: A(c?.error) ?? A(c?.message) ?? `Request failed with status ${e.status}`,
65
+ status: e.status,
66
+ fields: b,
67
+ code: A(c?.code),
68
+ params: I(p) ? p : null,
69
+ requestId: s,
70
+ payload: r
71
+ });
72
+ }
73
+ if (!o)
74
+ throw new S({
75
+ kind: "malformed",
76
+ message: `The server answered ${e.status} with a body that is not JSON`,
77
+ status: e.status,
78
+ requestId: s
79
+ });
80
+ return c !== null && typeof c.success == "boolean" ? {
81
+ data: c.data ?? null,
82
+ meta: c.meta ?? null,
83
+ message: A(c.message),
84
+ status: e.status,
85
+ requestId: s
86
+ } : { data: r, meta: null, message: null, status: e.status, requestId: s };
87
+ }
88
+ const J = /;\s*([^\s=;]+)\s*=\s*("(?:[^"\\]|\\.)*"|[^;]*)/g;
89
+ function L(e) {
90
+ const t = /^([^']*)'[^']*'(.*)$/s.exec(e);
91
+ if (!t) return null;
92
+ const s = new TextEncoder(), r = [];
93
+ for (const [, o, c] of t[2].matchAll(/%([0-9a-f]{2})|(.)/gis)) r.push(...o ? [parseInt(o, 16)] : s.encode(c));
94
+ try {
95
+ return new TextDecoder(t[1] || "utf-8", { fatal: !0 }).decode(Uint8Array.from(r));
96
+ } catch {
97
+ return null;
98
+ }
99
+ }
100
+ const G = (e) => e.slice(Math.max(e.lastIndexOf("/"), e.lastIndexOf("\\")) + 1).trim();
101
+ function K(e) {
102
+ if (!e) return null;
103
+ let t = null, s = null;
104
+ for (const [, r, o] of e.replace(/^[^;]*/, "").matchAll(J)) {
105
+ const c = r.toLowerCase();
106
+ if (c !== "filename" && c !== "filename*") continue;
107
+ const p = o.startsWith('"') ? o.slice(1, -1).replace(/\\(.)/g, "$1") : o.trim();
108
+ c === "filename*" ? s ?? (s = L(p)) : t ?? (t = p);
109
+ }
110
+ return G(s ?? t ?? "") || null;
111
+ }
112
+ const Q = (e, t) => globalThis.fetch(e, t), V = 20, M = (e) => /^[a-z][a-z0-9+.-]*:\/\//i.test(e);
113
+ function Z(e, t, s) {
114
+ const r = M(t) || e === "" ? t : `${e.replace(/\/+$/, "")}/${t.replace(/^\/+/, "")}`;
115
+ return s === "" ? r : `${r}${r.includes("?") ? "&" : "?"}${s}`;
116
+ }
117
+ const $ = (e, t) => new S({ kind: "aborted", message: "The request was cancelled", requestId: e, cause: t });
118
+ function X(e = {}) {
119
+ const { baseUrl: t = "", transport: s = Q, credentials: r = "include" } = e, o = [], c = (n) => {
120
+ n !== null && (o.push(n), o.length > V && o.shift());
121
+ };
122
+ async function b(n, a, i, u, y, m) {
123
+ const { signal: f } = u, l = e.requestId === !1 ? null : (e.requestId ?? N)();
124
+ if (f?.aborted) throw $(l, f.reason);
125
+ const h = F(i), w = new Headers({ Accept: y }), D = e.headers ? await e.headers() : void 0;
126
+ for (const d of [D, u.headers])
127
+ d && new Headers(d).forEach((z, C) => w.set(C, z));
128
+ u.idempotencyKey !== void 0 && w.set("Idempotency-Key", u.idempotencyKey), l !== null && !w.has(T) && w.set(T, l), h.contentType !== null && !w.has("Content-Type") && w.set("Content-Type", h.contentType);
129
+ const U = { method: n, headers: w, credentials: r, body: h.body, signal: f }, v = Z(t, a, B(u.query));
130
+ try {
131
+ const d = await s(v, U);
132
+ return await m(d, l);
133
+ } catch (d) {
134
+ throw q(d) ? (c(d.requestId), d) : f?.aborted || d instanceof Error && d.name === "AbortError" ? $(l, d) : (c(l), new S({
135
+ kind: "network",
136
+ message: d instanceof Error ? d.message : "The server could not be reached",
137
+ requestId: l,
138
+ cause: d
139
+ }));
140
+ }
141
+ }
142
+ async function p(n, a, i, u, y, m) {
143
+ try {
144
+ return await b(n, a, i, u, y, m);
145
+ } catch (f) {
146
+ if (!q(f) || f.kind !== "unauthorized" || u.handleUnauthorized === !1 || !e.onUnauthorized || await e.onUnauthorized({ error: f, method: n, path: a }) !== "retry") throw f;
147
+ return b(n, a, i, u, y, m);
148
+ }
149
+ }
150
+ const g = (n, a, i, u = {}) => p(n, a, i, u, "application/json", async (y, m) => {
151
+ const f = await k(y, m);
152
+ return c(f.requestId), f;
153
+ });
154
+ function R(n, a = {}, i) {
155
+ const { accept: u = "*/*", method: y = "GET", body: m, ...f } = a;
156
+ return p(y, n, m, f, u, async (l, h) => {
157
+ l.ok || await k(l, h);
158
+ const w = l.headers.get(T) ?? h;
159
+ return c(w), i(l, w);
160
+ });
161
+ }
162
+ async function x(n, a, i = {}) {
163
+ const u = typeof a == "object" && a !== null && !Array.isArray(a) ? { ...a } : {}, y = n.path.replace(/:([A-Za-z_][A-Za-z0-9_]*)/g, (f, l) => {
164
+ const h = u[l];
165
+ if (h == null || h === "")
166
+ throw new Error(`${n.method} ${n.path}: the input has no value for the path parameter "${l}"`);
167
+ return delete u[l], encodeURIComponent(String(h));
168
+ }), m = Object.keys(u).length > 0;
169
+ return n.method === "GET" || n.method === "DELETE" ? g(n.method, y, void 0, { ...i, query: { ...u, ...i.query } }) : g(n.method, y, m ? u : void 0, i);
170
+ }
171
+ return {
172
+ // the rest-tuple overload is the public contract; the implementation takes its arguments positionally
173
+ request: x,
174
+ get: (n, a) => g("GET", n, void 0, a),
175
+ post: (n, a, i) => g("POST", n, a, i),
176
+ put: (n, a, i) => g("PUT", n, a, i),
177
+ patch: (n, a, i) => g("PATCH", n, a, i),
178
+ delete: (n, a) => g("DELETE", n, void 0, a),
179
+ download: (n, a) => R(n, a, async (i, u) => ({
180
+ blob: await i.blob(),
181
+ filename: K(i.headers.get("Content-Disposition")),
182
+ requestId: u
183
+ })),
184
+ stream: (n, a) => R(n, a, async (i) => i),
185
+ recentRequestIds: () => [...o]
186
+ };
187
+ }
188
+ export {
189
+ V as R,
190
+ T as a,
191
+ X as c,
192
+ Q as f
193
+ };
@@ -1,7 +1,7 @@
1
- import { D as K, d as Q, h as W, l as Y, a as ee, r as te, b as se } from "../http-DOEfFCDA.js";
2
- import { _ as ie, a as ae, u as ne } from "../CollectionPage.vue_vue_type_script_setup_true_lang-dIrdS_Gn.js";
3
- import { L as re } from "../state-CXMexi0l.js";
4
- import { a as de, u as ue } from "../neighbors-Csfan8Ho.js";
1
+ import { D as K, d as Q, h as W, l as Y, a as ee, r as te, b as se } from "../http-D6qOS6xs.js";
2
+ import { _ as ie, a as ae, u as ne } from "../CollectionPage.vue_vue_type_script_setup_true_lang-D5HsYIck.js";
3
+ import { L as re } from "../state-QDaxntgR.js";
4
+ import { a as de, u as ue } from "../neighbors-DrEahe7B.js";
5
5
  import { r as p } from "../route-goWMxDUN.js";
6
6
  import { b as pe, a as me } from "../rowLayout-Ohh5ng1u.js";
7
7
  import { _ as _e } from "../DataTable.vue_vue_type_script_setup_true_lang-J3PhyJAS.js";
@@ -41,6 +41,22 @@ export interface ArchitectureFile {
41
41
  }
42
42
  /** An application's own rule: the messages for one file (each is prefixed with the file's path), or none. */
43
43
  export type ArchitectureRule = (file: ArchitectureFile) => string[] | undefined;
44
+ /** The rule `no-hardcoded-copy`: no text in the language of the code's authors where a person reads it. */
45
+ export interface CopyRuleConfig {
46
+ /** What the text of that language looks like: its letters and common words (matched line by line). Required. */
47
+ pattern: RegExp;
48
+ /** Where every string literal of a `.ts` / `<script>` and a template's `placeholder`, `title`, `aria-label` and `label` count. Default: the UI folders (`uiDirs`). Elsewhere only a template's text and the strings of `form.ts`, `*Form.ts` and `forms/` count. */
49
+ scope?: RegExp;
50
+ /** Words that are written in that language's letters in every language (brand names), cut out of what `scope` scans. Give it the `g` flag. */
51
+ properNames?: RegExp;
52
+ }
53
+ /** The rule `no-route-policy`: a route names its permission in `meta.permission`, never in `policy:` / `requires:` of a `routes.ts`. */
54
+ export interface RouteAccessConfig {
55
+ /** The session's retired list of permission names (`policies`): `authStore.<name>` and `state.<name>` are reported too. Default none. */
56
+ sessionField?: string;
57
+ /** Files (by path from the config's folder) that are not scanned: scripts, docs, e2e. Tests are never scanned. */
58
+ exclude?: RegExp;
59
+ }
44
60
  export interface ArchitectureConfig {
45
61
  /** The folder of the features, relative to the config file (default "features"). */
46
62
  featuresDir?: string;
@@ -63,11 +79,15 @@ export interface ArchitectureConfig {
63
79
  };
64
80
  /**
65
81
  * Known offenders that predate a rule, by rule: "deep-import" (`<file> -> <specifier>`), "raw-http", "feature-name" and
66
- * "feature-shape" (paths), and a pack rule's id (files; a stale entry is a violation, so the list only shrinks).
82
+ * "feature-shape" (paths), and a pack rule's or `copy` / `routeAccess` rule's id (files; a stale entry is a violation, so the list only shrinks).
67
83
  */
68
84
  allow?: Record<string, string[]>;
69
85
  /** Opt-in rule packs: "design-values" (theme tokens) and "presentation" (use the library's components). */
70
86
  packs?: ("design-values" | "presentation")[];
87
+ /** Switches on `no-hardcoded-copy`; its allowlist (`allow["no-hardcoded-copy"]`) is a ratchet like a pack rule's. */
88
+ copy?: CopyRuleConfig;
89
+ /** Switches on `no-route-policy`; its allowlist is `allow["no-route-policy"]`. */
90
+ routeAccess?: RouteAccessConfig;
71
91
  /** The application's own rules, run on every source file. */
72
92
  rules?: ArchitectureRule[];
73
93
  /** A document to name after a rule's message, by rule: "shared-layer", "api-error" or a pack rule's id. */
@@ -0,0 +1,40 @@
1
+ /**
2
+ * An outcome as one grouped card of numbers: a quiet label over a large tabular value per cell, hairlines between cells, an optional
3
+ * share bar under a value, and optional header and footer rows (a run's date and status, a success-rate bar).
4
+ *
5
+ * <StatSummary :items="[{ key: 'total', label: 'Rows', value: 120 },
6
+ * { key: 'failed', label: 'Errors', value: 9, tone: 'danger', share: 7.5 }]">
7
+ * <template #footer>…</template>
8
+ * </StatSummary>
9
+ *
10
+ * Wide screens show every cell in one row; compact screens wrap into `compactColumns` and drop cells marked `compact: false`.
11
+ */
12
+ export type StatTone = "neutral" | "muted" | "info" | "success" | "warning" | "danger";
13
+ export type StatItem = {
14
+ key: string;
15
+ label: string;
16
+ value: number;
17
+ tone?: StatTone;
18
+ /** 0–100: draws a share bar with the percentage under the value. */
19
+ share?: number | null;
20
+ /** False hides the cell on compact screens (secondary numbers). */
21
+ compact?: boolean;
22
+ };
23
+ type __VLS_Props = {
24
+ items: StatItem[];
25
+ compactColumns?: number;
26
+ };
27
+ type __VLS_Slots = {
28
+ header?: () => unknown;
29
+ footer?: () => unknown;
30
+ };
31
+ declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
32
+ compactColumns: number;
33
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
34
+ declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
35
+ export default _default;
36
+ type __VLS_WithSlots<T, S> = T & {
37
+ new (): {
38
+ $slots: S;
39
+ };
40
+ };
@@ -9,4 +9,5 @@ export { default as KeyValueList, type KeyValueItem } from "./KeyValueList.vue";
9
9
  export { default as MicroLabel } from "./MicroLabel.vue";
10
10
  export { default as Money } from "./Money.vue";
11
11
  export { default as Panel } from "./Panel.vue";
12
+ export { default as StatSummary, type StatItem, type StatTone } from "./StatSummary.vue";
12
13
  export { default as Timestamp } from "./Timestamp.vue";