@wssto2/vue-core 0.13.1 → 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 (113) hide show
  1. package/CHANGELOG.md +35 -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-ChfxdvXf.js → Activity-MOAIv6s4.js} +5 -5
  9. package/dist/{AdaptivePageShell.vue_vue_type_script_setup_true_lang-lPj9hPqV.js → AdaptivePageShell.vue_vue_type_script_setup_true_lang-Bsv5j5Z8.js} +1 -1
  10. package/dist/{Changes-BCa43_mO.js → Changes-Bu7D0dhY.js} +2 -2
  11. package/dist/{CollectionPage.vue_vue_type_script_setup_true_lang-C1GCvyZx.js → CollectionPage.vue_vue_type_script_setup_true_lang-D5HsYIck.js} +6 -6
  12. package/dist/{DataTable.vue_vue_type_script_setup_true_lang-B9r9M5Gt.js → DataTable.vue_vue_type_script_setup_true_lang-J3PhyJAS.js} +1 -1
  13. package/dist/{DateField.vue_vue_type_script_setup_true_lang-B5UUY1OO.js → DateField.vue_vue_type_script_setup_true_lang-CKKG4JEg.js} +2 -2
  14. package/dist/{DeadLetters-wFTqhISU.js → DeadLetters-DsujMnLG.js} +5 -5
  15. package/dist/FormGroup.vue_vue_type_script_setup_true_lang-CTVuhEbW.js +428 -0
  16. package/dist/{FormView.vue_vue_type_script_setup_true_lang-DvbPEiNQ.js → FormView.vue_vue_type_script_setup_true_lang-Cfvh7rF6.js} +1 -1
  17. package/dist/{General-jW7u4MjH.js → General-Dswj1oXt.js} +7 -7
  18. package/dist/IncidentRecord-DcmqpziF.js +522 -0
  19. package/dist/{IncidentsList-yu0xSMrH.js → IncidentsList-BRNqHZdU.js} +6 -6
  20. package/dist/{NewRolePage-CQ5UVaHs.js → NewRolePage-dFLznJGH.js} +3 -3
  21. package/dist/{NumberField.vue_vue_type_script_setup_true_lang-YVgf5CP6.js → NumberField.vue_vue_type_script_setup_true_lang-U-_kcnGr.js} +1 -1
  22. 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
  23. package/dist/{ProfilePage-Ca3x3UAH.js → ProfilePage-BnHR3xGB.js} +10 -10
  24. package/dist/{RecordHeader.vue_vue_type_script_setup_true_lang-Do_ATJwT.js → RecordHeader.vue_vue_type_script_setup_true_lang-SDgLjwEI.js} +1 -1
  25. package/dist/{ResourcePage.vue_vue_type_script_setup_true_lang-Coz91xht.js → ResourcePage.vue_vue_type_script_setup_true_lang-DRC3h71-.js} +1 -1
  26. 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
  27. package/dist/{RolePage-BUj1w1m1.js → RolePage-BtM2rFLm.js} +7 -7
  28. package/dist/{RolesPage-NKzBUsrM.js → RolesPage-MO1gAfdT.js} +4 -4
  29. package/dist/{SectionNavigator.vue_vue_type_script_setup_true_lang-DfKEhTFv.js → SectionNavigator.vue_vue_type_script_setup_true_lang-TMdsmYAg.js} +2 -2
  30. package/dist/ServiceAccountDialog.vue_vue_type_script_setup_true_lang-Bo3phlqB.js +127 -0
  31. package/dist/{ServiceAccountRecord-ClbyeLhL.js → ServiceAccountRecord-C1M-dcju.js} +10 -10
  32. package/dist/{ServiceAccountsList-B2VDnYxD.js → ServiceAccountsList-zfyS2WJB.js} +6 -6
  33. package/dist/{Sessions-BjkciyHH.js → Sessions-BYBUSqHI.js} +3 -3
  34. package/dist/{SettingsPage-Csb14qsx.js → SettingsPage-C9Kp2ddX.js} +9 -9
  35. package/dist/{SignIn-DPFMv4C7.js → SignIn-HBYLSZ1M.js} +5 -5
  36. package/dist/{SignInPage-DukoFqkt.js → SignInPage-CEoz3fWE.js} +3 -3
  37. package/dist/{SignIns-DvdpNkiS.js → SignIns-BAz7V4vy.js} +2 -2
  38. package/dist/{TimeField.vue_vue_type_script_setup_true_lang-DpDXHH7u.js → TimeField.vue_vue_type_script_setup_true_lang-BDlTAMsh.js} +2 -2
  39. package/dist/{Timestamp.vue_vue_type_script_setup_true_lang-DlEUKWra.js → Timestamp.vue_vue_type_script_setup_true_lang-jCXYFLtq.js} +1 -1
  40. package/dist/{UserRecord-B9SeSWQh.js → UserRecord-DkyhGma-.js} +9 -9
  41. package/dist/{UsersList-CREG8q3l.js → UsersList-CsW-jU0m.js} +4 -4
  42. package/dist/access/RestrictedPanel.vue.d.ts +20 -0
  43. package/dist/access/index.d.ts +1 -0
  44. package/dist/access/index.js +91 -31
  45. package/dist/app/application.d.ts +2 -2
  46. package/dist/app/current.d.ts +6 -0
  47. package/dist/app/index.d.ts +1 -1
  48. package/dist/app/index.js +17 -16
  49. package/dist/{application-DomS6sbx.js → application-2gHiwAVy.js} +6 -6
  50. package/dist/client/client.d.ts +6 -0
  51. package/dist/client/index.js +1 -1
  52. package/dist/client-Do8v1I5l.js +193 -0
  53. package/dist/collection/index.js +6 -6
  54. package/dist/config/index.d.ts +21 -1
  55. package/dist/content/StatSummary.vue.d.ts +40 -0
  56. package/dist/content/index.d.ts +1 -0
  57. package/dist/content/index.js +245 -176
  58. package/dist/{contributions-obnyn03x.js → contributions-9CPT-Z5v.js} +1 -1
  59. package/dist/{current-B0lHKTWr.js → current-CslcEPXp.js} +8 -4
  60. package/dist/eslint/index.js +2 -2
  61. package/dist/form/index.js +16 -16
  62. package/dist/form/useForm.d.ts +1 -1
  63. package/dist/format/format.d.ts +5 -2
  64. package/dist/format/index.js +1 -1
  65. package/dist/format-Cp1h0vsC.js +125 -0
  66. package/dist/{guards-DGcSfTEh.js → guards-6fJxfUtk.js} +1 -1
  67. package/dist/{http-DOEfFCDA.js → http-D6qOS6xs.js} +1 -1
  68. package/dist/i18n/index.d.ts +5 -1
  69. package/dist/i18n/index.js +21 -20
  70. package/dist/i18n/serverMessages.d.ts +15 -1
  71. package/dist/identity/index.js +2 -2
  72. package/dist/incidents/Occurrences.vue.d.ts +9 -0
  73. package/dist/incidents/api.d.ts +11 -2
  74. package/dist/incidents/index.js +1 -1
  75. package/dist/{index-DZikGJ8L.js → index--AF_DNhE.js} +22 -22
  76. package/dist/{index-D_yyd4C2.js → index-DYva-K_4.js} +5 -5
  77. package/dist/{index-Be9Q1PB_.js → index-Dlu-PA4W.js} +104 -98
  78. package/dist/index.d.ts +1 -1
  79. package/dist/index.js +1 -1
  80. package/dist/modules/incident/entities.d.ts +19 -0
  81. package/dist/modules/incident/routes.d.ts +4 -1
  82. package/dist/{navigation-CctcxT51.js → navigation-DMJ6akat.js} +1 -1
  83. package/dist/{neighbors-Csfan8Ho.js → neighbors-DrEahe7B.js} +1 -1
  84. package/dist/notifications/index.js +1 -1
  85. package/dist/onboarding/index.js +1 -1
  86. package/dist/page/index.js +3 -3
  87. package/dist/phone/index.d.ts +1 -1
  88. package/dist/phone/index.js +154 -142
  89. package/dist/phone/phone.d.ts +6 -0
  90. package/dist/platform/index.js +3 -3
  91. package/dist/{platform-DtISOEt7.js → platform-ORzRR3Tw.js} +1 -1
  92. package/dist/resource/index.js +2 -2
  93. package/dist/router/index.js +3 -3
  94. package/dist/{rowLayout-y1IB_h2r.js → rowLayout-Ohh5ng1u.js} +2 -2
  95. package/dist/{sections-fkW_IJLc.js → sections-DI_JhgQG.js} +1 -1
  96. package/dist/serverMessages-Ce8-MK4e.js +30 -0
  97. package/dist/shell/index.js +4 -4
  98. package/dist/{state-CXMexi0l.js → state-QDaxntgR.js} +1 -1
  99. package/dist/styles.css +1 -1
  100. package/dist/testing/index.js +3 -3
  101. package/dist/{useCommand-Ch_nx1AQ.js → useCommand-BvcU3AlW.js} +1 -1
  102. package/dist/{useGroupSheet-CPjHydQV.js → useGroupSheet-BGIntPKD.js} +1 -1
  103. package/dist/{usePreferences-B8LIZp_f.js → usePreferences-BfMXVbSO.js} +1 -1
  104. package/dist/{useRecordDialog-DdkauXnU.js → useRecordDialog-q_BNXdb7.js} +1 -1
  105. package/dist/{useResourceForm-Dl6YFYyz.js → useResourceForm-C1S628UI.js} +1 -1
  106. package/dist/{useTypedEntry-DKs8I1yP.js → useTypedEntry-tttjrClq.js} +1 -1
  107. package/package.json +2 -2
  108. package/dist/FormGroup.vue_vue_type_script_setup_true_lang-D6jYfNjW.js +0 -427
  109. package/dist/IncidentRecord-zTemLz2R.js +0 -404
  110. package/dist/ServiceAccountDialog.vue_vue_type_script_setup_true_lang-4nbhEpv_.js +0 -127
  111. package/dist/client-Dg303Pmc.js +0 -193
  112. package/dist/format-DoKs29bZ.js +0 -118
  113. package/dist/serverMessages-Ddghrewh.js +0 -25
@@ -1,49 +1,109 @@
1
- import { _ as f, a as R, b } from "../PersonAccess.vue_vue_type_script_setup_true_lang-CWCt9_dM.js";
2
- import { d as o, p as c } from "../feature-DdUAfyi4.js";
3
- import { a as s, b as t } from "../refusals-DfPzVNNY.js";
4
- import { d as g, p as x, r as h, c as v, u as y, e as C, f as K } from "../refusals-DfPzVNNY.js";
5
- import { d as r } from "../defineRoutes-BGAdiIrt.js";
6
- const a = r({
7
- roles: { name: "access.roles", path: "/iam/roles", component: () => import("../RolesPage-NKzBUsrM.js"), meta: { access: s.viewRoles, titleKey: "core.access.title" } },
8
- newRole: { name: "access.roles.new", path: "/iam/roles/new", component: () => import("../NewRolePage-CQ5UVaHs.js"), meta: { access: s.manageRoles, titleKey: "core.access.new_title" } },
1
+ import { _ as Q, a as U, b as W } from "../PersonAccess.vue_vue_type_script_setup_true_lang-D3yp43o5.js";
2
+ import { d as _, p as x } from "../feature-DdUAfyi4.js";
3
+ import { a as n, b } from "../refusals-DfPzVNNY.js";
4
+ import { d as Y, p as Z, r as ee, c as se, u as te, e as oe, f as ce } from "../refusals-DfPzVNNY.js";
5
+ import { d as h } from "../defineRoutes-BGAdiIrt.js";
6
+ import { defineComponent as w, openBlock as m, createBlock as R, unref as s, withCtx as u, createElementVNode as a, createVNode as d, toDisplayString as o, normalizeClass as g, createElementBlock as k, createTextVNode as r, createCommentVNode as y } from "vue";
7
+ import { useI18n as C } from "vue-i18n";
8
+ import { useRouter as v } from "vue-router";
9
+ import { _ as P } from "../Button.vue_vue_type_script_setup_true_lang-C74hcb0N.js";
10
+ import { _ as B } from "../Panel.vue_vue_type_script_setup_true_lang-D_Wg42hu.js";
11
+ import { _ as K } from "../Icon.vue_vue_type_script_lang-BhhsFYwp.js";
12
+ const p = h({
13
+ roles: { name: "access.roles", path: "/iam/roles", component: () => import("../RolesPage-MO1gAfdT.js"), meta: { access: n.viewRoles, titleKey: "core.access.title" } },
14
+ newRole: { name: "access.roles.new", path: "/iam/roles/new", component: () => import("../NewRolePage-dFLznJGH.js"), meta: { access: n.manageRoles, titleKey: "core.access.new_title" } },
9
15
  role: {
10
16
  name: "access.role",
11
17
  path: "/iam/roles/:ref",
12
- component: () => import("../RolePage-BUj1w1m1.js"),
18
+ component: () => import("../RolePage-BtM2rFLm.js"),
13
19
  // A role's ref (its key, or the id of a custom one) swaps in place when a link leads to another role.
14
- meta: { access: s.viewRoles, titleKey: "core.access.title", remountOnParam: "ref" }
20
+ meta: { access: n.viewRoles, titleKey: "core.access.title", remountOnParam: "ref" }
15
21
  }
16
- }), m = {
17
- access: s.viewAccess,
22
+ }), M = {
23
+ access: n.viewAccess,
18
24
  section: { labelKey: "core.access.person_roles", icon: "shieldStarFill" }
19
25
  };
20
- function u(e) {
21
- return o({
26
+ function O(e) {
27
+ return _({
22
28
  id: "access",
23
- routes: a.records,
24
- context: c(t, {
29
+ routes: p.records,
30
+ context: x(b, {
25
31
  catalogue: e.catalogue,
26
32
  subjectRoute: e.subjectRoute ?? (() => null),
27
33
  constraints: e.roleConstraints ?? [],
28
34
  problems: e.problems ?? {},
29
35
  scopes: e.scopes ?? null
30
36
  }),
31
- navigation: e.destination ? [{ destination: e.destination, to: a.roles, within: ["access.role", "access.roles.new"] }] : []
37
+ navigation: e.destination ? [{ destination: e.destination, to: p.roles, within: ["access.role", "access.roles.new"] }] : []
32
38
  });
33
39
  }
40
+ const z = {
41
+ "data-test": "restricted-panel",
42
+ class: "flex flex-1 flex-col items-center justify-center px-4 py-16 text-center"
43
+ }, L = { class: "mb-2 text-lg font-semibold text-content-strong" }, N = {
44
+ key: 0,
45
+ class: "mb-6 text-subheadline text-content-muted"
46
+ }, S = ["href"], G = /* @__PURE__ */ w({
47
+ __name: "RestrictedPanel",
48
+ props: {
49
+ contact: { default: void 0 },
50
+ home: { default: "/" }
51
+ },
52
+ setup(e) {
53
+ const t = e, i = v(), { t: c } = C();
54
+ function f() {
55
+ window.history.state?.back ? i.back() : i.push(t.home);
56
+ }
57
+ return (V, l) => (m(), R(s(B), null, {
58
+ default: u(() => [
59
+ a("div", z, [
60
+ d(s(K), {
61
+ name: "lockLine",
62
+ size: 32,
63
+ class: "mb-6 size-12 text-status-danger-content"
64
+ }),
65
+ a("h2", L, o(s(c)("core.no_access.title")), 1),
66
+ a("p", {
67
+ class: g(["max-w-prose text-subheadline text-content-muted", t.contact ? "mb-1" : "mb-6"])
68
+ }, o(s(c)("core.no_access.body")), 3),
69
+ t.contact ? (m(), k("p", N, [
70
+ r(o(s(c)("core.no_access.contact")) + " ", 1),
71
+ a("a", {
72
+ href: `mailto:${t.contact}`,
73
+ class: "text-content-link hover:underline"
74
+ }, o(t.contact), 9, S),
75
+ l[0] || (l[0] = r(". ", -1))
76
+ ])) : y("", !0),
77
+ d(s(P), {
78
+ size: "sm",
79
+ icon: "arrowLeftSLine",
80
+ onClick: f
81
+ }, {
82
+ default: u(() => [
83
+ r(o(s(c)("core.no_access.back")), 1)
84
+ ]),
85
+ _: 1
86
+ })
87
+ ])
88
+ ]),
89
+ _: 1
90
+ }));
91
+ }
92
+ });
34
93
  export {
35
- f as BindingRow,
36
- R as PersonAccess,
37
- u as accessFeature,
38
- a as accessPages,
39
- s as accessPermissions,
40
- b as accessRoutes,
41
- g as dependantsClosure,
42
- x as permissionTree,
43
- m as personRolesSection,
44
- h as requiredClosure,
45
- v as roleProblems,
46
- y as useAccessLabels,
47
- C as useDescribeRefusal,
48
- K as useRefusalMessage
94
+ Q as BindingRow,
95
+ U as PersonAccess,
96
+ G as RestrictedPanel,
97
+ O as accessFeature,
98
+ p as accessPages,
99
+ n as accessPermissions,
100
+ W as accessRoutes,
101
+ Y as dependantsClosure,
102
+ Z as permissionTree,
103
+ M as personRolesSection,
104
+ ee as requiredClosure,
105
+ se as roleProblems,
106
+ te as useAccessLabels,
107
+ oe as useDescribeRefusal,
108
+ ce as useRefusalMessage
49
109
  };
@@ -106,8 +106,8 @@ export interface ApplicationOptions {
106
106
  describeError?: AppErrorDescriber;
107
107
  /**
108
108
  * The application's one sentence for a field message the server sent (often a code or a translation key), for every form
109
- * (`useForm`, `useResourceForm`, `useCommand`) that has no `describeFieldError` of its own; a form's own wins. Without either,
110
- * messages show as sent.
109
+ * (`useForm`, `useResourceForm`, `useCommand`) that has no `describeFieldError` of its own; a form's own wins. Without either, go-core's validator keys (`validation_errors.*`) are worded by the library and
110
+ * other messages show as sent.
111
111
  */
112
112
  describeFieldError?: AppFieldErrorDescriber;
113
113
  /** Called with every error the application catches (component errors, unhandled rejections, failed effects and loads). Default: `console.error`. */
@@ -1,3 +1,4 @@
1
+ import type { HttpClient } from "../client";
1
2
  import type { Application } from "./application";
2
3
  /** Called by `createApplication`; the returned function unbinds, and only if this application is still the current one. */
3
4
  export declare function bindApplication(application: Application): () => void;
@@ -9,3 +10,8 @@ export declare function bindApplication(application: Application): () => void;
9
10
  * Throws before one exists. In a unit test make one first: `createTestApplication()` from `@wssto2/vue-core/testing`, and `dispose()` it after.
10
11
  */
11
12
  export declare function currentApplication(): Application;
13
+ /**
14
+ * The platform's HTTP client of the current application, for an `api.ts` (`const http = currentHttp` is a module's one line of setup).
15
+ * Call it when a request is made, not at module load: it throws before `createApplication` ran.
16
+ */
17
+ export declare function currentHttp(): HttpClient;
@@ -1,6 +1,6 @@
1
1
  export { createApplication } from "./application";
2
2
  export type { Application, ApplicationI18n, ApplicationErrorReport, ApplicationI18nOptions, ApplicationLocaleOptions, ApplicationOptions, ApplicationRouterOptions, ShellDefinition, } from "./application";
3
- export { currentApplication } from "./current";
3
+ export { currentApplication, currentHttp } from "./current";
4
4
  export { ShellOutlet } from "./contributions";
5
5
  export { applicationKey, useApplication } from "./environment";
6
6
  export type { ApplicationEnvironment, ApplicationState } from "./environment";
package/dist/app/index.js CHANGED
@@ -1,18 +1,19 @@
1
- import { A as o, c as r } from "../application-DomS6sbx.js";
2
- import { c as t } from "../current-B0lHKTWr.js";
3
- import { S as i } from "../contributions-obnyn03x.js";
4
- import { a as c, u as l } from "../environment-Dva-SG8D.js";
5
- import { d as f, p as x } from "../feature-DdUAfyi4.js";
6
- import { k as A, u as d } from "../keepAlive-ClGnsIzT.js";
1
+ import { A as r, c as o } from "../application-2gHiwAVy.js";
2
+ import { c as p, a as s } from "../current-CslcEPXp.js";
3
+ import { S as n } from "../contributions-9CPT-Z5v.js";
4
+ import { a as l, u } from "../environment-Dva-SG8D.js";
5
+ import { d as x, p as m } from "../feature-DdUAfyi4.js";
6
+ import { k as d, u as S } from "../keepAlive-ClGnsIzT.js";
7
7
  export {
8
- o as ApplicationError,
9
- i as ShellOutlet,
10
- c as applicationKey,
11
- r as createApplication,
12
- t as currentApplication,
13
- f as defineFeature,
14
- A as keepSessionAlive,
15
- x as provideContext,
16
- l as useApplication,
17
- d as useLanguages
8
+ r as ApplicationError,
9
+ n as ShellOutlet,
10
+ l as applicationKey,
11
+ o as createApplication,
12
+ p as currentApplication,
13
+ s as currentHttp,
14
+ x as defineFeature,
15
+ d as keepSessionAlive,
16
+ m as provideContext,
17
+ u as useApplication,
18
+ S as useLanguages
18
19
  };
@@ -5,20 +5,20 @@ import { effectScope as V, watch as G, defineComponent as ye, openBlock as Fe, c
5
5
  import { useI18n as Be, createI18n as He } from "vue-i18n";
6
6
  import { createRouter as Ve, isNavigationFailure as Ge } from "vue-router";
7
7
  import { i as Je } from "./leaveGuard-Cc8yeLxM.js";
8
- import { c as ze, i as Qe, f as Ue } from "./format-DoKs29bZ.js";
8
+ import { c as ze, i as Qe, f as Ue } from "./format-Cp1h0vsC.js";
9
9
  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,10 +1,10 @@
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-C1GCvyZx.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
- import { b as pe, a as me } from "../rowLayout-y1IB_h2r.js";
7
- import { _ as _e } from "../DataTable.vue_vue_type_script_setup_true_lang-B9r9M5Gt.js";
6
+ import { b as pe, a as me } from "../rowLayout-Ohh5ng1u.js";
7
+ import { _ as _e } from "../DataTable.vue_vue_type_script_setup_true_lang-J3PhyJAS.js";
8
8
  import { defineComponent as h, openBlock as c, createElementBlock as u, Fragment as P, renderList as E, createBlock as w, unref as d, withCtx as g, normalizeClass as v, createVNode as _, createCommentVNode as y, shallowRef as S, useTemplateRef as T, watch as L, renderSlot as D } from "vue";
9
9
  import { _ as b } from "../Icon.vue_vue_type_script_lang-BhhsFYwp.js";
10
10
  import { _ as R } from "../Tooltip.vue_vue_type_script_setup_true_lang-Dtg5Y6pf.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";