@wssto2/vue-core 0.5.0 → 0.5.2

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 (59) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/{AccessGate.vue_vue_type_script_setup_true_lang-Nw1IsB8N.js → AccessGate.vue_vue_type_script_setup_true_lang-DZ9GcLC1.js} +1 -1
  3. package/dist/{Activity-CoGI2_GL.js → Activity-dpY2kIs2.js} +2 -2
  4. package/dist/{Changes-Cwfe6wbX.js → Changes-CL8F1w8q.js} +2 -2
  5. package/dist/{CollectionPage.vue_vue_type_script_setup_true_lang-CtvHtFLy.js → CollectionPage.vue_vue_type_script_setup_true_lang-l-e-6WeS.js} +1 -1
  6. package/dist/{DeadLetters-DyA5Dqn0.js → DeadLetters-DopyRRx0.js} +4 -4
  7. package/dist/{General-DTEfxWls.js → General-mrVzi-5R.js} +2 -2
  8. package/dist/{NewRolePage-CRZoUajV.js → NewRolePage-sfr7tQs5.js} +2 -2
  9. package/dist/{ProfilePage-DLY81mvN.js → ProfilePage-EiTIYzZ5.js} +2 -2
  10. package/dist/{RoleEditor.vue_vue_type_script_setup_true_lang-gXbxXG2R.js → RoleEditor.vue_vue_type_script_setup_true_lang-BGtyOyWL.js} +6 -5
  11. package/dist/{RolePage-B9t586Q8.js → RolePage-ByUr3v_H.js} +3 -3
  12. package/dist/{RolesPage-BRdG-OSL.js → RolesPage-CvHrY9ZC.js} +2 -2
  13. package/dist/{SectionNavigator.vue_vue_type_script_setup_true_lang-Cy9Oi0ts.js → SectionNavigator.vue_vue_type_script_setup_true_lang-Ci04hApd.js} +1 -1
  14. package/dist/{Sessions-vGyUOnPG.js → Sessions-CHLokZ9e.js} +2 -2
  15. package/dist/{SettingsPage-V8WeADZZ.js → SettingsPage-DvOGJz9L.js} +2 -2
  16. package/dist/{SignIn-C-3i8RG6.js → SignIn-ypRvdmjg.js} +2 -2
  17. package/dist/{SignInPage-D2NA3VKU.js → SignInPage-CbPeKlAo.js} +2 -2
  18. package/dist/{SignIns-eoYPB6kB.js → SignIns-BApzbGq-.js} +2 -2
  19. package/dist/{UserRecord-BaQl2zzQ.js → UserRecord-BCTaBajE.js} +5 -5
  20. package/dist/{UsersList-BfXWgH5K.js → UsersList-CqSK3cQL.js} +4 -4
  21. package/dist/access/api.d.ts +8 -7
  22. package/dist/access/context.d.ts +7 -0
  23. package/dist/access/feature.d.ts +8 -0
  24. package/dist/access/index.js +1 -1
  25. package/dist/access/labels.d.ts +5 -0
  26. package/dist/app/index.js +117 -115
  27. package/dist/app/keepAlive.d.ts +4 -8
  28. package/dist/collection/index.js +3 -3
  29. package/dist/{contributions-DVQPcjJz.js → contributions-fx5q5n1u.js} +1 -1
  30. package/dist/{guards-DRh4zmxO.js → guards-D4mXf_2X.js} +1 -1
  31. package/dist/{http-D_pBg22D.js → http-CdQowFlW.js} +1 -1
  32. package/dist/identity/index.d.ts +1 -1
  33. package/dist/identity/index.js +6 -7
  34. package/dist/identity/session.d.ts +10 -7
  35. package/dist/{index-g-qbUeTk.js → index-BPwfLD7i.js} +261 -239
  36. package/dist/index-BVlbcaKs.js +763 -0
  37. package/dist/{index-kqk7Mclb.js → index-auJqVMWC.js} +90 -92
  38. package/dist/index.d.ts +1 -1
  39. package/dist/index.js +1 -1
  40. package/dist/keepAlive-z3IRFkQq.js +46 -0
  41. package/dist/{navigation-DuQwti76.js → navigation-Bc5EQ_Si.js} +1 -1
  42. package/dist/{neighbors-IMRQ4rkm.js → neighbors-Bv6vnWlW.js} +1 -1
  43. package/dist/notifications/index.d.ts +2 -0
  44. package/dist/notifications/index.js +5 -4
  45. package/dist/notifications/push/pushState.d.ts +27 -0
  46. package/dist/page/index.js +1 -1
  47. package/dist/platform/index.js +3 -3
  48. package/dist/platform/platform.d.ts +7 -2
  49. package/dist/platform/session.d.ts +17 -0
  50. package/dist/platform-Dx6STiwY.js +283 -0
  51. package/dist/router/index.js +3 -3
  52. package/dist/{sections-D5rgQ4YB.js → sections-B0HxIOC2.js} +1 -1
  53. package/dist/shell/index.js +3 -3
  54. package/dist/{status-C2gHqkj6.js → status-BUFELJz2.js} +2 -2
  55. package/dist/testing/index.js +1 -1
  56. package/package.json +1 -1
  57. package/dist/index-WkbzC_ee.js +0 -745
  58. package/dist/keepAlive-CDvMQlcJ.js +0 -49
  59. package/dist/platform-Dl1fbScN.js +0 -268
@@ -1,18 +1,18 @@
1
1
  import { route as i } from "./client/index.js";
2
- import { d as W, p as H } from "./feature-DdUAfyi4.js";
3
- import { k as re } from "./keepAlive-CDvMQlcJ.js";
2
+ import { d as j, p as W } from "./feature-DdUAfyi4.js";
3
+ import { k as re } from "./keepAlive-z3IRFkQq.js";
4
4
  import { d as G } from "./defineRoutes-BGAdiIrt.js";
5
5
  import { d as R } from "./context-Ch1r4fdN.js";
6
- import { defineComponent as w, computed as g, watch as q, openBlock as _, createElementBlock as D, ref as F, useTemplateRef as ae, watchEffect as ce, onBeforeUnmount as ue, createVNode as v, unref as o, createElementVNode as p, toDisplayString as f, createCommentVNode as I, createBlock as K, useId as le, Teleport as me, normalizeClass as M, createTextVNode as C, withCtx as T, mergeProps as pe, h as de } from "vue";
6
+ import { defineComponent as w, computed as g, watch as q, openBlock as _, createElementBlock as D, ref as F, useTemplateRef as ae, watchEffect as ce, onBeforeUnmount as ue, createVNode as v, unref as o, createElementVNode as p, toDisplayString as f, createCommentVNode as I, createBlock as K, useId as le, Teleport as me, normalizeClass as B, createTextVNode as C, withCtx as T, mergeProps as pe, h as de } from "vue";
7
7
  import { i as P } from "./error-Bb_dr_Ay.js";
8
8
  import { u as fe } from "./environment-Dva-SG8D.js";
9
9
  import { u as A } from "./describeError-BqGAUZgX.js";
10
10
  import { t as k } from "./toast-CqSDTWRX.js";
11
- import { u as x, h as O, f as V } from "./platform-Dl1fbScN.js";
11
+ import { u as x, h as O, f as M } from "./platform-Dx6STiwY.js";
12
12
  import { useI18n as E } from "vue-i18n";
13
- import { _ as Y } from "./Icon.vue_vue_type_script_lang-D7oC-d-S.js";
14
- import { useRouter as J, useRoute as he } from "vue-router";
15
- import { _ as Q } from "./AccountMenuItem.vue_vue_type_script_setup_true_lang-CPeNxh5K.js";
13
+ import { _ as H } from "./Icon.vue_vue_type_script_lang-D7oC-d-S.js";
14
+ import { useRouter as Y, useRoute as he } from "vue-router";
15
+ import { _ as J } from "./AccountMenuItem.vue_vue_type_script_setup_true_lang-CPeNxh5K.js";
16
16
  import { _ as z } from "./Button.vue_vue_type_script_setup_true_lang-CL9Qh5yq.js";
17
17
  import { u as ye } from "./leaveGuard-Cc8yeLxM.js";
18
18
  import { _ as ge } from "./FormView.vue_vue_type_script_setup_true_lang-CPSYV7iQ.js";
@@ -24,7 +24,7 @@ import { u as xe } from "./FormErrors.vue_vue_type_script_setup_true_lang-D7edzN
24
24
  import { u as Ee } from "./format-D8X4zsx6.js";
25
25
  import { b as Se } from "./routeResource-CcYA75T2.js";
26
26
  import "./ActionRow.vue_vue_type_script_setup_true_lang-BCgKzUvG.js";
27
- import { _ as Te } from "./AccessGate.vue_vue_type_script_setup_true_lang-Nw1IsB8N.js";
27
+ import { _ as Te } from "./AccessGate.vue_vue_type_script_setup_true_lang-DZ9GcLC1.js";
28
28
  const b = {
29
29
  login: i("POST", "/v1/auth/login", { public: !0 }),
30
30
  refresh: i("POST", "/v1/auth/refresh", { public: !0 }),
@@ -57,7 +57,7 @@ const b = {
57
57
  profileSignins: i("GET", "/v1/iam/profile/signins"),
58
58
  profileSessions: i("GET", "/v1/iam/profile/sessions"),
59
59
  profileRevokeSession: i("DELETE", "/v1/iam/profile/sessions/:session_id")
60
- }, [ke, X] = R("vue-core.identity"), $ = (e) => P(e) && e.kind === "unauthorized";
60
+ }, [ke, Q] = R("vue-core.identity"), $ = (e) => P(e) && e.kind === "unauthorized";
61
61
  function Pe(e) {
62
62
  if (!P(e) || e.code !== "identity.signin.locked") return null;
63
63
  const s = e.params?.locked_until, t = typeof s == "string" ? new Date(s) : null;
@@ -98,8 +98,8 @@ const Re = { hidden: "" }, Ie = /* @__PURE__ */ w({
98
98
  }), (r, a) => (_(), D("span", Re));
99
99
  }
100
100
  });
101
- function Z() {
102
- const e = x(), s = J(), { home: t } = X(), n = A(), m = F(!1), d = g(() => O(e.session.state.value)?.impersonator != null);
101
+ function X() {
102
+ const e = x(), s = Y(), { home: t } = Q(), n = A(), m = F(!1), d = g(() => O(e.session.state.value)?.impersonator != null);
103
103
  async function u() {
104
104
  m.value = !0;
105
105
  try {
@@ -115,7 +115,7 @@ function Z() {
115
115
  const Ke = { class: "min-w-0 flex-1" }, $e = { class: "hidden md:inline" }, Ue = { class: "md:hidden" }, Le = ["disabled"], qe = /* @__PURE__ */ w({
116
116
  __name: "ImpersonationBanner",
117
117
  setup(e) {
118
- const { t: s } = E(), t = x(), { returning: n, leave: m } = Z(), d = g(() => O(t.session.state.value)?.impersonator ?? null), u = g(() => {
118
+ const { t: s } = E(), t = x(), { returning: n, leave: m } = X(), d = g(() => O(t.session.state.value)?.impersonator ?? null), u = g(() => {
119
119
  const l = O(t.session.state.value)?.user;
120
120
  return typeof l?.name == "string" ? l.name : typeof l?.login == "string" ? l.login : String(l?.id ?? "");
121
121
  }), r = ae("strip");
@@ -137,7 +137,7 @@ const Ke = { class: "min-w-0 flex-1" }, $e = { class: "hidden md:inline" }, Ue =
137
137
  "data-impersonation-banner": "",
138
138
  class: "sticky top-0 z-40 flex flex-wrap items-center gap-x-3 gap-y-1.5 bg-status-warning-surface px-4 py-2 text-subheadline text-status-warning-content shadow-[inset_0_-1px_0_rgb(154_74_7/0.25)]"
139
139
  }, [
140
- v(o(Y), {
140
+ v(o(H), {
141
141
  name: "informationLine",
142
142
  size: 18,
143
143
  class: "shrink-0 compact:hidden"
@@ -158,8 +158,8 @@ const Ke = { class: "min-w-0 flex-1" }, $e = { class: "hidden md:inline" }, Ue =
158
158
  }), ze = /* @__PURE__ */ w({
159
159
  __name: "ReturnMenuItem",
160
160
  setup(e) {
161
- const { t: s } = E(), { impersonating: t, leave: n } = Z();
162
- return (m, d) => o(t) ? (_(), K(Q, {
161
+ const { t: s } = E(), { impersonating: t, leave: n } = X();
162
+ return (m, d) => o(t) ? (_(), K(J, {
163
163
  key: 0,
164
164
  label: o(s)("core.identity.impersonation.return"),
165
165
  icon: "logoutBoxRLine",
@@ -220,13 +220,13 @@ const De = ["aria-labelledby"], Fe = ["id"], Ne = { class: "mt-1 text-subheadlin
220
220
  "aria-hidden": "true"
221
221
  }, null, -1)),
222
222
  p("div", {
223
- class: M(["fixed inset-0 flex p-4", o(u) ? "items-end p-0" : "items-center justify-center"])
223
+ class: B(["fixed inset-0 flex p-4", o(u) ? "items-end p-0" : "items-center justify-center"])
224
224
  }, [
225
225
  p("div", {
226
226
  ref_key: "panel",
227
227
  ref: c,
228
228
  tabindex: "-1",
229
- class: M(["flex w-full flex-col gap-4 bg-surface-overlay p-6 shadow-float outline-none", o(u) ? "rounded-t-2xl pb-[max(2rem,var(--app-safe-bottom))]" : "max-w-sm rounded-menu"])
229
+ class: B(["flex w-full flex-col gap-4 bg-surface-overlay p-6 shadow-float outline-none", o(u) ? "rounded-t-2xl pb-[max(2rem,var(--app-safe-bottom))]" : "max-w-sm rounded-menu"])
230
230
  }, [
231
231
  p("div", null, [
232
232
  p("h2", {
@@ -236,7 +236,7 @@ const De = ["aria-labelledby"], Fe = ["id"], Ne = { class: "mt-1 text-subheadlin
236
236
  p("p", Ne, f(o(s)("core.identity.expired.body")), 1)
237
237
  ]),
238
238
  p("p", Be, [
239
- v(o(Y), {
239
+ v(o(H), {
240
240
  name: "checkboxCircleFill",
241
241
  size: 16,
242
242
  class: "shrink-0"
@@ -285,25 +285,46 @@ const De = ["aria-labelledby"], Fe = ["id"], Ne = { class: "mt-1 text-subheadlin
285
285
  ], 8, De)) : I("", !0)
286
286
  ]));
287
287
  }
288
- }), He = (e) => typeof e == "object" && e !== null && !Array.isArray(e), Ye = (e) => {
289
- if (!He(e)) throw new TypeError("expected an object");
288
+ }), He = G({
289
+ login: { name: "login", path: "/login", component: () => import("./SignInPage-CbPeKlAo.js"), meta: { public: !0, titleKey: "core.identity.signin.title" } }
290
+ });
291
+ function Rs(e = {}) {
292
+ return j({
293
+ id: "identity",
294
+ routes: He.records,
295
+ context: W(ke, { home: e.home ?? "/" }),
296
+ holdsExpiredSession: !0,
297
+ contributions: [
298
+ // Not optional: a shell without a `host` could not ask for the password, and the person would be stuck on a dead page.
299
+ { id: "identity.expiry", slot: "host", component: We, scope: "always" },
300
+ // Not optional either: acting as somebody else must always be visible.
301
+ { id: "identity.impersonation", slot: "banner", component: qe, scope: "authenticated" },
302
+ // The same way out in the account menu (a shell without that slot shows only the banner's button).
303
+ { id: "identity.return", slot: "accountMenu", component: ze, scope: "authenticated", optional: !0, order: -20 },
304
+ { id: "identity.locale", slot: "host", component: Ie, scope: "authenticated", optional: !0 }
305
+ ],
306
+ effects: [re()]
307
+ });
308
+ }
309
+ const Ye = (e) => typeof e == "object" && e !== null && !Array.isArray(e), Je = (e) => {
310
+ if (!Ye(e)) throw new TypeError("expected an object");
290
311
  if (typeof e.id != "number") throw new TypeError("id: expected a number");
291
312
  for (const s of ["login", "name", "email", "locale"])
292
313
  if (typeof e[s] != "string") throw new TypeError(`${s}: expected a string`);
293
314
  return { id: e.id, login: e.login, name: e.name, email: e.email, locale: e.locale };
294
- }, L = (e) => P(e) && e.kind === "unauthorized", B = (e, s) => e.request(b.refresh, { refresh_token: "" }, { signal: s, handleUnauthorized: !1 });
295
- function Je(e, s) {
315
+ }, L = (e) => P(e) && e.kind === "unauthorized", Z = (e, s) => e.request(b.refresh, { refresh_token: "" }, { signal: s, handleUnauthorized: !1 });
316
+ function Qe(e, s) {
296
317
  return {
297
318
  async load(t) {
298
319
  try {
299
320
  const { data: n } = await e.request(b.me, void 0, { signal: t, handleUnauthorized: !1 });
300
- return V(n, s);
321
+ return M(n, s);
301
322
  } catch (n) {
302
323
  if (!L(n)) throw n;
303
324
  }
304
325
  try {
305
- const { data: n } = await B(e, t);
306
- return V(n, s);
326
+ const { data: n } = await Z(e, t);
327
+ return M(n, s);
307
328
  } catch (n) {
308
329
  if (L(n)) return null;
309
330
  throw n;
@@ -319,98 +340,76 @@ function Je(e, s) {
319
340
  };
320
341
  }
321
342
  function Is(e) {
322
- const s = e?.parseUser ?? Ye;
343
+ const s = e?.parseUser ?? Je;
323
344
  return {
324
- session: (n) => Je(n, s),
345
+ session: (n) => Qe(n, s),
346
+ ...e?.renewable && { renewable: e.renewable },
325
347
  async renewSession(n, m) {
326
348
  try {
327
- return await B(m), (await n.refresh()).status === "authenticated";
349
+ return await Z(m), (await n.refresh()).status === "authenticated";
328
350
  } catch {
329
351
  return !1;
330
352
  }
331
353
  }
332
354
  };
333
355
  }
334
- const Qe = async (e) => {
335
- await B(e.http);
336
- }, Xe = G({
337
- login: { name: "login", path: "/login", component: () => import("./SignInPage-D2NA3VKU.js"), meta: { public: !0, titleKey: "core.identity.signin.title" } }
338
- });
339
- function Ks(e = {}) {
340
- return W({
341
- id: "identity",
342
- routes: Xe.records,
343
- context: H(ke, { home: e.home ?? "/" }),
344
- holdsExpiredSession: !0,
345
- contributions: [
346
- // Not optional: a shell without a `host` could not ask for the password, and the person would be stuck on a dead page.
347
- { id: "identity.expiry", slot: "host", component: We, scope: "always" },
348
- // Not optional either: acting as somebody else must always be visible.
349
- { id: "identity.impersonation", slot: "banner", component: qe, scope: "authenticated" },
350
- // The same way out in the account menu (a shell without that slot shows only the banner's button).
351
- { id: "identity.return", slot: "accountMenu", component: ze, scope: "authenticated", optional: !0, order: -20 },
352
- { id: "identity.locale", slot: "host", component: Ie, scope: "authenticated", optional: !0 }
353
- ],
354
- effects: [re({ renew: Qe })]
355
- });
356
- }
357
356
  const ee = G({
358
- index: { name: "profile", path: "/profile", component: () => import("./ProfilePage-DLY81mvN.js"), meta: { titleKey: "core.profile.title" } }
359
- }), Ze = /* @__PURE__ */ w({
357
+ index: { name: "profile", path: "/profile", component: () => import("./ProfilePage-EiTIYzZ5.js"), meta: { titleKey: "core.profile.title" } }
358
+ }), Xe = /* @__PURE__ */ w({
360
359
  __name: "ProfileMenuItem",
361
360
  setup(e) {
362
361
  const { t: s } = E();
363
- return (t, n) => (_(), K(Q, {
362
+ return (t, n) => (_(), K(J, {
364
363
  label: o(s)("core.profile.menu"),
365
364
  icon: "user3Line",
366
365
  to: o(ee).index,
367
366
  "data-profile-menu-item": ""
368
367
  }, null, 8, ["label", "to"]));
369
368
  }
370
- }), [es, $s] = R("vue-core.users"), ss = Symbol("vue-core.users.person"), [Us, Ls] = R("vue-core.users.personActions"), [qs, zs] = R("vue-core.users.personSessions");
371
- function ts(e) {
369
+ }), [Ze, Ks] = R("vue-core.users"), es = Symbol("vue-core.users.person"), [$s, Us] = R("vue-core.users.personActions"), [Ls, qs] = R("vue-core.users.personSessions");
370
+ function ss(e) {
372
371
  const s = w({
373
372
  name: `PersonSection(${e.path})`,
374
373
  setup() {
375
- const t = Se(ss);
374
+ const t = Se(es);
376
375
  return () => t.data.value ? de(e.component, e.props?.(t.data.value) ?? {}) : null;
377
376
  }
378
377
  });
379
378
  return { name: `users.record.${e.path}`, path: e.path, component: s, meta: { ...e.meta } };
380
379
  }
381
- const j = "iam.user:view", Gs = "iam.user:manage", ns = "iam.user.activity:view", se = G({
382
- index: { name: "users.index", path: "/users", component: () => import("./UsersList-BfXWgH5K.js"), meta: { access: j, titleKey: "core.users.title" } },
380
+ const V = "iam.user:view", zs = "iam.user:manage", ts = "iam.user.activity:view", se = G({
381
+ index: { name: "users.index", path: "/users", component: () => import("./UsersList-CqSK3cQL.js"), meta: { access: V, titleKey: "core.users.title" } },
383
382
  record: {
384
383
  name: "users.record",
385
384
  path: "/users/:id",
386
- component: () => import("./UserRecord-BaQl2zzQ.js"),
387
- meta: { access: j, titleKey: "core.users.title", remountOnParam: "id" },
385
+ component: () => import("./UserRecord-BCTaBajE.js"),
386
+ meta: { access: V, titleKey: "core.users.title", remountOnParam: "id" },
388
387
  children: [
389
- { name: "users.record.general", path: "general", component: () => import("./General-DTEfxWls.js"), meta: { section: { labelKey: "core.users.sections.general", icon: "user3Line", groupKey: "core.users.section_groups.person" } } },
390
- { name: "users.record.signin", path: "signin", component: () => import("./SignIn-C-3i8RG6.js"), meta: { section: { labelKey: "core.users.sections.signin", icon: "key2Line", groupKey: "core.users.section_groups.access" } } },
391
- { name: "users.record.sessions", path: "sessions", component: () => import("./Sessions-vGyUOnPG.js"), meta: { section: { labelKey: "core.users.sections.sessions", icon: "deviceLine", groupKey: "core.users.section_groups.access" } } },
392
- { name: "users.record.signins", path: "signins", component: () => import("./SignIns-eoYPB6kB.js"), meta: { section: { labelKey: "core.users.sections.signins", icon: "timeFill", groupKey: "core.users.section_groups.activity" } } },
393
- { name: "users.record.changes", path: "changes", component: () => import("./Changes-Cwfe6wbX.js"), meta: { section: { labelKey: "core.users.sections.changes", icon: "edit", groupKey: "core.users.section_groups.activity" } } },
394
- { name: "users.record.activity", path: "activity", component: () => import("./Activity-CoGI2_GL.js"), meta: { access: ns, section: { labelKey: "core.users.sections.activity", icon: "listCheck", groupKey: "core.users.section_groups.activity" } } }
388
+ { name: "users.record.general", path: "general", component: () => import("./General-mrVzi-5R.js"), meta: { section: { labelKey: "core.users.sections.general", icon: "user3Line", groupKey: "core.users.section_groups.person" } } },
389
+ { name: "users.record.signin", path: "signin", component: () => import("./SignIn-ypRvdmjg.js"), meta: { section: { labelKey: "core.users.sections.signin", icon: "key2Line", groupKey: "core.users.section_groups.access" } } },
390
+ { name: "users.record.sessions", path: "sessions", component: () => import("./Sessions-CHLokZ9e.js"), meta: { section: { labelKey: "core.users.sections.sessions", icon: "deviceLine", groupKey: "core.users.section_groups.access" } } },
391
+ { name: "users.record.signins", path: "signins", component: () => import("./SignIns-BApzbGq-.js"), meta: { section: { labelKey: "core.users.sections.signins", icon: "timeFill", groupKey: "core.users.section_groups.activity" } } },
392
+ { name: "users.record.changes", path: "changes", component: () => import("./Changes-CL8F1w8q.js"), meta: { section: { labelKey: "core.users.sections.changes", icon: "edit", groupKey: "core.users.section_groups.activity" } } },
393
+ { name: "users.record.activity", path: "activity", component: () => import("./Activity-dpY2kIs2.js"), meta: { access: ts, section: { labelKey: "core.users.sections.activity", icon: "listCheck", groupKey: "core.users.section_groups.activity" } } }
395
394
  ]
396
395
  }
397
396
  });
398
- function os(e) {
399
- return se.records.map((s) => s.name === "users.record" ? { ...s, children: [...s.children ?? [], ...e.map(ts)] } : s);
397
+ function ns(e) {
398
+ return se.records.map((s) => s.name === "users.record" ? { ...s, children: [...s.children ?? [], ...e.map(ss)] } : s);
400
399
  }
401
- function Ds(e = {}) {
400
+ function Gs(e = {}) {
402
401
  const s = e.people ?? !0, t = e.profile ?? !0, n = e.signInAs ?? "iam.user:impersonate";
403
- return W({
402
+ return j({
404
403
  id: "users",
405
- routes: [...s ? os(e.sections ?? []) : [], ...t ? ee.records : []],
406
- context: H(es, { signInAs: n, activityAreas: e.activityAreas ?? {}, profileSections: e.profileSections ?? [] }),
404
+ routes: [...s ? ns(e.sections ?? []) : [], ...t ? ee.records : []],
405
+ context: W(Ze, { signInAs: n, activityAreas: e.activityAreas ?? {}, profileSections: e.profileSections ?? [] }),
407
406
  navigation: s && e.destination ? [{ destination: e.destination, to: se.index, within: ["users.record"] }] : [],
408
407
  // The entry of the account menu; a shell without that menu leaves it out.
409
- contributions: t ? [{ id: "users.profile", slot: "accountMenu", component: Ze, scope: "authenticated", optional: !0, order: -10 }] : [],
408
+ contributions: t ? [{ id: "users.profile", slot: "accountMenu", component: Xe, scope: "authenticated", optional: !0, order: -10 }] : [],
410
409
  requires: s && n !== !1 ? ["identity"] : []
411
410
  });
412
411
  }
413
- const Fs = /* @__PURE__ */ w({
412
+ const Ds = /* @__PURE__ */ w({
414
413
  __name: "SignInAsButton",
415
414
  props: {
416
415
  userId: {},
@@ -418,7 +417,7 @@ const Fs = /* @__PURE__ */ w({
418
417
  permission: {}
419
418
  },
420
419
  setup(e) {
421
- const s = e, { t } = E(), n = x(), m = J(), { home: d } = X(), u = A(), r = F(!1), a = g(() => {
420
+ const s = e, { t } = E(), n = x(), m = Y(), { home: d } = Q(), u = A(), r = F(!1), a = g(() => {
422
421
  const c = O(n.session.state.value);
423
422
  return c !== null && c.impersonator === void 0 && c.user.id !== s.userId;
424
423
  });
@@ -453,28 +452,27 @@ const Fs = /* @__PURE__ */ w({
453
452
  }
454
453
  });
455
454
  export {
456
- Gs as M,
457
- ss as P,
458
- Fs as _,
455
+ zs as M,
456
+ es as P,
457
+ Ds as _,
459
458
  Ge as a,
460
- Ls as b,
461
- $s as c,
459
+ Us as b,
460
+ Ks as c,
462
461
  $ as d,
463
- zs as e,
462
+ qs as e,
464
463
  se as f,
465
- Us as g,
466
- Ks as h,
464
+ $s as g,
465
+ Rs as h,
467
466
  b as i,
468
467
  Is as j,
469
- Je as k,
468
+ Qe as k,
470
469
  Pe as l,
471
- Ye as m,
470
+ Je as m,
472
471
  ee as n,
473
- Oe as o,
474
- qs as p,
475
- Ce as q,
476
- Qe as r,
472
+ Ce as o,
473
+ Ls as p,
474
+ Gs as q,
475
+ Oe as r,
477
476
  Ae as s,
478
- Ds as t,
479
- X as u
477
+ Q as u
480
478
  };
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** The version of @wssto2/vue-core (kept equal to package.json by index.test.ts). */
2
- export declare const version = "0.5.0";
2
+ export declare const version = "0.5.2";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- const o = "0.5.0";
1
+ const o = "0.5.2";
2
2
  export {
3
3
  o as version
4
4
  };
@@ -0,0 +1,46 @@
1
+ function b(d = {}) {
2
+ const { margin: l = 6e4, retryAfter: v = 3e4 } = d;
3
+ return {
4
+ id: "vue-core.keep-session-alive",
5
+ scope: "session",
6
+ start({ signal: n, platform: i, report: m }) {
7
+ let s;
8
+ const o = () => {
9
+ const e = i.session.state.value;
10
+ return i.session.renewable && e.status === "authenticated" && e.expiresAt ? e.expiresAt.getTime() - Date.now() - l : null;
11
+ }, w = async () => {
12
+ try {
13
+ await i.session.renew();
14
+ } catch (e) {
15
+ m(e);
16
+ }
17
+ };
18
+ function r(e = 0) {
19
+ clearTimeout(s);
20
+ const u = o();
21
+ u !== null && !n.aborted && (s = setTimeout(() => void t(), Math.min(Math.max(u, e), 864e5)));
22
+ }
23
+ async function t() {
24
+ if (n.aborted || !navigator.onLine) return;
25
+ const e = o();
26
+ if (e !== null) {
27
+ if (e <= 0) {
28
+ if (await w(), n.aborted) return;
29
+ r((o() ?? 1) <= 0 ? v : 0);
30
+ return;
31
+ }
32
+ r();
33
+ }
34
+ }
35
+ const a = () => {
36
+ document.visibilityState === "visible" && t();
37
+ }, c = () => void t();
38
+ return document.addEventListener("visibilitychange", a), window.addEventListener("online", c), t(), () => {
39
+ clearTimeout(s), document.removeEventListener("visibilitychange", a), window.removeEventListener("online", c);
40
+ };
41
+ }
42
+ };
43
+ }
44
+ export {
45
+ b as k
46
+ };
@@ -1,6 +1,6 @@
1
1
  import { computed as k } from "vue";
2
2
  import { d as y } from "./context-Ch1r4fdN.js";
3
- import { h as N } from "./platform-Dl1fbScN.js";
3
+ import { h as N } from "./platform-Dx6STiwY.js";
4
4
  function F(l, a = {}) {
5
5
  const i = /* @__PURE__ */ new Map(), o = [];
6
6
  for (const e of l) {
@@ -1,7 +1,7 @@
1
1
  import { computed as j, ref as z, shallowRef as I, watch as F, getCurrentScope as J, onScopeDispose as Q } from "vue";
2
2
  import { useRoute as O } from "vue-router";
3
3
  import { a as N } from "./error-Bb_dr_Ay.js";
4
- import { L as k, d as B, e as D, o as U, q as V } from "./http-D_pBg22D.js";
4
+ import { L as k, d as B, e as D, o as U, q as V } from "./http-CdQowFlW.js";
5
5
  function K(l, t, n, g) {
6
6
  return typeof t == "string" ? t : { ...t, query: { ...t.query, [n]: D(l, g) } };
7
7
  }
@@ -7,6 +7,8 @@ export { eventsRoutes } from "../modules/events/routes";
7
7
  export { notificationsFeature } from "./feature";
8
8
  export type { NotificationsFeatureOptions } from "./feature";
9
9
  export type { NotificationCategoryLook, NotificationSettingsSection } from "./context";
10
+ export { usePushState } from "./push/pushState";
11
+ export type { PushState } from "./push/pushState";
10
12
  export { notificationSettingsRoutes } from "./settings/routes";
11
13
  export type { NotificationSettingsRoutes } from "./settings/routes";
12
14
  export { deadLettersRoutes } from "./deadletters/routes";
@@ -1,8 +1,9 @@
1
- import { d as s, e as o, n as a, b as i, c as n } from "../index-g-qbUeTk.js";
1
+ import { d as s, e as a, n as o, b as i, c as n, f as u } from "../index-BPwfLD7i.js";
2
2
  export {
3
3
  s as deadLettersRoutes,
4
- o as eventsRoutes,
5
- a as notificationRoutes,
4
+ a as eventsRoutes,
5
+ o as notificationRoutes,
6
6
  i as notificationSettingsRoutes,
7
- n as notificationsFeature
7
+ n as notificationsFeature,
8
+ u as usePushState
8
9
  };
@@ -0,0 +1,27 @@
1
+ import { type ComputedRef, type Ref } from "vue";
2
+ import type { HttpClient } from "../../client";
3
+ import { type PushBrowser } from "./browser";
4
+ /** This browser's push, for an application's own screens (an onboarding step): the same state the settings page shows. */
5
+ export interface PushState {
6
+ /** Settled: `available`, `permission` and `subscribed` are read. Until then `subscribed` is false, so wait for it before offering push. */
7
+ readonly ready: Readonly<Ref<boolean>>;
8
+ /** The server has push and this browser can use it (not an old browser, not an iPhone Safari tab outside the home-screen app). */
9
+ readonly available: ComputedRef<boolean>;
10
+ /** The browser's permission; `unknown` where there is no Notification API. */
11
+ readonly permission: Readonly<Ref<NotificationPermission | "unknown">>;
12
+ /** This browser holds a push subscription, backed by the permission, which the server was given at sign-in or by `enable()`. */
13
+ readonly subscribed: ComputedRef<boolean>;
14
+ readonly busy: Readonly<Ref<boolean>>;
15
+ /** Asks for the permission and registers this browser; call it from a tap. Resolves to `subscribed`. */
16
+ enable(): Promise<boolean>;
17
+ /** Stops push on this browser only. */
18
+ disable(): Promise<void>;
19
+ }
20
+ /**
21
+ * This browser's push state and its two actions, read at once when called (in `setup`). Built on what the notification settings page uses,
22
+ * so a browser that already has push on is `subscribed` and an onboarding step does not offer it again.
23
+ *
24
+ * const push = usePushState();
25
+ * // v-if="push.ready.value && push.available.value && !push.subscribed.value" -> <Button @click="push.enable()">
26
+ */
27
+ export declare function usePushState(http?: HttpClient, browser?: PushBrowser): PushState;
@@ -8,7 +8,7 @@ import { _ as ue } from "../RecordHeader.vue_vue_type_script_setup_true_lang-fmx
8
8
  import { c as pe, i as fe, p as me, a as be, u as ge, b as ve } from "../chrome-nUcmVu8G.js";
9
9
  import { s as z, u as I } from "../sectionIndex-BS0ic5W7.js";
10
10
  import { p as _e, a as xe } from "../sectionIndex-BS0ic5W7.js";
11
- import { _ as ye } from "../SectionNavigator.vue_vue_type_script_setup_true_lang-Cy9Oi0ts.js";
11
+ import { _ as ye } from "../SectionNavigator.vue_vue_type_script_setup_true_lang-Ci04hApd.js";
12
12
  import { a as Se, _ as Ce } from "../SectionList.vue_vue_type_script_setup_true_lang-wyW7n3Uq.js";
13
13
  import { _ as A } from "../Panel.vue_vue_type_script_setup_true_lang-BA0u_DtS.js";
14
14
  const K = ["aria-label"], M = ["aria-label"], N = ["aria-selected", "tabindex", "onClick"], R = { class: "relative" }, E = {
@@ -5,11 +5,11 @@ var S = (s) => {
5
5
  var v = (s, t, e) => t in s ? N(s, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : s[t] = e;
6
6
  var $ = (s, t, e) => v(s, typeof t != "symbol" ? t + "" : t, e), w = (s, t, e) => t.has(s) || S("Cannot " + e);
7
7
  var o = (s, t, e) => (w(s, t, "read from private field"), e ? e.call(s) : t.get(s)), l = (s, t, e) => t.has(s) ? S("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(s) : t.set(s, e), f = (s, t, e, r) => (w(s, t, "write to private field"), r ? r.call(s, e) : t.set(s, e), e), h = (s, t, e) => (w(s, t, "access private method"), e);
8
- import { u as E } from "../platform-Dl1fbScN.js";
9
- import { b as F, c as G, a as K, d as U, h as _, e as z, i as D, p as H, f as Q, g as R } from "../platform-Dl1fbScN.js";
8
+ import { u as E } from "../platform-Dx6STiwY.js";
9
+ import { b as F, c as G, a as K, d as U, h as _, e as z, i as D, p as H, f as Q, g as R } from "../platform-Dx6STiwY.js";
10
10
  import { M as W, d as X } from "../context-Ch1r4fdN.js";
11
11
  import { computed as O } from "vue";
12
- import { _ as Z } from "../AccessGate.vue_vue_type_script_setup_true_lang-Nw1IsB8N.js";
12
+ import { _ as Z } from "../AccessGate.vue_vue_type_script_setup_true_lang-DZ9GcLC1.js";
13
13
  class m extends Error {
14
14
  constructor(e, r = [], n) {
15
15
  super(r.length > 0 ? `${e}: ${r.join("; ")}` : e);
@@ -30,12 +30,17 @@ export interface PlatformOptions<U extends SessionUser, C extends BootstrapConfi
30
30
  */
31
31
  session?: SessionAdapter<U> | ((http: HttpClient) => SessionAdapter<U>);
32
32
  /**
33
- * Called once when a request is answered 401 while signed in, before the session is given up
34
- * (concurrent 401s share one call). Renew it with the platform's client (for example a refresh-token call, then
33
+ * How the session is renewed (`session.renew()`): when a request is answered 401 while signed in, before the
34
+ * session is given up, and when `keepSessionAlive` finds it due. Concurrent renewals, whoever asked, share one call. Renew it with the platform's client (for example a refresh-token call, then
35
35
  * `session.refresh()`) and return true: the failed request is sent again. False or a throw expires
36
36
  * the session. Without it a 401 expires the session at once.
37
37
  */
38
38
  renewSession?: (session: Session<U>, http: HttpClient) => Promise<boolean>;
39
+ /**
40
+ * False while the session cannot be renewed, for example an embed session (a bearer token with no refresh token):
41
+ * a 401 then ends the session at once and `keepSessionAlive` stays idle. Asked each time. Default: renewable when `renewSession` is given.
42
+ */
43
+ renewable?: () => boolean;
39
44
  /** Called after a 401 expired a signed-in session: the application decides (usually: go to the login page). */
40
45
  onSessionExpired?: () => void;
41
46
  /** Called with the failure of a session load or of a before-sign-out hook. */
@@ -89,6 +89,19 @@ export interface Session<U extends SessionUser = SessionUser> {
89
89
  update(patch: SessionPatch<U>): void;
90
90
  /** The server rejected the session (401): signed in becomes anonymous with reason `expired`. No-op when nobody is signed in. */
91
91
  expire(): void;
92
+ /**
93
+ * Whether this session can be renewed at all: the platform was given a `renewSession` and its `renewable()` says
94
+ * yes. An embed session (a bearer token with no refresh token) is not: nothing renews it, and `keepSessionAlive` idles.
95
+ */
96
+ readonly renewable: boolean;
97
+ /**
98
+ * The one way a session is renewed: the timer's (`keepSessionAlive`), the client's after a 401, and an application's own
99
+ * fetch wrapper all call it. Concurrent callers share one in-flight renewal, so the refresh token (which go-core rotates
100
+ * on every use) is presented once. Resolves true when the session goes on (the failed request may be sent again), false
101
+ * when it ended: a refused or throwing renewal, or a session that is not `renewable`, expires it (`onExpired` runs once).
102
+ * False without effect when nobody is signed in.
103
+ */
104
+ renew(): Promise<boolean>;
92
105
  /**
93
106
  * Runs the before-sign-out hooks (together, at most `beforeSignOutTimeout` ms; a failing or late one is reported
94
107
  * to `onError` and never blocks), then signs out locally (state cleared before anything else can read it), then
@@ -114,5 +127,9 @@ export interface SessionOptions<U extends SessionUser = SessionUser> {
114
127
  beforeSignOut?: BeforeSignOutHook<U>;
115
128
  /** Called after `expire()` moved a signed-in session to anonymous. */
116
129
  onExpired?: () => void;
130
+ /** What a renewal does: renew the tokens and read the session again; true when it goes on. Without it the session is not `renewable`. */
131
+ renew?: (session: Session<U>) => Promise<boolean>;
132
+ /** Asked at each renewal and by `keepSessionAlive`; false when this session cannot be renewed (an embed token). Default true. */
133
+ renewable?: () => boolean;
117
134
  }
118
135
  export declare function createSession<U extends SessionUser = SessionUser>(adapter: SessionAdapter<U>, options?: SessionOptions<U>): Session<U>;