@saasicat/ui-vue 0.8.0 → 0.10.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.
@@ -471,6 +471,76 @@ var BatchColumnFetcher = class {
471
471
  }
472
472
  };
473
473
 
474
+ // src/client/admin-resource-client.ts
475
+ function createAdminResourceClient(options) {
476
+ const base = options.adminBase ?? "/api/v1/admin";
477
+ const tenantsEndpoint = `${base}/tenants`;
478
+ const getJson2 = async (url) => {
479
+ const response = await options.http(url, { method: "GET" });
480
+ assertSuccess(response.status, "GET", url);
481
+ return await response.json();
482
+ };
483
+ const sendJson = async (method, url, body) => {
484
+ const response = await options.http(url, {
485
+ method,
486
+ headers: { "content-type": "application/json" },
487
+ body: body === void 0 ? void 0 : JSON.stringify(body)
488
+ });
489
+ assertSuccess(response.status, method, url);
490
+ return await response.json();
491
+ };
492
+ return {
493
+ tenantsEndpoint,
494
+ loadTenantDetail: (slug) => getJson2(`${tenantsEndpoint}/${encodeURIComponent(slug)}`),
495
+ loadUsers: (filter) => getJson2(
496
+ `${base}/users${queryString({ q: filter.q, tenant: filter.tenant })}`
497
+ ),
498
+ loadAudit: (filter) => getJson2(
499
+ `${base}/audit${queryString({
500
+ actor: filter.actor,
501
+ action: filter.action,
502
+ entity: filter.entity,
503
+ since: filter.since,
504
+ limit: filter.limit
505
+ })}`
506
+ ),
507
+ loadSubscriptions: () => getJson2(`${base}/subscriptions`),
508
+ loadPromos: (filter) => getJson2(
509
+ `${base}/promo-codes${queryString({
510
+ search: filter.search,
511
+ status: filter.status
512
+ })}`
513
+ ),
514
+ createPromo: async (payload) => {
515
+ await sendJson("POST", `${base}/promo-codes`, payload);
516
+ },
517
+ updatePromo: async (id, payload) => {
518
+ await sendJson("PATCH", `${base}/promo-codes/${encodeURIComponent(id)}`, payload);
519
+ },
520
+ deletePromo: async (id) => {
521
+ await sendJson("DELETE", `${base}/promo-codes/${encodeURIComponent(id)}`);
522
+ },
523
+ suspendTenant: (slug, reason) => sendJson("POST", `${tenantsEndpoint}/${encodeURIComponent(slug)}/suspend`, {
524
+ reason
525
+ }),
526
+ reactivateTenant: (slug) => sendJson("POST", `${tenantsEndpoint}/${encodeURIComponent(slug)}/reactivate`)
527
+ };
528
+ }
529
+ function assertSuccess(status, method, url) {
530
+ if (status < 200 || status >= 300) {
531
+ throw new Error(`${method} ${url} \u2192 HTTP ${status}`);
532
+ }
533
+ }
534
+ function queryString(params) {
535
+ const search = new URLSearchParams();
536
+ for (const [key, value2] of Object.entries(params)) {
537
+ if (value2 === void 0 || value2 === null || value2 === "") continue;
538
+ search.set(key, String(value2));
539
+ }
540
+ const value = search.toString();
541
+ return value ? `?${value}` : "";
542
+ }
543
+
474
544
  export {
475
545
  ADMIN_UI_VERSION,
476
546
  HttpJsonError,
@@ -490,5 +560,6 @@ export {
490
560
  ActionDefNotInManifestError,
491
561
  ActionRegistry,
492
562
  BatchColumnDriftError,
493
- BatchColumnFetcher
563
+ BatchColumnFetcher,
564
+ createAdminResourceClient
494
565
  };
@@ -38,6 +38,7 @@ __export(client_exports, {
38
38
  SA_MESSAGES: () => SA_MESSAGES,
39
39
  buildRoutes: () => buildRoutes,
40
40
  buildSidebar: () => buildSidebar,
41
+ createAdminResourceClient: () => createAdminResourceClient,
41
42
  defaultHttpClient: () => defaultHttpClient,
42
43
  defaultKvStore: () => defaultKvStore,
43
44
  defaultSectionOrder: () => defaultSectionOrder,
@@ -620,6 +621,76 @@ var BatchColumnFetcher = class {
620
621
  }
621
622
  };
622
623
 
624
+ // src/client/admin-resource-client.ts
625
+ function createAdminResourceClient(options) {
626
+ const base = options.adminBase ?? "/api/v1/admin";
627
+ const tenantsEndpoint = `${base}/tenants`;
628
+ const getJson2 = async (url) => {
629
+ const response = await options.http(url, { method: "GET" });
630
+ assertSuccess(response.status, "GET", url);
631
+ return await response.json();
632
+ };
633
+ const sendJson = async (method, url, body) => {
634
+ const response = await options.http(url, {
635
+ method,
636
+ headers: { "content-type": "application/json" },
637
+ body: body === void 0 ? void 0 : JSON.stringify(body)
638
+ });
639
+ assertSuccess(response.status, method, url);
640
+ return await response.json();
641
+ };
642
+ return {
643
+ tenantsEndpoint,
644
+ loadTenantDetail: (slug) => getJson2(`${tenantsEndpoint}/${encodeURIComponent(slug)}`),
645
+ loadUsers: (filter) => getJson2(
646
+ `${base}/users${queryString({ q: filter.q, tenant: filter.tenant })}`
647
+ ),
648
+ loadAudit: (filter) => getJson2(
649
+ `${base}/audit${queryString({
650
+ actor: filter.actor,
651
+ action: filter.action,
652
+ entity: filter.entity,
653
+ since: filter.since,
654
+ limit: filter.limit
655
+ })}`
656
+ ),
657
+ loadSubscriptions: () => getJson2(`${base}/subscriptions`),
658
+ loadPromos: (filter) => getJson2(
659
+ `${base}/promo-codes${queryString({
660
+ search: filter.search,
661
+ status: filter.status
662
+ })}`
663
+ ),
664
+ createPromo: async (payload) => {
665
+ await sendJson("POST", `${base}/promo-codes`, payload);
666
+ },
667
+ updatePromo: async (id, payload) => {
668
+ await sendJson("PATCH", `${base}/promo-codes/${encodeURIComponent(id)}`, payload);
669
+ },
670
+ deletePromo: async (id) => {
671
+ await sendJson("DELETE", `${base}/promo-codes/${encodeURIComponent(id)}`);
672
+ },
673
+ suspendTenant: (slug, reason) => sendJson("POST", `${tenantsEndpoint}/${encodeURIComponent(slug)}/suspend`, {
674
+ reason
675
+ }),
676
+ reactivateTenant: (slug) => sendJson("POST", `${tenantsEndpoint}/${encodeURIComponent(slug)}/reactivate`)
677
+ };
678
+ }
679
+ function assertSuccess(status, method, url) {
680
+ if (status < 200 || status >= 300) {
681
+ throw new Error(`${method} ${url} \u2192 HTTP ${status}`);
682
+ }
683
+ }
684
+ function queryString(params) {
685
+ const search = new URLSearchParams();
686
+ for (const [key, value2] of Object.entries(params)) {
687
+ if (value2 === void 0 || value2 === null || value2 === "") continue;
688
+ search.set(key, String(value2));
689
+ }
690
+ const value = search.toString();
691
+ return value ? `?${value}` : "";
692
+ }
693
+
623
694
  // src/client/i18n/format.ts
624
695
  function formatMessage(template, params) {
625
696
  return template.replace(/\{(\w+)\}/g, (match, name) => {
@@ -3618,6 +3689,7 @@ function resolveMessages(locale, overrides) {
3618
3689
  SA_MESSAGES,
3619
3690
  buildRoutes,
3620
3691
  buildSidebar,
3692
+ createAdminResourceClient,
3621
3693
  defaultHttpClient,
3622
3694
  defaultKvStore,
3623
3695
  defaultSectionOrder,
@@ -1,6 +1,6 @@
1
1
  import { H as HttpClient, K as KvStore, S as SaLocale } from '../messages-BIYw32u1.cjs';
2
2
  export { d as ActionDefNotInManifestError, A as ActionHandler, c as ActionRegistry, D as DEFAULT_SA_LOCALE, e as HttpResponse, M as MessageTree, f as MissingHandlerError, P as PartialMessages, R as ResolvedAction, g as SA_INTL_LOCALES, h as SA_LOCALES, i as SA_MESSAGES, a as SaMessages, b as SaMessagesOverrides, T as TranslationOf, j as defaultHttpClient, k as defaultKvStore, l as defineMessages, m as mergeMessages, r as resolveMessages } from '../messages-BIYw32u1.cjs';
3
- import { PublicBootResponse, AdminManifest, StandardPageKey, TenantColumnDef } from '@saasicat/types';
3
+ import { PublicBootResponse, AdminManifest, StandardPageKey, TenantColumnDef, PromoCodeRecord, AdminTenantDetail, AdminUserListFilter, AdminUserListRow, AdminAuditListFilter, AuditEntry, AdminSubscriptionListRow } from '@saasicat/types';
4
4
 
5
5
  declare const ADMIN_UI_VERSION = "1.2.0";
6
6
 
@@ -247,6 +247,39 @@ declare class BatchColumnFetcher {
247
247
  private buildUrl;
248
248
  }
249
249
 
250
+ interface AdminResourceClientOptions {
251
+ http: HttpClient;
252
+ /** Default `/api/v1/admin`. */
253
+ adminBase?: string;
254
+ }
255
+ /** Filters accepted by the standard PromoCodesPage, including its "all" state. */
256
+ interface AdminPromoListFilter {
257
+ search?: string;
258
+ status?: string | null;
259
+ }
260
+ /** Promo row shape used by the extensible standard Admin table. */
261
+ interface AdminPromoListRow extends PromoCodeRecord {
262
+ [extra: string]: unknown;
263
+ }
264
+ /**
265
+ * Ready-to-use client for the standard SaaSiCat AdminResources and promo
266
+ * controllers. App wrappers pass these functions straight to the standard
267
+ * pages; no repeated fetch/error/query-string plumbing is needed.
268
+ */
269
+ declare function createAdminResourceClient(options: AdminResourceClientOptions): {
270
+ tenantsEndpoint: string;
271
+ loadTenantDetail: (slug: string) => Promise<AdminTenantDetail>;
272
+ loadUsers: (filter: AdminUserListFilter) => Promise<AdminUserListRow[]>;
273
+ loadAudit: (filter: AdminAuditListFilter) => Promise<AuditEntry[]>;
274
+ loadSubscriptions: () => Promise<AdminSubscriptionListRow[]>;
275
+ loadPromos: (filter: AdminPromoListFilter) => Promise<AdminPromoListRow[]>;
276
+ createPromo: (payload: unknown) => Promise<void>;
277
+ updatePromo: (id: string, payload: unknown) => Promise<void>;
278
+ deletePromo: (id: string) => Promise<void>;
279
+ suspendTenant: (slug: string, reason: string) => Promise<unknown>;
280
+ reactivateTenant: (slug: string) => Promise<unknown>;
281
+ };
282
+
250
283
  type MessageParams = Record<string, string | number>;
251
284
  declare function formatMessage(template: string, params: MessageParams): string;
252
285
 
@@ -260,4 +293,4 @@ declare function formatMessage(template: string, params: MessageParams): string;
260
293
  */
261
294
  declare function formatCurrency(amount: number | string | null | undefined, locale?: SaLocale, currency?: string): string;
262
295
 
263
- export { ADMIN_UI_VERSION, type BatchColumnData, BatchColumnDriftError, BatchColumnFetcher, type BatchColumnFetcherOptions, type BatchColumnRow, type BatchColumnValue, BootLoadError, BootLoader, type BootLoaderOptions, type BuildRouteEntry, type CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpClient, HttpJsonError, KvStore, ManifestLoadError, ManifestLoader, type ManifestLoaderOptions, type MessageParams, type NavBuilderOptions, type ParamStyle, SaLocale, type SidebarItem, type SidebarSection, buildRoutes, buildSidebar, defaultSectionOrder, formatCurrency, formatMessage, getJson, postJson, resolveExtension, trimTrailingSlashes };
296
+ export { ADMIN_UI_VERSION, type AdminPromoListFilter, type AdminPromoListRow, type AdminResourceClientOptions, type BatchColumnData, BatchColumnDriftError, BatchColumnFetcher, type BatchColumnFetcherOptions, type BatchColumnRow, type BatchColumnValue, BootLoadError, BootLoader, type BootLoaderOptions, type BuildRouteEntry, type CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpClient, HttpJsonError, KvStore, ManifestLoadError, ManifestLoader, type ManifestLoaderOptions, type MessageParams, type NavBuilderOptions, type ParamStyle, SaLocale, type SidebarItem, type SidebarSection, buildRoutes, buildSidebar, createAdminResourceClient, defaultSectionOrder, formatCurrency, formatMessage, getJson, postJson, resolveExtension, trimTrailingSlashes };
@@ -1,6 +1,6 @@
1
1
  import { H as HttpClient, K as KvStore, S as SaLocale } from '../messages-BIYw32u1.js';
2
2
  export { d as ActionDefNotInManifestError, A as ActionHandler, c as ActionRegistry, D as DEFAULT_SA_LOCALE, e as HttpResponse, M as MessageTree, f as MissingHandlerError, P as PartialMessages, R as ResolvedAction, g as SA_INTL_LOCALES, h as SA_LOCALES, i as SA_MESSAGES, a as SaMessages, b as SaMessagesOverrides, T as TranslationOf, j as defaultHttpClient, k as defaultKvStore, l as defineMessages, m as mergeMessages, r as resolveMessages } from '../messages-BIYw32u1.js';
3
- import { PublicBootResponse, AdminManifest, StandardPageKey, TenantColumnDef } from '@saasicat/types';
3
+ import { PublicBootResponse, AdminManifest, StandardPageKey, TenantColumnDef, PromoCodeRecord, AdminTenantDetail, AdminUserListFilter, AdminUserListRow, AdminAuditListFilter, AuditEntry, AdminSubscriptionListRow } from '@saasicat/types';
4
4
 
5
5
  declare const ADMIN_UI_VERSION = "1.2.0";
6
6
 
@@ -247,6 +247,39 @@ declare class BatchColumnFetcher {
247
247
  private buildUrl;
248
248
  }
249
249
 
250
+ interface AdminResourceClientOptions {
251
+ http: HttpClient;
252
+ /** Default `/api/v1/admin`. */
253
+ adminBase?: string;
254
+ }
255
+ /** Filters accepted by the standard PromoCodesPage, including its "all" state. */
256
+ interface AdminPromoListFilter {
257
+ search?: string;
258
+ status?: string | null;
259
+ }
260
+ /** Promo row shape used by the extensible standard Admin table. */
261
+ interface AdminPromoListRow extends PromoCodeRecord {
262
+ [extra: string]: unknown;
263
+ }
264
+ /**
265
+ * Ready-to-use client for the standard SaaSiCat AdminResources and promo
266
+ * controllers. App wrappers pass these functions straight to the standard
267
+ * pages; no repeated fetch/error/query-string plumbing is needed.
268
+ */
269
+ declare function createAdminResourceClient(options: AdminResourceClientOptions): {
270
+ tenantsEndpoint: string;
271
+ loadTenantDetail: (slug: string) => Promise<AdminTenantDetail>;
272
+ loadUsers: (filter: AdminUserListFilter) => Promise<AdminUserListRow[]>;
273
+ loadAudit: (filter: AdminAuditListFilter) => Promise<AuditEntry[]>;
274
+ loadSubscriptions: () => Promise<AdminSubscriptionListRow[]>;
275
+ loadPromos: (filter: AdminPromoListFilter) => Promise<AdminPromoListRow[]>;
276
+ createPromo: (payload: unknown) => Promise<void>;
277
+ updatePromo: (id: string, payload: unknown) => Promise<void>;
278
+ deletePromo: (id: string) => Promise<void>;
279
+ suspendTenant: (slug: string, reason: string) => Promise<unknown>;
280
+ reactivateTenant: (slug: string) => Promise<unknown>;
281
+ };
282
+
250
283
  type MessageParams = Record<string, string | number>;
251
284
  declare function formatMessage(template: string, params: MessageParams): string;
252
285
 
@@ -260,4 +293,4 @@ declare function formatMessage(template: string, params: MessageParams): string;
260
293
  */
261
294
  declare function formatCurrency(amount: number | string | null | undefined, locale?: SaLocale, currency?: string): string;
262
295
 
263
- export { ADMIN_UI_VERSION, type BatchColumnData, BatchColumnDriftError, BatchColumnFetcher, type BatchColumnFetcherOptions, type BatchColumnRow, type BatchColumnValue, BootLoadError, BootLoader, type BootLoaderOptions, type BuildRouteEntry, type CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpClient, HttpJsonError, KvStore, ManifestLoadError, ManifestLoader, type ManifestLoaderOptions, type MessageParams, type NavBuilderOptions, type ParamStyle, SaLocale, type SidebarItem, type SidebarSection, buildRoutes, buildSidebar, defaultSectionOrder, formatCurrency, formatMessage, getJson, postJson, resolveExtension, trimTrailingSlashes };
296
+ export { ADMIN_UI_VERSION, type AdminPromoListFilter, type AdminPromoListRow, type AdminResourceClientOptions, type BatchColumnData, BatchColumnDriftError, BatchColumnFetcher, type BatchColumnFetcherOptions, type BatchColumnRow, type BatchColumnValue, BootLoadError, BootLoader, type BootLoaderOptions, type BuildRouteEntry, type CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpClient, HttpJsonError, KvStore, ManifestLoadError, ManifestLoader, type ManifestLoaderOptions, type MessageParams, type NavBuilderOptions, type ParamStyle, SaLocale, type SidebarItem, type SidebarSection, buildRoutes, buildSidebar, createAdminResourceClient, defaultSectionOrder, formatCurrency, formatMessage, getJson, postJson, resolveExtension, trimTrailingSlashes };
@@ -13,12 +13,13 @@ import {
13
13
  MissingHandlerError,
14
14
  buildRoutes,
15
15
  buildSidebar,
16
+ createAdminResourceClient,
16
17
  defaultSectionOrder,
17
18
  getJson,
18
19
  postJson,
19
20
  resolveExtension,
20
21
  trimTrailingSlashes
21
- } from "../chunk-7N3CJTOA.js";
22
+ } from "../chunk-66BUSVC5.js";
22
23
  import {
23
24
  DEFAULT_SA_LOCALE,
24
25
  SA_INTL_LOCALES,
@@ -51,6 +52,7 @@ export {
51
52
  SA_MESSAGES,
52
53
  buildRoutes,
53
54
  buildSidebar,
55
+ createAdminResourceClient,
54
56
  defaultHttpClient,
55
57
  defaultKvStore,
56
58
  defaultSectionOrder,
package/dist/index.cjs CHANGED
@@ -65,6 +65,7 @@ __export(src_exports, {
65
65
  buildQuotaRegistry: () => buildQuotaRegistry,
66
66
  buildRoutes: () => buildRoutes,
67
67
  buildSidebar: () => buildSidebar,
68
+ createAdminResourceClient: () => createAdminResourceClient,
68
69
  createAdminRoutes: () => createAdminRoutes,
69
70
  createManifestStore: () => createManifestStore,
70
71
  createPlatformLoaders: () => createPlatformLoaders,
@@ -694,6 +695,76 @@ var BatchColumnFetcher = class {
694
695
  }
695
696
  };
696
697
 
698
+ // src/client/admin-resource-client.ts
699
+ function createAdminResourceClient(options) {
700
+ const base = options.adminBase ?? "/api/v1/admin";
701
+ const tenantsEndpoint = `${base}/tenants`;
702
+ const getJson2 = async (url) => {
703
+ const response = await options.http(url, { method: "GET" });
704
+ assertSuccess(response.status, "GET", url);
705
+ return await response.json();
706
+ };
707
+ const sendJson = async (method, url, body) => {
708
+ const response = await options.http(url, {
709
+ method,
710
+ headers: { "content-type": "application/json" },
711
+ body: body === void 0 ? void 0 : JSON.stringify(body)
712
+ });
713
+ assertSuccess(response.status, method, url);
714
+ return await response.json();
715
+ };
716
+ return {
717
+ tenantsEndpoint,
718
+ loadTenantDetail: (slug) => getJson2(`${tenantsEndpoint}/${encodeURIComponent(slug)}`),
719
+ loadUsers: (filter) => getJson2(
720
+ `${base}/users${queryString({ q: filter.q, tenant: filter.tenant })}`
721
+ ),
722
+ loadAudit: (filter) => getJson2(
723
+ `${base}/audit${queryString({
724
+ actor: filter.actor,
725
+ action: filter.action,
726
+ entity: filter.entity,
727
+ since: filter.since,
728
+ limit: filter.limit
729
+ })}`
730
+ ),
731
+ loadSubscriptions: () => getJson2(`${base}/subscriptions`),
732
+ loadPromos: (filter) => getJson2(
733
+ `${base}/promo-codes${queryString({
734
+ search: filter.search,
735
+ status: filter.status
736
+ })}`
737
+ ),
738
+ createPromo: async (payload) => {
739
+ await sendJson("POST", `${base}/promo-codes`, payload);
740
+ },
741
+ updatePromo: async (id, payload) => {
742
+ await sendJson("PATCH", `${base}/promo-codes/${encodeURIComponent(id)}`, payload);
743
+ },
744
+ deletePromo: async (id) => {
745
+ await sendJson("DELETE", `${base}/promo-codes/${encodeURIComponent(id)}`);
746
+ },
747
+ suspendTenant: (slug, reason) => sendJson("POST", `${tenantsEndpoint}/${encodeURIComponent(slug)}/suspend`, {
748
+ reason
749
+ }),
750
+ reactivateTenant: (slug) => sendJson("POST", `${tenantsEndpoint}/${encodeURIComponent(slug)}/reactivate`)
751
+ };
752
+ }
753
+ function assertSuccess(status, method, url) {
754
+ if (status < 200 || status >= 300) {
755
+ throw new Error(`${method} ${url} \u2192 HTTP ${status}`);
756
+ }
757
+ }
758
+ function queryString(params) {
759
+ const search = new URLSearchParams();
760
+ for (const [key, value2] of Object.entries(params)) {
761
+ if (value2 === void 0 || value2 === null || value2 === "") continue;
762
+ search.set(key, String(value2));
763
+ }
764
+ const value = search.toString();
765
+ return value ? `?${value}` : "";
766
+ }
767
+
697
768
  // src/client/i18n/format.ts
698
769
  function formatMessage(template, params) {
699
770
  return template.replace(/\{(\w+)\}/g, (match, name) => {
@@ -6532,6 +6603,7 @@ function defaultTenantPlanSectionI18n(locale) {
6532
6603
  buildQuotaRegistry,
6533
6604
  buildRoutes,
6534
6605
  buildSidebar,
6606
+ createAdminResourceClient,
6535
6607
  createAdminRoutes,
6536
6608
  createManifestStore,
6537
6609
  createPlatformLoaders,
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { BootLoaderOptions, ManifestLoaderOptions, BuildRouteEntry, SidebarSection, NavBuilderOptions, BatchColumnData, BatchColumnFetcherOptions, BootLoader, ManifestLoader } from './client/index.cjs';
2
- export { ADMIN_UI_VERSION, BatchColumnDriftError, BatchColumnFetcher, BatchColumnRow, BatchColumnValue, BootLoadError, CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpJsonError, ManifestLoadError, MessageParams, ParamStyle, SidebarItem, buildRoutes, buildSidebar, defaultSectionOrder, formatCurrency, formatMessage, getJson, postJson, resolveExtension, trimTrailingSlashes } from './client/index.cjs';
2
+ export { ADMIN_UI_VERSION, AdminPromoListFilter, AdminPromoListRow, AdminResourceClientOptions, BatchColumnDriftError, BatchColumnFetcher, BatchColumnRow, BatchColumnValue, BootLoadError, CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpJsonError, ManifestLoadError, MessageParams, ParamStyle, SidebarItem, buildRoutes, buildSidebar, createAdminResourceClient, defaultSectionOrder, formatCurrency, formatMessage, getJson, postJson, resolveExtension, trimTrailingSlashes } from './client/index.cjs';
3
3
  import { H as HttpClient, c as ActionRegistry, A as ActionHandler, K as KvStore, S as SaLocale } from './messages-BIYw32u1.cjs';
4
4
  export { d as ActionDefNotInManifestError, D as DEFAULT_SA_LOCALE, e as HttpResponse, M as MessageTree, f as MissingHandlerError, P as PartialMessages, R as ResolvedAction, g as SA_INTL_LOCALES, h as SA_LOCALES, i as SA_MESSAGES, a as SaMessages, b as SaMessagesOverrides, T as TranslationOf, j as defaultHttpClient, k as defaultKvStore, l as defineMessages, m as mergeMessages, r as resolveMessages } from './messages-BIYw32u1.cjs';
5
5
  import { A as ActionsMap, a as SuperAdminBrand, b as SuperAdminEndpoints, E as ExtensionsMap, c as SuperAdminLoginAdapter } from './use-super-admin-i18n-DL_qI1BY.cjs';
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { BootLoaderOptions, ManifestLoaderOptions, BuildRouteEntry, SidebarSection, NavBuilderOptions, BatchColumnData, BatchColumnFetcherOptions, BootLoader, ManifestLoader } from './client/index.js';
2
- export { ADMIN_UI_VERSION, BatchColumnDriftError, BatchColumnFetcher, BatchColumnRow, BatchColumnValue, BootLoadError, CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpJsonError, ManifestLoadError, MessageParams, ParamStyle, SidebarItem, buildRoutes, buildSidebar, defaultSectionOrder, formatCurrency, formatMessage, getJson, postJson, resolveExtension, trimTrailingSlashes } from './client/index.js';
2
+ export { ADMIN_UI_VERSION, AdminPromoListFilter, AdminPromoListRow, AdminResourceClientOptions, BatchColumnDriftError, BatchColumnFetcher, BatchColumnRow, BatchColumnValue, BootLoadError, CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpJsonError, ManifestLoadError, MessageParams, ParamStyle, SidebarItem, buildRoutes, buildSidebar, createAdminResourceClient, defaultSectionOrder, formatCurrency, formatMessage, getJson, postJson, resolveExtension, trimTrailingSlashes } from './client/index.js';
3
3
  import { H as HttpClient, c as ActionRegistry, A as ActionHandler, K as KvStore, S as SaLocale } from './messages-BIYw32u1.js';
4
4
  export { d as ActionDefNotInManifestError, D as DEFAULT_SA_LOCALE, e as HttpResponse, M as MessageTree, f as MissingHandlerError, P as PartialMessages, R as ResolvedAction, g as SA_INTL_LOCALES, h as SA_LOCALES, i as SA_MESSAGES, a as SaMessages, b as SaMessagesOverrides, T as TranslationOf, j as defaultHttpClient, k as defaultKvStore, l as defineMessages, m as mergeMessages, r as resolveMessages } from './messages-BIYw32u1.js';
5
5
  import { A as ActionsMap, a as SuperAdminBrand, b as SuperAdminEndpoints, E as ExtensionsMap, c as SuperAdminLoginAdapter } from './use-super-admin-i18n-CWNu_W3u.js';
package/dist/index.js CHANGED
@@ -13,12 +13,13 @@ import {
13
13
  MissingHandlerError,
14
14
  buildRoutes,
15
15
  buildSidebar,
16
+ createAdminResourceClient,
16
17
  defaultSectionOrder,
17
18
  getJson,
18
19
  postJson,
19
20
  resolveExtension,
20
21
  trimTrailingSlashes
21
- } from "./chunk-7N3CJTOA.js";
22
+ } from "./chunk-66BUSVC5.js";
22
23
  import {
23
24
  SUPER_ADMIN_ACTIONS_KEY,
24
25
  SUPER_ADMIN_BRAND_KEY,
@@ -2831,6 +2832,7 @@ export {
2831
2832
  buildQuotaRegistry,
2832
2833
  buildRoutes,
2833
2834
  buildSidebar,
2835
+ createAdminResourceClient,
2834
2836
  createAdminRoutes,
2835
2837
  createManifestStore,
2836
2838
  createPlatformLoaders,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@saasicat/ui-vue",
3
- "version": "0.8.0",
4
- "description": "Vue 3 components + composables for the SuperAdmin UI shell. Provides boot loader, manifest loader (ETag cache), nav builder, action registry and standard pages.",
3
+ "version": "0.10.0",
4
+ "description": "Vue 3 components, resource clients and composables for the SuperAdmin UI shell. Provides boot and manifest loaders, navigation, actions and standard pages.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.js",
@@ -53,11 +53,11 @@
53
53
  "src"
54
54
  ],
55
55
  "dependencies": {
56
- "@saasicat/types": "^0.8.0"
56
+ "@saasicat/types": "^0.10.0"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "pinia": "^2.0.0 || ^3.0.0",
60
- "quasar": "^2.18.0",
60
+ "quasar": "^2.22.0",
61
61
  "vue": "^3.5.0",
62
62
  "vue-router": "^4.5.0 || ^5.0.0"
63
63
  },
@@ -76,7 +76,7 @@
76
76
  "@playwright/test": "^1.59.1",
77
77
  "@types/node": "^25.6.0",
78
78
  "pinia": "^3.0.0",
79
- "quasar": "^2.18.0",
79
+ "quasar": "^2.22.0",
80
80
  "tsup": "^8.0.0",
81
81
  "typescript": "^6.0.0",
82
82
  "vue": "^3.5.0",
@@ -0,0 +1,112 @@
1
+ import type {
2
+ AdminAuditListFilter,
3
+ AdminSubscriptionListRow,
4
+ AdminTenantDetail,
5
+ AdminUserListFilter,
6
+ AdminUserListRow,
7
+ AuditEntry,
8
+ PromoCodeRecord,
9
+ } from '@saasicat/types';
10
+ import type { HttpClient } from './types.js';
11
+
12
+ export interface AdminResourceClientOptions {
13
+ http: HttpClient;
14
+ /** Default `/api/v1/admin`. */
15
+ adminBase?: string;
16
+ }
17
+
18
+ /** Filters accepted by the standard PromoCodesPage, including its "all" state. */
19
+ export interface AdminPromoListFilter {
20
+ search?: string;
21
+ status?: string | null;
22
+ }
23
+
24
+ /** Promo row shape used by the extensible standard Admin table. */
25
+ export interface AdminPromoListRow extends PromoCodeRecord {
26
+ [extra: string]: unknown;
27
+ }
28
+
29
+ /**
30
+ * Ready-to-use client for the standard SaaSiCat AdminResources and promo
31
+ * controllers. App wrappers pass these functions straight to the standard
32
+ * pages; no repeated fetch/error/query-string plumbing is needed.
33
+ */
34
+ export function createAdminResourceClient(options: AdminResourceClientOptions) {
35
+ const base = options.adminBase ?? '/api/v1/admin';
36
+ const tenantsEndpoint = `${base}/tenants`;
37
+
38
+ const getJson = async <T>(url: string): Promise<T> => {
39
+ const response = await options.http(url, { method: 'GET' });
40
+ assertSuccess(response.status, 'GET', url);
41
+ return (await response.json()) as T;
42
+ };
43
+
44
+ const sendJson = async <T>(method: string, url: string, body?: unknown): Promise<T> => {
45
+ const response = await options.http(url, {
46
+ method,
47
+ headers: { 'content-type': 'application/json' },
48
+ body: body === undefined ? undefined : JSON.stringify(body),
49
+ });
50
+ assertSuccess(response.status, method, url);
51
+ return (await response.json()) as T;
52
+ };
53
+
54
+ return {
55
+ tenantsEndpoint,
56
+ loadTenantDetail: (slug: string) =>
57
+ getJson<AdminTenantDetail>(`${tenantsEndpoint}/${encodeURIComponent(slug)}`),
58
+ loadUsers: (filter: AdminUserListFilter) =>
59
+ getJson<AdminUserListRow[]>(
60
+ `${base}/users${queryString({ q: filter.q, tenant: filter.tenant })}`,
61
+ ),
62
+ loadAudit: (filter: AdminAuditListFilter) =>
63
+ getJson<AuditEntry[]>(
64
+ `${base}/audit${queryString({
65
+ actor: filter.actor,
66
+ action: filter.action,
67
+ entity: filter.entity,
68
+ since: filter.since,
69
+ limit: filter.limit,
70
+ })}`,
71
+ ),
72
+ loadSubscriptions: () => getJson<AdminSubscriptionListRow[]>(`${base}/subscriptions`),
73
+ loadPromos: (filter: AdminPromoListFilter) =>
74
+ getJson<AdminPromoListRow[]>(
75
+ `${base}/promo-codes${queryString({
76
+ search: filter.search,
77
+ status: filter.status,
78
+ })}`,
79
+ ),
80
+ createPromo: async (payload: unknown): Promise<void> => {
81
+ await sendJson('POST', `${base}/promo-codes`, payload);
82
+ },
83
+ updatePromo: async (id: string, payload: unknown): Promise<void> => {
84
+ await sendJson('PATCH', `${base}/promo-codes/${encodeURIComponent(id)}`, payload);
85
+ },
86
+ deletePromo: async (id: string): Promise<void> => {
87
+ await sendJson('DELETE', `${base}/promo-codes/${encodeURIComponent(id)}`);
88
+ },
89
+ suspendTenant: (slug: string, reason: string): Promise<unknown> =>
90
+ sendJson('POST', `${tenantsEndpoint}/${encodeURIComponent(slug)}/suspend`, {
91
+ reason,
92
+ }),
93
+ reactivateTenant: (slug: string): Promise<unknown> =>
94
+ sendJson('POST', `${tenantsEndpoint}/${encodeURIComponent(slug)}/reactivate`),
95
+ };
96
+ }
97
+
98
+ function assertSuccess(status: number, method: string, url: string): void {
99
+ if (status < 200 || status >= 300) {
100
+ throw new Error(`${method} ${url} → HTTP ${status}`);
101
+ }
102
+ }
103
+
104
+ function queryString(params: Record<string, string | number | null | undefined>): string {
105
+ const search = new URLSearchParams();
106
+ for (const [key, value] of Object.entries(params)) {
107
+ if (value === undefined || value === null || value === '') continue;
108
+ search.set(key, String(value));
109
+ }
110
+ const value = search.toString();
111
+ return value ? `?${value}` : '';
112
+ }
@@ -22,4 +22,5 @@ export * from './manifest-loader.js';
22
22
  export * from './nav-builder.js';
23
23
  export * from './action-registry.js';
24
24
  export * from './batch-column-fetcher.js';
25
+ export * from './admin-resource-client.js';
25
26
  export * from './i18n/index.js';