@revenexx/studio-shared 0.1.2 → 0.3.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 (120) hide show
  1. package/README.md +22 -12
  2. package/dist/module.d.mts +15 -0
  3. package/dist/module.json +9 -0
  4. package/dist/module.mjs +58 -0
  5. package/dist/runtime/components/DataTable/ColumnsMenu.d.vue.ts +12 -0
  6. package/{components → dist/runtime/components}/DataTable/ColumnsMenu.vue +13 -19
  7. package/dist/runtime/components/DataTable/ColumnsMenu.vue.d.ts +12 -0
  8. package/dist/runtime/components/DataTable/DataTable.d.vue.ts +87 -0
  9. package/dist/runtime/components/DataTable/DataTable.vue +510 -0
  10. package/dist/runtime/components/DataTable/DataTable.vue.d.ts +87 -0
  11. package/dist/runtime/components/DataTable/FilterMenu.d.vue.ts +21 -0
  12. package/dist/runtime/components/DataTable/FilterMenu.vue +46 -0
  13. package/dist/runtime/components/DataTable/FilterMenu.vue.d.ts +21 -0
  14. package/dist/runtime/components/DataTable/SavedViewsMenu.d.vue.ts +6 -0
  15. package/dist/runtime/components/DataTable/SavedViewsMenu.vue +189 -0
  16. package/dist/runtime/components/DataTable/SavedViewsMenu.vue.d.ts +6 -0
  17. package/dist/runtime/components/DataTable/SortMenu.d.vue.ts +13 -0
  18. package/dist/runtime/components/DataTable/SortMenu.vue +47 -0
  19. package/dist/runtime/components/DataTable/SortMenu.vue.d.ts +13 -0
  20. package/dist/runtime/components/DataTable/ViewModeSwitch.d.vue.ts +20 -0
  21. package/dist/runtime/components/DataTable/ViewModeSwitch.vue +26 -0
  22. package/dist/runtime/components/DataTable/ViewModeSwitch.vue.d.ts +20 -0
  23. package/dist/runtime/components/DataTable/types.d.ts +104 -0
  24. package/dist/runtime/components/DataTable/types.js +0 -0
  25. package/dist/runtime/components/Media/MediaFolderTree.d.vue.ts +17 -0
  26. package/dist/runtime/components/Media/MediaFolderTree.vue +65 -0
  27. package/dist/runtime/components/Media/MediaFolderTree.vue.d.ts +17 -0
  28. package/dist/runtime/components/Media/MediaPickerDialog.d.vue.ts +18 -0
  29. package/dist/runtime/components/Media/MediaPickerDialog.vue +163 -0
  30. package/dist/runtime/components/Media/MediaPickerDialog.vue.d.ts +18 -0
  31. package/dist/runtime/components/Media/MediaUploader.d.vue.ts +29 -0
  32. package/dist/runtime/components/Media/MediaUploader.vue +161 -0
  33. package/dist/runtime/components/Media/MediaUploader.vue.d.ts +29 -0
  34. package/dist/runtime/components/Shared/BuildLogsFlyout.d.vue.ts +30 -0
  35. package/{components → dist/runtime/components}/Shared/BuildLogsFlyout.vue +37 -54
  36. package/dist/runtime/components/Shared/BuildLogsFlyout.vue.d.ts +30 -0
  37. package/dist/runtime/components/Shared/GitDeploymentSettings.d.vue.ts +17 -0
  38. package/dist/runtime/components/Shared/GitDeploymentSettings.vue +75 -0
  39. package/dist/runtime/components/Shared/GitDeploymentSettings.vue.d.ts +17 -0
  40. package/dist/runtime/components/Shared/KpiTile.d.vue.ts +13 -0
  41. package/{components → dist/runtime/components}/Shared/KpiTile.vue +11 -19
  42. package/dist/runtime/components/Shared/KpiTile.vue.d.ts +13 -0
  43. package/dist/runtime/components/Shared/ListSurface.d.vue.ts +38 -0
  44. package/dist/runtime/components/Shared/ListSurface.vue +27 -0
  45. package/dist/runtime/components/Shared/ListSurface.vue.d.ts +38 -0
  46. package/dist/runtime/components/Shared/PageHeader.d.vue.ts +23 -0
  47. package/{components → dist/runtime/components}/Shared/PageHeader.vue +6 -8
  48. package/dist/runtime/components/Shared/PageHeader.vue.d.ts +23 -0
  49. package/dist/runtime/components/Shared/RecordLayout.d.vue.ts +52 -0
  50. package/dist/runtime/components/Shared/RecordLayout.vue +63 -0
  51. package/dist/runtime/components/Shared/RecordLayout.vue.d.ts +52 -0
  52. package/dist/runtime/components/Shared/RecordRailCard.d.vue.ts +26 -0
  53. package/dist/runtime/components/Shared/RecordRailCard.vue +20 -0
  54. package/dist/runtime/components/Shared/RecordRailCard.vue.d.ts +26 -0
  55. package/dist/runtime/components/Shared/SidebarNav.d.vue.ts +41 -0
  56. package/dist/runtime/components/Shared/SidebarNav.vue +48 -0
  57. package/dist/runtime/components/Shared/SidebarNav.vue.d.ts +41 -0
  58. package/dist/runtime/components/Shared/SidebarNavLink.d.vue.ts +15 -0
  59. package/dist/runtime/components/Shared/SidebarNavLink.vue +49 -0
  60. package/dist/runtime/components/Shared/SidebarNavLink.vue.d.ts +15 -0
  61. package/dist/runtime/components/Shared/SortHeader.d.vue.ts +23 -0
  62. package/dist/runtime/components/Shared/SortHeader.vue +35 -0
  63. package/dist/runtime/components/Shared/SortHeader.vue.d.ts +23 -0
  64. package/dist/runtime/components/Shared/StateCard.d.vue.ts +32 -0
  65. package/{components → dist/runtime/components}/Shared/StateCard.vue +21 -36
  66. package/dist/runtime/components/Shared/StateCard.vue.d.ts +32 -0
  67. package/dist/runtime/components/Shared/StudioCard.d.vue.ts +15 -0
  68. package/dist/runtime/components/Shared/StudioCard.vue +19 -0
  69. package/dist/runtime/components/Shared/StudioCard.vue.d.ts +15 -0
  70. package/dist/runtime/components/Shared/TabBar.d.vue.ts +23 -0
  71. package/{components → dist/runtime/components}/Shared/TabBar.vue +7 -16
  72. package/dist/runtime/components/Shared/TabBar.vue.d.ts +23 -0
  73. package/dist/runtime/components/Shared/ViewTab.d.vue.ts +7 -0
  74. package/{components → dist/runtime/components}/Shared/ViewTab.vue +7 -9
  75. package/dist/runtime/components/Shared/ViewTab.vue.d.ts +7 -0
  76. package/dist/runtime/components/Shared/Wizard.d.vue.ts +47 -0
  77. package/dist/runtime/components/Shared/Wizard.vue +66 -0
  78. package/dist/runtime/components/Shared/Wizard.vue.d.ts +47 -0
  79. package/dist/runtime/composables/useListRail.d.ts +9 -0
  80. package/dist/runtime/composables/useListRail.js +19 -0
  81. package/dist/runtime/composables/useMediaLibrary.d.ts +41 -0
  82. package/dist/runtime/composables/useMediaLibrary.js +36 -0
  83. package/dist/runtime/composables/usePlatformAuth.d.ts +35 -0
  84. package/dist/runtime/composables/usePlatformAuth.js +17 -0
  85. package/dist/runtime/composables/usePlatformTalkback.d.ts +29 -0
  86. package/dist/runtime/composables/usePlatformTalkback.js +54 -0
  87. package/dist/runtime/composables/usePlatformTenant.d.ts +14 -0
  88. package/dist/runtime/composables/usePlatformTenant.js +18 -0
  89. package/dist/runtime/composables/useT.d.ts +11 -0
  90. package/dist/runtime/composables/useT.js +8 -0
  91. package/dist/runtime/composables/useTalkbackChannels.d.ts +78 -0
  92. package/dist/runtime/composables/useTalkbackChannels.js +52 -0
  93. package/dist/runtime/lib/formatBridge.d.ts +50 -0
  94. package/dist/runtime/lib/formatBridge.js +54 -0
  95. package/dist/runtime/lib/i18nBridge.d.ts +31 -0
  96. package/dist/runtime/lib/i18nBridge.js +17 -0
  97. package/dist/runtime/lib/isoLists.d.ts +61 -0
  98. package/dist/runtime/lib/isoLists.js +62 -0
  99. package/dist/runtime/lib/sidebarNav.d.ts +34 -0
  100. package/dist/runtime/lib/sidebarNav.js +22 -0
  101. package/dist/runtime/lib/talkback.d.ts +59 -0
  102. package/dist/runtime/lib/talkback.js +49 -0
  103. package/dist/runtime/types/nav.d.ts +37 -0
  104. package/dist/runtime/types/nav.js +0 -0
  105. package/dist/runtime/types/storage.d.ts +67 -0
  106. package/dist/runtime/types/storage.js +0 -0
  107. package/dist/types.d.mts +27 -0
  108. package/package.json +41 -13
  109. package/components/DataTable/DataTable.vue +0 -518
  110. package/components/DataTable/FilterMenu.vue +0 -40
  111. package/components/DataTable/types.ts +0 -82
  112. package/components/Shared/GitDeploymentSettings.vue +0 -87
  113. package/components/Shared/SidebarNav.vue +0 -100
  114. package/components/Shared/SortHeader.vue +0 -50
  115. package/components/Shared/StudioCard.vue +0 -24
  116. package/components/Shared/Wizard.vue +0 -80
  117. package/composables/usePlatformAuth.ts +0 -35
  118. package/composables/usePlatformTenant.ts +0 -35
  119. package/index.ts +0 -16
  120. package/nuxt.config.ts +0 -23
@@ -0,0 +1,31 @@
1
+ import type { Ref } from 'vue';
2
+ /** Interpolation values for a message with `{placeholders}`. */
3
+ export type TranslateNamed = Record<string, unknown>;
4
+ /**
5
+ * The subset of vue-i18n's `t` the packages are allowed to rely on:
6
+ * `t(key)`, `t(key, named)`, `t(key, plural)`, `t(key, plural, named)`.
7
+ */
8
+ export interface Translate {
9
+ (key: string): string;
10
+ (key: string, named: TranslateNamed): string;
11
+ (key: string, plural: number): string;
12
+ (key: string, plural: number, named: TranslateNamed): string;
13
+ }
14
+ export interface Translator {
15
+ t: Translate;
16
+ /** The host's current UI locale. Reactive, so computeds re-run on a switch. */
17
+ locale: Ref<string>;
18
+ }
19
+ /** Called once by the host. Pass `null` to detach (tests). */
20
+ export declare function setTranslator(translator: Translator | null): void;
21
+ /** Whether a host translator is installed. Rarely needed — prefer `translate`. */
22
+ export declare function hasTranslator(): boolean;
23
+ /** The host's current UI locale, or `'en'` when the host has no i18n. */
24
+ export declare function currentLocale(): string;
25
+ /**
26
+ * Translate through the host, or return the key unchanged.
27
+ *
28
+ * Reads `locale.value` before delegating so the caller picks up a reactive
29
+ * dependency on the locale even if the host's `t` were to memoize.
30
+ */
31
+ export declare const translate: Translate;
@@ -0,0 +1,17 @@
1
+ import { shallowRef } from "vue";
2
+ const registered = shallowRef(null);
3
+ export function setTranslator(translator) {
4
+ registered.value = translator;
5
+ }
6
+ export function hasTranslator() {
7
+ return registered.value !== null;
8
+ }
9
+ export function currentLocale() {
10
+ return registered.value?.locale.value ?? "en";
11
+ }
12
+ export const translate = ((key, ...args) => {
13
+ const translator = registered.value;
14
+ if (!translator) return key;
15
+ void translator.locale.value;
16
+ return translator.t(key, ...args);
17
+ });
@@ -0,0 +1,61 @@
1
+ /**
2
+ * The two international lists every studio ends up needing: countries
3
+ * (ISO 3166-1 alpha-2) and currencies (ISO 4217).
4
+ *
5
+ * They live in `studio-shared` rather than in a studio because a country is
6
+ * not a Commerce concern — Mail wants a sender country, Analytics wants a
7
+ * region breakdown, and whichever surface asked second would otherwise make
8
+ * the second copy. This module is that first copy, and the only one.
9
+ *
10
+ * ## Codes are data, names are derived
11
+ *
12
+ * The country CODES are written out here, because that literally is the
13
+ * standard: 249 two-letter identifiers, stable, and not enumerable from any
14
+ * runtime API. The NAMES are not written out — `Intl.DisplayNames` has them
15
+ * for every locale the browser ships, so a German cockpit reads
16
+ * "Vereinigtes Königreich" without anyone translating a hardcoded English
17
+ * list. Currencies need neither: `Intl.supportedValuesOf('currency')` is the
18
+ * code list, and `Intl.DisplayNames` is the names.
19
+ *
20
+ * The practical consequence is that adding a language costs nothing here.
21
+ *
22
+ * ## Sorted by the label, never by the code
23
+ *
24
+ * An operator scans a country list alphabetically by what they read.
25
+ * "Ägypten" belongs at the top of a German list and "Egypt" belongs under E;
26
+ * sorting by `EG` would put it in neither place. So every list is collated in
27
+ * the locale it is being displayed in, and the sort is redone per locale.
28
+ * The result is cached per locale — the collation is the expensive part and
29
+ * the answer never changes within a session.
30
+ */
31
+ /**
32
+ * The locale the lists are labelled in when a caller does not say. The cockpit
33
+ * is German-facing; when a real `useLocale()` lands, pass it through and this
34
+ * default stops being used.
35
+ */
36
+ export declare const DEFAULT_ISO_LOCALE = "de";
37
+ /** One choice: the stored code plus what a human reads in their language. */
38
+ export interface IsoOption {
39
+ /** The value written to the column — `'DE'`, `'EUR'`. */
40
+ code: string;
41
+ /** Localized name — `'Deutschland'`, `'Euro'`. Falls back to the code. */
42
+ label: string;
43
+ }
44
+ /** ISO 3166-1 alpha-2, unsorted. Use `countryOptions()` to display them. */
45
+ export declare function countryCodes(): readonly string[];
46
+ /**
47
+ * ISO 4217, as the runtime knows it. Empty on an engine without
48
+ * `Intl.supportedValuesOf` — callers treat that like any other unresolvable
49
+ * list and fall back to whatever literal options they were given.
50
+ */
51
+ export declare function currencyCodes(): readonly string[];
52
+ /** Drop the memoised lists — for tests, and after a language switch. */
53
+ export declare function clearIsoListCache(): void;
54
+ /** Every country, sorted by its name in `locale`. */
55
+ export declare function countryOptions(locale?: string): IsoOption[];
56
+ /** Every currency the runtime knows, sorted by its name in `locale`. */
57
+ export declare function currencyOptions(locale?: string): IsoOption[];
58
+ /** `'DE'` → `'Deutschland'`. Unknown codes come back unchanged. */
59
+ export declare function countryLabel(code: unknown, locale?: string): string;
60
+ /** `'EUR'` → `'Euro'`. Unknown codes come back unchanged. */
61
+ export declare function currencyLabel(code: unknown, locale?: string): string;
@@ -0,0 +1,62 @@
1
+ const COUNTRY_CODES = Object.freeze(
2
+ "AD AE AF AG AI AL AM AO AQ AR AS AT AU AW AX AZ BA BB BD BE BF BG BH BI BJ BL BM BN BO BQ BR BS BT BV BW BY BZ CA CC CD CF CG CH CI CK CL CM CN CO CR CU CV CW CX CY CZ DE DJ DK DM DO DZ EC EE EG EH ER ES ET FI FJ FK FM FO FR GA GB GD GE GF GG GH GI GL GM GN GP GQ GR GS GT GU GW GY HK HM HN HR HT HU ID IE IL IM IN IO IQ IR IS IT JE JM JO JP KE KG KH KI KM KN KP KR KW KY KZ LA LB LC LI LK LR LS LT LU LV LY MA MC MD ME MF MG MH MK ML MM MN MO MP MQ MR MS MT MU MV MW MX MY MZ NA NC NE NF NG NI NL NO NP NR NU NZ OM PA PE PF PG PH PK PL PM PN PR PS PT PW PY QA RE RO RS RU RW SA SB SC SD SE SG SH SI SJ SK SL SM SN SO SR SS ST SV SX SY SZ TC TD TF TG TH TJ TK TL TM TN TO TR TT TV TW TZ UA UG UM US UY UZ VA VC VE VG VI VN VU WF WS YE YT ZA ZM ZW".split(" ")
3
+ );
4
+ export const DEFAULT_ISO_LOCALE = "de";
5
+ export function countryCodes() {
6
+ return COUNTRY_CODES;
7
+ }
8
+ export function currencyCodes() {
9
+ const supported = Intl.supportedValuesOf;
10
+ if (typeof supported !== "function") return [];
11
+ try {
12
+ return Object.freeze(supported.call(Intl, "currency"));
13
+ } catch {
14
+ return [];
15
+ }
16
+ }
17
+ function displayNames(type, locale) {
18
+ try {
19
+ return new Intl.DisplayNames([locale], { type, fallback: "code" });
20
+ } catch {
21
+ return null;
22
+ }
23
+ }
24
+ function collator(locale) {
25
+ try {
26
+ return new Intl.Collator(locale);
27
+ } catch {
28
+ return { compare: (a, b) => a < b ? -1 : a > b ? 1 : 0 };
29
+ }
30
+ }
31
+ function build(codes, type, locale) {
32
+ const names = displayNames(type, locale);
33
+ const compare = collator(locale).compare;
34
+ return codes.map((code) => ({ code, label: names?.of(code) || code })).sort((a, b) => compare(a.label, b.label));
35
+ }
36
+ const cache = /* @__PURE__ */ new Map();
37
+ function cached(key, make) {
38
+ const hit = cache.get(key);
39
+ if (hit) return hit;
40
+ const built = make();
41
+ cache.set(key, built);
42
+ return built;
43
+ }
44
+ export function clearIsoListCache() {
45
+ cache.clear();
46
+ }
47
+ export function countryOptions(locale = DEFAULT_ISO_LOCALE) {
48
+ return cached(`region:${locale}`, () => build(COUNTRY_CODES, "region", locale));
49
+ }
50
+ export function currencyOptions(locale = DEFAULT_ISO_LOCALE) {
51
+ return cached(`currency:${locale}`, () => build(currencyCodes(), "currency", locale));
52
+ }
53
+ export function countryLabel(code, locale = DEFAULT_ISO_LOCALE) {
54
+ const key = typeof code === "string" ? code.trim().toUpperCase() : "";
55
+ if (!key) return "";
56
+ return displayNames("region", locale)?.of(key) || key;
57
+ }
58
+ export function currencyLabel(code, locale = DEFAULT_ISO_LOCALE) {
59
+ const key = typeof code === "string" ? code.trim().toUpperCase() : "";
60
+ if (!key) return "";
61
+ return displayNames("currency", locale)?.of(key) || key;
62
+ }
@@ -0,0 +1,34 @@
1
+ import type { SidebarNavItem } from '../types/nav.js';
2
+ /**
3
+ * Pure helpers behind `SidebarNav` / `SidebarNavLink`. They live outside the
4
+ * SFCs so the active-route and link-target rules can be tested without
5
+ * mounting a component (and so both SFCs share exactly one implementation).
6
+ *
7
+ * **`children` means tabs, not sub-navigation.** An item with children is one
8
+ * sidebar row; its children are the tabs of the page that row opens. Nothing
9
+ * here expands, so there is no collapse state to keep — the row is a link like
10
+ * any other, it just knows about the routes its tabs carry. Anything that
11
+ * should stand on its own in the sidebar is declared as its own item.
12
+ */
13
+ /** Stable identity for `v-for` keys — `to` is unique where it exists. */
14
+ export declare function sidebarItemKey(item: SidebarNavItem): string;
15
+ /** True when `path` is the item's own route, or sits below it. */
16
+ export declare function sidebarItemIsActive(item: SidebarNavItem, path: string): boolean;
17
+ /** True when the item, or any of its tabs, matches `path`. */
18
+ export declare function sidebarItemHoldsActive(item: SidebarNavItem, path: string): boolean;
19
+ /**
20
+ * Which row gets the highlight. The tabs of a group are not rows of their own,
21
+ * so the group stays lit for every one of them — an operator on *Carriers*
22
+ * still sees where they are, which is **Shipping**.
23
+ */
24
+ export declare function sidebarItemIsCurrent(item: SidebarNavItem, path: string): boolean;
25
+ /**
26
+ * Where the row links. A group with a route of its own opens that (it is the
27
+ * default tab); a pure container — a heading several apps contribute to, where
28
+ * no single app's view is the right landing page — opens its first tab.
29
+ *
30
+ * `undefined` means the row has nothing to open at all. `navCompose` prunes
31
+ * those before they reach a sidebar, but the guard keeps a hand-written
32
+ * section (Settings, Apps, …) from rendering a dead row.
33
+ */
34
+ export declare function sidebarItemTarget(item: SidebarNavItem): string | undefined;
@@ -0,0 +1,22 @@
1
+ export function sidebarItemKey(item) {
2
+ return item.key ?? item.to ?? item.label;
3
+ }
4
+ export function sidebarItemIsActive(item, path) {
5
+ if (!item.to) return false;
6
+ if (item.exact) return path === item.to;
7
+ return path === item.to || path.startsWith(`${item.to}/`);
8
+ }
9
+ export function sidebarItemHoldsActive(item, path) {
10
+ return sidebarItemIsActive(item, path) || (item.children ?? []).some((child) => sidebarItemHoldsActive(child, path));
11
+ }
12
+ export function sidebarItemIsCurrent(item, path) {
13
+ return sidebarItemHoldsActive(item, path);
14
+ }
15
+ export function sidebarItemTarget(item) {
16
+ if (item.to) return item.to;
17
+ for (const child of item.children ?? []) {
18
+ const target = sidebarItemTarget(child);
19
+ if (target) return target;
20
+ }
21
+ return void 0;
22
+ }
@@ -0,0 +1,59 @@
1
+ import type { ShallowRef } from 'vue';
2
+ import type { Talkback, TalkbackOptions } from '@revenexx/talkback-js';
3
+ export interface PlatformTalkbackConfig {
4
+ /** Centrifugo's client transport, e.g. `https://talkback.revenexx.com`. */
5
+ host: string;
6
+ /**
7
+ * Where a connection token is minted. The facade's own `${host}/v1/tokens` by
8
+ * default — the browser's Zitadel token authorises it directly, so no BFF route
9
+ * stands in between.
10
+ */
11
+ tokenEndpoint: string;
12
+ /** Likewise, `${host}/v1/subscription-tokens`. */
13
+ subscriptionTokenEndpoint: string;
14
+ /**
15
+ * The active tenant slug. A GETTER, not a value: operator impersonation
16
+ * changes it at run time, and it is positionally first in every channel name.
17
+ */
18
+ tenant: () => string;
19
+ /**
20
+ * The caller's Zitadel access token, passed to the facade as the bearer.
21
+ *
22
+ * The facade admits it because an end user holds `user` or `admin` in the
23
+ * Zitadel USER project, and such a caller may mint only for itself: the request
24
+ * carries no `user_id` and the facade fills it from this token's own `sub`.
25
+ */
26
+ getToken: () => Promise<string | null>;
27
+ /**
28
+ * Replaces the Centrifuge client. Left unset outside tests — the fake in
29
+ * `@revenexx/talkback-js/testing` satisfies it.
30
+ */
31
+ client?: TalkbackOptions['client'];
32
+ debug?: boolean;
33
+ }
34
+ /**
35
+ * The `sub` claim of a JWT, or null when it isn't one.
36
+ *
37
+ * This is where the client's `userId` comes from, and the choice is
38
+ * load-bearing rather than convenient. The BFF derives the token's subject from
39
+ * the same claim of the same token, so client and server cannot disagree about
40
+ * the name of the `user:` channel — a mismatch would mint a grant for one name
41
+ * and subscribe to another, which fails as a silent 403 on a channel nobody
42
+ * publishes to. Deliberately NOT verified: nothing is authorised here, and the
43
+ * BFF verifies the signature before it grants anything.
44
+ *
45
+ * Mirrors the base64url handling in the cockpit's `useConsoleAuth`.
46
+ */
47
+ export declare function decodeJwtSub(jwt: string | null | undefined): string | null;
48
+ /**
49
+ * Builds the client for a host.
50
+ *
51
+ * `tenant` and `userId` are providers because talkback-js reads them on every
52
+ * channel build; passing values would pin the first tenant the page saw.
53
+ */
54
+ export declare function createPlatformTalkback(config: PlatformTalkbackConfig): Promise<Talkback>;
55
+ /** Registered once by the host's provider. Pass `null` to detach (tests). */
56
+ export declare function setTalkback(tb: Talkback | null): void;
57
+ export declare function getTalkback(): Talkback | null;
58
+ /** The registry itself, for composables that must react to it appearing. */
59
+ export declare function talkbackRef(): ShallowRef<Talkback | null>;
@@ -0,0 +1,49 @@
1
+ import { shallowRef } from "vue";
2
+ export function decodeJwtSub(jwt) {
3
+ if (!jwt) return null;
4
+ try {
5
+ const parts = jwt.split(".");
6
+ if (parts.length !== 3) return null;
7
+ const p = parts[1].replace(/-/g, "+").replace(/_/g, "/");
8
+ const b64 = p.padEnd(p.length + (4 - p.length % 4) % 4, "=");
9
+ const claims = JSON.parse(atob(b64));
10
+ return typeof claims.sub === "string" && claims.sub ? claims.sub : null;
11
+ } catch {
12
+ return null;
13
+ }
14
+ }
15
+ export async function createPlatformTalkback(config) {
16
+ const { createTalkback } = await import("@revenexx/talkback-js");
17
+ let userId = "";
18
+ const accessToken = async () => {
19
+ const token = await config.getToken();
20
+ if (token) {
21
+ userId = decodeJwtSub(token) ?? userId;
22
+ }
23
+ return token;
24
+ };
25
+ try {
26
+ userId = decodeJwtSub(await config.getToken()) ?? "";
27
+ } catch {
28
+ }
29
+ return createTalkback({
30
+ host: config.host,
31
+ tenant: () => config.tenant(),
32
+ userId: () => userId,
33
+ tokenEndpoint: config.tokenEndpoint,
34
+ subscriptionTokenEndpoint: config.subscriptionTokenEndpoint,
35
+ accessToken,
36
+ ...config.client ? { client: config.client } : {},
37
+ ...config.debug === void 0 ? {} : { debug: config.debug }
38
+ });
39
+ }
40
+ const current = shallowRef(null);
41
+ export function setTalkback(tb) {
42
+ current.value = tb;
43
+ }
44
+ export function getTalkback() {
45
+ return current.value;
46
+ }
47
+ export function talkbackRef() {
48
+ return current;
49
+ }
@@ -0,0 +1,37 @@
1
+ import type { Component } from 'vue';
2
+ /**
3
+ * SidebarNav data shapes. They live in a plain .ts file (not the SFC) so the
4
+ * package barrel can re-export them without dragging a `.vue` import into
5
+ * node-side type resolution (the module dts build / plain tsc can't follow
6
+ * type re-exports through an SFC).
7
+ */
8
+ export type SidebarNavItem = {
9
+ label: string;
10
+ /**
11
+ * Target route. Omit it for a pure container — a heading several apps
12
+ * contribute pages to, where no single view is the right landing page. The
13
+ * row then links to the first of its `children` instead.
14
+ */
15
+ to?: string;
16
+ icon?: Component;
17
+ badge?: number | string | null;
18
+ /** Dim + show a "soon" tag (not-yet-shipped surfaces). */
19
+ preview?: boolean;
20
+ /** Match the route exactly (for studio roots like `/settings`). */
21
+ exact?: boolean;
22
+ /**
23
+ * The item's **tabs**, not sub-navigation. The sidebar shows one row; the
24
+ * page it opens shows these across the top, each addressed by its own route
25
+ * (see `studio-commerce/lib/navGroups.ts`). The row stays highlighted on all
26
+ * of them.
27
+ */
28
+ children?: SidebarNavItem[];
29
+ /** Stable `v-for` key. Defaults to `to ?? label`. */
30
+ key?: string;
31
+ };
32
+ export type SidebarNavSection = {
33
+ key: string;
34
+ /** Empty/omitted → no group label (pinned items at the top). */
35
+ label?: string;
36
+ items: SidebarNavItem[];
37
+ };
File without changes
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Media storage service (revenexx/storage) `/v1` API shapes — the subset the
3
+ * shared media components (uploader, folder tree, picker dialog) render.
4
+ *
5
+ * Mirrors the cockpit's `app/types/storage.ts` field-for-field so the two are
6
+ * structurally identical: the cockpit passes its own `StorageAsset` straight
7
+ * into these components and back out of their emits. The module can't import
8
+ * the cockpit's copy (host-only path), so the contract lives here.
9
+ */
10
+ export type AssetKind = 'image' | 'video' | 'audio' | 'pdf' | 'document' | 'archive' | 'model3d' | 'other';
11
+ export type AssetStatus = 'uploading' | 'pending_scan' | 'pending_processing' | 'available' | 'quarantined' | 'processing_failed' | 'soft_deleted';
12
+ export type AssetVisibility = 'public' | 'private';
13
+ export interface StorageAsset {
14
+ id: string;
15
+ tenant_id: string;
16
+ folder_id: string | null;
17
+ kind: AssetKind;
18
+ status: AssetStatus;
19
+ visibility: AssetVisibility;
20
+ mime_type: string;
21
+ original_name: string;
22
+ path_name: string;
23
+ display_name: string | null;
24
+ alt_text: string | null;
25
+ description: string | null;
26
+ tags: string[];
27
+ size_bytes: number;
28
+ content_hash: string | null;
29
+ width: number | null;
30
+ height: number | null;
31
+ duration_ms: number | null;
32
+ page_count: number | null;
33
+ dominant_color: string | null;
34
+ metadata: Record<string, unknown>;
35
+ /** Delivery URL for public assets; null for private (use a signed URL). */
36
+ url: string | null;
37
+ /** 3D assets only: imgproxy-resizable preview image (rendered from the model). */
38
+ preview_url?: string | null;
39
+ /** 3D assets only: the web-renderable mesh (.glb) for <rx-model-viewer>. */
40
+ model_url?: string | null;
41
+ created_at: string | null;
42
+ updated_at: string | null;
43
+ processed_at: string | null;
44
+ deleted_at: string | null;
45
+ }
46
+ export interface StorageFolder {
47
+ id: string;
48
+ tenant_id: string;
49
+ parent_id: string | null;
50
+ name: string;
51
+ /** Full hierarchy path, e.g. `/marketing/q1-campaign`. */
52
+ path: string;
53
+ is_system: boolean;
54
+ created_at: string | null;
55
+ updated_at: string | null;
56
+ }
57
+ /** A folder augmented with its children, for rendering the tree. */
58
+ export interface StorageFolderNode extends StorageFolder {
59
+ children: StorageFolderNode[];
60
+ }
61
+ /** Per-file state while a batch uploads. */
62
+ export interface UploadProgress {
63
+ name: string;
64
+ pct: number;
65
+ status: 'pending' | 'uploading' | 'done' | 'failed';
66
+ error?: string;
67
+ }
File without changes
@@ -0,0 +1,27 @@
1
+ import type { NuxtModule } from '@nuxt/schema'
2
+
3
+ import type { default as Module } from './module.mjs'
4
+
5
+ export type ModuleOptions = typeof Module extends NuxtModule<infer O> ? Partial<O> : Record<string, any>
6
+
7
+ export { type SidebarNavItem, type SidebarNavSection } from '../dist/runtime/types/nav.js'
8
+
9
+ export { type PlatformAuth } from '../dist/runtime/composables/usePlatformAuth.js'
10
+
11
+ export { type PlatformTenant } from '../dist/runtime/composables/usePlatformTenant.js'
12
+
13
+ export { type PlatformTalkback } from '../dist/runtime/composables/usePlatformTalkback.js'
14
+
15
+ export { type TalkbackChannel, type TalkbackChannelOptions, type TalkbackMaybeRef } from '../dist/runtime/composables/useTalkbackChannels.js'
16
+
17
+ export { type MediaLibraryClient } from '../dist/runtime/composables/useMediaLibrary.js'
18
+
19
+ export { type IsoOption } from '../dist/runtime/lib/isoLists.js'
20
+
21
+ export { type Translate, type TranslateNamed, type Translator } from '../dist/runtime/lib/i18nBridge.js'
22
+
23
+ export { default } from './module.mjs'
24
+
25
+ export * from '../dist/runtime/components/DataTable/types.js'
26
+
27
+ export * from '../dist/runtime/types/storage.js'
package/package.json CHANGED
@@ -1,32 +1,60 @@
1
1
  {
2
2
  "name": "@revenexx/studio-shared",
3
- "version": "0.1.2",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
- "description": "Shared revenexx Studio shell primitives (PageHeader, SidebarNav, StateCard, DataTable, …) + the platform provider contract (usePlatformAuth/usePlatformTenant). A Nuxt layer — extend it, then add a studio module.",
6
- "main": "./nuxt.config.ts",
5
+ "description": "Shared revenexx Studio shell primitives (PageHeader, SidebarNav, StateCard, DataTable, …) + the platform provider contract (usePlatformAuth/usePlatformTenant). A Nuxt module — add it to `modules`.",
6
+ "main": "./dist/module.mjs",
7
+ "types": "./dist/types.d.mts",
7
8
  "exports": {
8
9
  ".": {
9
- "types": "./index.ts",
10
- "import": "./index.ts"
10
+ "types": "./dist/types.d.mts",
11
+ "import": "./dist/module.mjs"
11
12
  },
12
- "./nuxt.config": "./nuxt.config.ts",
13
- "./components/*": "./components/*"
13
+ "./components/*": "./dist/runtime/components/*",
14
+ "./lib/*": {
15
+ "types": "./dist/runtime/lib/*.d.ts",
16
+ "import": "./dist/runtime/lib/*.js"
17
+ }
14
18
  },
15
19
  "files": [
16
- "nuxt.config.ts",
17
- "index.ts",
18
- "components",
19
- "composables",
20
+ "dist",
20
21
  "LICENSE"
21
22
  ],
22
23
  "publishConfig": {
23
24
  "registry": "https://registry.npmjs.org/",
24
25
  "access": "public"
25
26
  },
27
+ "dependencies": {
28
+ "@nuxt/kit": "^4.0.0"
29
+ },
26
30
  "peerDependencies": {
27
31
  "@revenexx/studio": "*",
32
+ "@revenexx/talkback-js": "^0.3.0",
33
+ "@solar-icons/nuxt": "^1.2.0",
34
+ "centrifuge": ">=5.2.0",
28
35
  "nuxt": "^4.0.0",
29
- "vue": "^3.5.0"
36
+ "vue": "^3.5.0",
37
+ "vue-sonner": "^2.0.0"
38
+ },
39
+ "peerDependenciesMeta": {
40
+ "@revenexx/talkback-js": {
41
+ "optional": true
42
+ },
43
+ "centrifuge": {
44
+ "optional": true
45
+ }
46
+ },
47
+ "devDependencies": {
48
+ "@nuxt/module-builder": "^1.0.2",
49
+ "@nuxt/kit": "^4.0.0",
50
+ "@revenexx/talkback-js": "^0.3.0",
51
+ "centrifuge": "^5.4.0",
52
+ "nuxt": "^4.2.2",
53
+ "vue": "^3.5.26",
54
+ "vue-tsc": "^2.2.0"
30
55
  },
31
- "license": "SEE LICENSE IN LICENSE"
56
+ "license": "SEE LICENSE IN LICENSE",
57
+ "scripts": {
58
+ "build": "nuxt-module-build build"
59
+ }
32
60
  }