@saasicat/ui-vue 0.24.2 → 0.26.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.
- package/README.md +32 -8
- package/dist/{catalog-DJcfm5N2.d.cts → catalog-Dch1Ryw0.d.cts} +353 -69
- package/dist/{catalog-DJcfm5N2.d.ts → catalog-Dch1Ryw0.d.ts} +353 -69
- package/dist/{chunk-F7NRM6KI.js → chunk-BPF2BMCQ.js} +748 -24
- package/dist/{chunk-D74FFCCP.js → chunk-NEXTZZRQ.js} +95 -177
- package/dist/{chunk-TQQMKWN6.js → chunk-O3J3ITF2.js} +119 -7
- package/dist/client/index.cjs +758 -83
- package/dist/client/index.d.cts +414 -9
- package/dist/client/index.d.ts +414 -9
- package/dist/client/index.js +84 -12
- package/dist/index.cjs +1325 -294
- package/dist/index.d.cts +205 -15
- package/dist/index.d.ts +205 -15
- package/dist/index.js +566 -240
- package/dist/quasar/index.cjs +574 -62
- package/dist/quasar/index.d.cts +61 -6
- package/dist/quasar/index.d.ts +61 -6
- package/dist/quasar/index.js +83 -19
- package/dist/{use-sa-theme-OUBlaqgl.d.ts → resource-registry-D7Xjs-5f.d.cts} +157 -7
- package/dist/{use-sa-theme-B5t7oXph.d.cts → resource-registry-TaR7rtq0.d.ts} +157 -7
- package/package.json +4 -3
- package/src/client/admin-error.ts +552 -0
- package/src/client/admin-resource-client.ts +9 -12
- package/src/client/batch-column-fetcher.ts +2 -2
- package/src/client/boot-loader.ts +12 -1
- package/src/client/http/axios-http-client.ts +383 -0
- package/src/client/http/fetch-http-client.ts +89 -0
- package/src/client/http/index.ts +6 -0
- package/src/client/http-json.ts +82 -16
- package/src/client/i18n/messages/discovery.ts +0 -6
- package/src/client/i18n/messages/errors.ts +44 -0
- package/src/client/i18n/messages/marketing.ts +0 -6
- package/src/client/i18n/messages/promos.ts +0 -2
- package/src/client/i18n/messages/shell.ts +12 -0
- package/src/client/i18n/messages.ts +3 -0
- package/src/client/index.ts +6 -0
- package/src/client/manifest-loader.ts +65 -15
- package/src/client/resources/audit.resource.ts +25 -0
- package/src/client/resources/define-resource.ts +166 -0
- package/src/client/resources/index.ts +42 -0
- package/src/client/resources/list-resource.ts +176 -0
- package/src/client/resources/plans.resource.ts +169 -0
- package/src/client/resources/resource-request.ts +117 -0
- package/src/client/resources/tenants.resource.ts +27 -0
- package/src/client/types.ts +10 -3
- package/src/components/BundleVersionPublishDialog.vue +1 -1
- package/src/components/MarketingPromotionsTab.vue +263 -241
- package/src/components/ThemeSwitcher.vue +85 -0
- package/src/components/admin-page/AdminAccordion.vue +125 -0
- package/src/components/bundle-editor/BundleCreatePanel.vue +1 -1
- package/src/components/dialogs/PromoCodeDialogFields.vue +20 -20
- package/src/components/plan/PlanCycleToggle.vue +1 -1
- package/src/components/plan-detail/PlanVersionsPanel.vue +5 -2
- package/src/index.ts +5 -0
- package/src/pages-standard/AdminLayout.vue +57 -0
- package/src/pages-standard/AdminManifestErrorPage.vue +4 -3
- package/src/pages-standard/BundlesPage.vue +5 -35
- package/src/pages-standard/DiscoveryPage.vue +8 -1
- package/src/pages-standard/MarketingCatalogPage.vue +14 -3
- package/src/pages-standard/SuperAdminLoginPage.vue +23 -2
- package/src/pages-standard/SuperAdminSetupWizard.vue +37 -3
- package/src/pages-standard/bundles-page/BundleAccordionList.vue +30 -32
- package/src/pages-standard/discovery-page/DiscoveryFeatureCard.vue +80 -88
- package/src/pages-standard/discovery-page/DiscoveryQuotaCard.vue +73 -79
- package/src/pages-standard/marketing-catalog/MarketingCatalogAdmin.vue +44 -6
- package/src/pages-standard/marketing-catalog/MarketingCatalogPreview.vue +8 -2
- package/src/pages-tenant/PackageSnapshotPanel.vue +31 -2
- package/src/quasar/confirm.ts +83 -0
- package/src/quasar/create-super-admin-app.ts +84 -10
- package/src/quasar/dark-bridge.ts +47 -10
- package/src/quasar/index.ts +1 -0
- package/src/ui/theme/components/accordion.css +118 -0
- package/src/ui/theme/index.css +1 -0
- package/src/vue/create-admin-routes.ts +9 -1
- package/src/vue/platform-loaders.ts +12 -2
- package/src/vue/resource-registry.ts +211 -0
- package/src/vue/super-admin-context.ts +20 -5
- package/src/vue/ui-confirm.ts +76 -0
- package/src/vue/use-api-list.ts +50 -45
- package/src/vue/use-async-action.ts +170 -0
- package/src/vue/use-async-data.ts +83 -0
- package/src/vue/use-bundles.ts +34 -7
- package/src/vue/use-catalog-entries.ts +37 -12
- package/src/vue/use-discovery.ts +27 -6
- package/src/vue/use-marketing-projections.ts +29 -7
- package/src/vue/use-plans.ts +36 -8
- package/src/vue/use-promotions.ts +27 -7
- package/src/vue/use-resource-list.ts +272 -0
- package/src/vue/use-sa-theme.ts +34 -5
- package/src/vue/use-tenant-subscription-bundles.ts +22 -3
package/dist/client/index.d.ts
CHANGED
|
@@ -1,19 +1,406 @@
|
|
|
1
|
-
import { H as HttpClient, K as KvStore, S as SaLocale,
|
|
2
|
-
export {
|
|
1
|
+
import { H as HttpClient, a as SaMessages, K as KvStore, S as SaLocale, a9 as SaNavMessages } from '../catalog-Dch1Ryw0.js';
|
|
2
|
+
export { i as ActionDefNotInManifestError, A as ActionHandler, h as ActionRegistry, j as AuditListFilter, B as Bound, D as DEFAULT_SA_LOCALE, k as DefineResourceOptions, l as HttpResponse, L as LIST_FIRST_PAGE, m as LIST_PAGE_SIZE_DEFAULT, n as LIST_PAGE_SIZE_MAX, o as LIST_PAGINATION_PARAMS, q as ListFilterOf, r as ListOp, s as ListQuery, M as MessageTree, t as MissingHandlerError, u as PartialMessages, P as PlatformResources, v as PublishPlanVersionOptions, w as ResolvedAction, f as ResourceContext, R as ResourceDef, g as ResourceListPage, x as ResourceOp, e as ResourceOps, y as SA_INTL_LOCALES, z as SA_LOCALES, C as SA_LOCALE_LABELS, E as SA_MESSAGES, F as SaBuiltinLocale, G as SaCatalog, I as SaCatalogOptions, c as SaLocaleDefinition, b as SaLocaleOption, d as SaMessagesOverrides, T as TenantsListFilter, J as TranslationOf, N as auditResource, O as bindResource, Q as clampListPage, U as clampListPageSize, V as createSaCatalog, W as defaultHttpClient, X as defaultKvStore, Y as defineListOp, Z as defineMessages, _ as defineResource, $ as filterQueryString, a0 as isSaBuiltinLocale, a1 as isSentInQuery, a2 as listUrl, a3 as mergeMessages, a4 as planVersionsResource, a5 as plansResource, p as platformResources, a6 as readListPage, a7 as resolveMessages, a8 as tenantsResource } from '../catalog-Dch1Ryw0.js';
|
|
3
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
|
|
|
7
|
+
interface FetchHttpClientOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Prefix for relative URLs, e.g. `'https://api.example.com'`. Absolute
|
|
10
|
+
* URLs are passed through untouched.
|
|
11
|
+
*
|
|
12
|
+
* Note that an app configures its API prefix twice if it also passes a
|
|
13
|
+
* fully-qualified `apiBase` to the shell — the two would concatenate. Pick
|
|
14
|
+
* one; a doubled prefix 404s on the first request rather than degrading
|
|
15
|
+
* quietly, which is the reason this does not try to detect it.
|
|
16
|
+
*/
|
|
17
|
+
baseUrl?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Headers to add to every request, read per request so a token that
|
|
20
|
+
* changes between calls is picked up without rebuilding the client. May
|
|
21
|
+
* return a promise for a token that has to be refreshed first.
|
|
22
|
+
*
|
|
23
|
+
* Headers passed by the caller win, so a request that sets its own
|
|
24
|
+
* `Content-Type` keeps it.
|
|
25
|
+
*/
|
|
26
|
+
headers?: () => Record<string, string> | Promise<Record<string, string>>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Builds an `HttpClient` over `fetch`.
|
|
30
|
+
*
|
|
31
|
+
* With no options it is a bare passthrough plus an `Accept: application/json`
|
|
32
|
+
* header — the platform speaks JSON everywhere, and saying so is what stops a
|
|
33
|
+
* content-negotiating gateway from answering with HTML.
|
|
34
|
+
*/
|
|
35
|
+
declare function createFetchHttpClient(options?: FetchHttpClientOptions): HttpClient;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The part of the merged request config axios echoes back on every response —
|
|
39
|
+
* on the one it resolves with and on the one it attaches to a rejection. These
|
|
40
|
+
* three fields say whether `data` is a decoded value or the body as it arrived,
|
|
41
|
+
* for as long as axios's own response transform is the one that produced it;
|
|
42
|
+
* see `bodyIsRaw`.
|
|
43
|
+
*
|
|
44
|
+
* They are `unknown` rather than their axios types so that a real
|
|
45
|
+
* `AxiosResponse` stays structurally assignable without this package taking a
|
|
46
|
+
* dependency on axios to name them.
|
|
47
|
+
*/
|
|
48
|
+
interface AxiosLikeResponseConfig {
|
|
49
|
+
transformResponse?: unknown;
|
|
50
|
+
responseType?: unknown;
|
|
51
|
+
transitional?: unknown;
|
|
52
|
+
}
|
|
53
|
+
interface AxiosLikeResponse {
|
|
54
|
+
status: number;
|
|
55
|
+
data: unknown;
|
|
56
|
+
headers: unknown;
|
|
57
|
+
config?: AxiosLikeResponseConfig;
|
|
58
|
+
}
|
|
59
|
+
interface AxiosLikeConfig {
|
|
60
|
+
url: string;
|
|
61
|
+
method?: string;
|
|
62
|
+
headers?: Record<string, string>;
|
|
63
|
+
data?: unknown;
|
|
64
|
+
}
|
|
65
|
+
/** The part of an axios instance this adapter uses. */
|
|
66
|
+
interface AxiosLike {
|
|
67
|
+
request(config: AxiosLikeConfig): Promise<AxiosLikeResponse>;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* What an instance leaves in `response.data`, for the one case the response
|
|
71
|
+
* cannot describe: an instance that replaced `transformResponse` with a
|
|
72
|
+
* non-empty pipeline of its own.
|
|
73
|
+
*
|
|
74
|
+
* - `'auto'` — read it off the config axios echoes on the response. Correct for
|
|
75
|
+
* an instance that still runs axios's own transform, and for every way of
|
|
76
|
+
* switching that transform's parsing off: `responseType: 'text'`,
|
|
77
|
+
* `transitional: { forcedJSONParsing: false }`, and a `transformResponse`
|
|
78
|
+
* that runs nothing (`[]` or `null`).
|
|
79
|
+
* - `'raw'` — `data` is the body as it arrived, and `json()` parses it.
|
|
80
|
+
* - `'decoded'` — `data` is a value the pipeline already produced, and `json()`
|
|
81
|
+
* hands it over untouched.
|
|
82
|
+
*/
|
|
83
|
+
type AxiosResponseBody = 'auto' | 'raw' | 'decoded';
|
|
84
|
+
interface AxiosHttpClientOptions {
|
|
85
|
+
/**
|
|
86
|
+
* Prefix(es) to remove from the start of a URL before handing it to the
|
|
87
|
+
* instance, for the usual case where the instance already carries them as
|
|
88
|
+
* its `baseURL`. Tried in order, first match wins — so list the longest
|
|
89
|
+
* first (`['/api/v1', '/api']`), or `/api/v1/admin/x` loses only `/api`.
|
|
90
|
+
*/
|
|
91
|
+
stripPrefix?: string | readonly string[];
|
|
92
|
+
/**
|
|
93
|
+
* How this instance hands the body over. Defaults to `'auto'`, which needs
|
|
94
|
+
* no configuration and is right for every instance that leaves axios's own
|
|
95
|
+
* `transformResponse` in place.
|
|
96
|
+
*
|
|
97
|
+
* Set it only if you replaced `transformResponse` with a non-empty pipeline
|
|
98
|
+
* of your own: `'raw'` if that pipeline hands the body over as it arrived
|
|
99
|
+
* (`[(data) => data]`), `'decoded'` if it parses. The response cannot be
|
|
100
|
+
* read for the answer — both echo one opaque function — so `'auto'` would
|
|
101
|
+
* take your pipeline for axios's; see `bodyIsRaw`.
|
|
102
|
+
*
|
|
103
|
+
* The declaration is read before anything else, an empty `data` included:
|
|
104
|
+
* under `'decoded'` an empty `data` is the empty string the pipeline
|
|
105
|
+
* produced, and `json()` hands it over; under `'raw'` it is an empty body,
|
|
106
|
+
* and `json()` throws the way `Response.json()` does.
|
|
107
|
+
*/
|
|
108
|
+
responseBody?: AxiosResponseBody;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Adapts an axios instance to `HttpClient`.
|
|
112
|
+
*
|
|
113
|
+
* Two decisions are worth knowing about, because five of the six shims this
|
|
114
|
+
* replaces made them differently:
|
|
115
|
+
*
|
|
116
|
+
* **No status throws — but the instance still decides.** A 402, a 404 and a
|
|
117
|
+
* 500 all arrive as responses, because the platform reads statuses itself (a
|
|
118
|
+
* 304 is a cache hit, a 402 carries a limit payload) and can only do that for
|
|
119
|
+
* statuses it is handed. That is achieved by adapting the rejection rather
|
|
120
|
+
* than by overriding `validateStatus`: an override would make axios resolve
|
|
121
|
+
* everything, and a config that never rejects makes the **rejection half of
|
|
122
|
+
* the instance's own response interceptors unreachable** — the conventional
|
|
123
|
+
* place a consumer puts token refresh and retry. Their session would expire
|
|
124
|
+
* silently instead of refreshing.
|
|
125
|
+
*
|
|
126
|
+
* **`json()` decodes only what axios left undecoded.** Which of the two it is
|
|
127
|
+
* cannot be guessed from the value. The response says it for every instance
|
|
128
|
+
* that still runs axios's own `transformResponse`; an instance that replaced it
|
|
129
|
+
* says it with the `responseBody` option, because at that point the response no
|
|
130
|
+
* longer can. See `bodyIsRaw`.
|
|
131
|
+
*
|
|
132
|
+
* Nothing here overrides the instance's own configuration — not
|
|
133
|
+
* `validateStatus`, and not `transformResponse` either. Forcing the transform
|
|
134
|
+
* off would make the answer knowable, at the price of handing the consumer's
|
|
135
|
+
* own response interceptors a string where they had an object.
|
|
136
|
+
*/
|
|
137
|
+
declare function createAxiosHttpClient(instance: AxiosLike, options?: AxiosHttpClientOptions): HttpClient;
|
|
138
|
+
|
|
139
|
+
interface ResourceRequestInit {
|
|
140
|
+
/** Default `GET`. */
|
|
141
|
+
method?: string;
|
|
142
|
+
/** Serialised here — the `HttpClient` contract only carries strings. */
|
|
143
|
+
body?: unknown;
|
|
144
|
+
/** Merged over the defaults, so a caller's header wins. */
|
|
145
|
+
headers?: Record<string, string>;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Sends a request and returns the parsed body, or `null` when there was none.
|
|
149
|
+
*
|
|
150
|
+
* `null` covers both a `204` and a 2xx whose body would not parse. The two are
|
|
151
|
+
* deliberately not distinguished: every caller treats them the same way — a
|
|
152
|
+
* list turns `null` into `[]`, a mutation turns it into a failure — and no
|
|
153
|
+
* endpoint in this family answers a mutation with an empty 200 on purpose.
|
|
154
|
+
*
|
|
155
|
+
* A non-2xx throws an `AdminError` carrying the parsed body, so a caller can
|
|
156
|
+
* still branch on `status` and `body.code` the way the pages do today.
|
|
157
|
+
*
|
|
158
|
+
* A client that resolved without an HTTP status throws before any of that: no
|
|
159
|
+
* status means the request never reached the server, which is a transport
|
|
160
|
+
* failure and not an answer this function may read.
|
|
161
|
+
*/
|
|
162
|
+
declare function requestJson<T>(http: HttpClient, url: string, init?: ResourceRequestInit): Promise<T | null>;
|
|
163
|
+
/**
|
|
164
|
+
* Reads the body of a request that must answer with one.
|
|
165
|
+
*
|
|
166
|
+
* The empty case is a failure rather than a `null` the caller has to re-check:
|
|
167
|
+
* a create that returns nothing has not told us what it created. Raised with
|
|
168
|
+
* `status: 0`, because no HTTP status went wrong — the response was a 2xx.
|
|
169
|
+
*/
|
|
170
|
+
declare function requestJsonBody<T>(http: HttpClient, url: string, what: string, init?: ResourceRequestInit): Promise<T>;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Marks an error as one this package raised. Called by the package's own error
|
|
174
|
+
* classes in their constructors; nothing else should call it.
|
|
175
|
+
*/
|
|
176
|
+
declare function markPlatformError(error: Error): void;
|
|
177
|
+
/** Whether an error came from this package, across bundle copies. */
|
|
178
|
+
declare function isPlatformError(value: unknown): boolean;
|
|
179
|
+
/**
|
|
180
|
+
* Marks an error as the empty-body sentinel: the call reached the server, the
|
|
181
|
+
* server answered, and the body the caller needed was not in it. Returns the
|
|
182
|
+
* error so a throw site stays one expression.
|
|
183
|
+
*
|
|
184
|
+
* Called at those throw sites only — never in a constructor, because the class
|
|
185
|
+
* is also raised for calls that failed outright.
|
|
186
|
+
*/
|
|
187
|
+
declare function markEmptyResponse<E extends Error>(error: E): E;
|
|
188
|
+
/** Whether an error is that sentinel, across bundle copies. */
|
|
189
|
+
declare function isEmptyResponse(value: unknown): boolean;
|
|
7
190
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
191
|
+
* Marks an error as one the request did not survive: no connection, DNS
|
|
192
|
+
* failure, CORS rejection, abort, or a client that reported the same by
|
|
193
|
+
* resolving without an HTTP status. Returns the error so a throw site stays one
|
|
194
|
+
* expression.
|
|
11
195
|
*/
|
|
12
|
-
declare
|
|
196
|
+
declare function markTransportFailure<E>(error: E): E;
|
|
197
|
+
/** Whether an error is a declared transport failure, across bundle copies. */
|
|
198
|
+
declare function isTransportFailure(value: unknown): boolean;
|
|
199
|
+
interface AdminErrorInit {
|
|
200
|
+
/** HTTP status. `0` means the request never produced one. */
|
|
201
|
+
status?: number;
|
|
202
|
+
/** Machine-readable code from the response body (`{ code }`). */
|
|
203
|
+
code?: string;
|
|
204
|
+
/** Parsed response body, when there was one. */
|
|
205
|
+
body?: unknown;
|
|
206
|
+
/** Requested URL, when known. */
|
|
207
|
+
url?: string;
|
|
208
|
+
/** Request method, when known. */
|
|
209
|
+
method?: string;
|
|
210
|
+
/**
|
|
211
|
+
* Text the failing side supplied. Never invent one — its absence is the
|
|
212
|
+
* signal that only a translated fallback can be shown.
|
|
213
|
+
*/
|
|
214
|
+
detail?: string;
|
|
215
|
+
/**
|
|
216
|
+
* The request completed and the answer was unusable — a 2xx that carried
|
|
217
|
+
* no body where one was required.
|
|
218
|
+
*
|
|
219
|
+
* Its own state because the model could not otherwise tell it from a
|
|
220
|
+
* transport failure: both have no HTTP status to report, and both were
|
|
221
|
+
* therefore `status: 0`. They need opposite words. A request that never
|
|
222
|
+
* left says "check your connection"; one the server accepted and answered
|
|
223
|
+
* with nothing says "check whether the change was applied", because it may
|
|
224
|
+
* well have been.
|
|
225
|
+
*/
|
|
226
|
+
emptyResponse?: boolean;
|
|
227
|
+
/**
|
|
228
|
+
* The request never reached the server.
|
|
229
|
+
*
|
|
230
|
+
* Its own state for the same reason as `emptyResponse`: neither has an HTTP
|
|
231
|
+
* status to reason from, so a status of `0` cannot tell them apart — and
|
|
232
|
+
* neither can it tell either of them from an error that simply carries no
|
|
233
|
+
* status, such as a bug in page code. Only the seam that made the request
|
|
234
|
+
* knows, and it says so with `markTransportFailure`.
|
|
235
|
+
*/
|
|
236
|
+
transportFailure?: boolean;
|
|
237
|
+
/** Diagnostic message. Derived from the fields above when omitted. */
|
|
238
|
+
message?: string;
|
|
239
|
+
/** The error this one was built from. */
|
|
240
|
+
cause?: unknown;
|
|
241
|
+
}
|
|
242
|
+
/** A failed admin API call, in the one shape the package works with. */
|
|
243
|
+
declare class AdminError extends Error {
|
|
244
|
+
/** HTTP status. `0` means the request never produced one. */
|
|
13
245
|
readonly status: number;
|
|
14
|
-
|
|
15
|
-
|
|
246
|
+
/** Machine-readable code from the response body, when it carried one. */
|
|
247
|
+
readonly code?: string;
|
|
248
|
+
/** Parsed response body, when there was one. */
|
|
249
|
+
readonly body?: unknown;
|
|
250
|
+
/** Requested URL, when known. */
|
|
251
|
+
readonly url?: string;
|
|
252
|
+
/** Request method, when known. */
|
|
253
|
+
readonly method?: string;
|
|
254
|
+
/**
|
|
255
|
+
* Text the failing side supplied — the only candidate for user-facing
|
|
256
|
+
* output. `undefined` when nothing was supplied.
|
|
257
|
+
*/
|
|
258
|
+
readonly detail?: string;
|
|
259
|
+
/** The request completed but the answer was unusable. See `AdminErrorInit`. */
|
|
260
|
+
readonly emptyResponse: boolean;
|
|
261
|
+
/** The request never reached the server. See `AdminErrorInit`. */
|
|
262
|
+
readonly transportFailure: boolean;
|
|
263
|
+
constructor(init?: AdminErrorInit);
|
|
16
264
|
}
|
|
265
|
+
/** Whether `err` is an `AdminError`, including one from another bundle copy. */
|
|
266
|
+
declare function isAdminError(err: unknown): err is AdminError;
|
|
267
|
+
/**
|
|
268
|
+
* Whether an error is axios saying, in its own words, that the request was made
|
|
269
|
+
* and no response ever arrived.
|
|
270
|
+
*
|
|
271
|
+
* This is the one transport failure read rather than branded, because a library
|
|
272
|
+
* cannot be asked to mark itself. What it reads is axios's own three-way split,
|
|
273
|
+
* documented under "Handling errors" in its README and visible in the
|
|
274
|
+
* `AxiosError` constructor: `response` is set only when the server answered,
|
|
275
|
+
* `request` only once one was actually made, and an error with neither happened
|
|
276
|
+
* while the request was still being set up.
|
|
277
|
+
*
|
|
278
|
+
* Measured against axios 1.18.1 driven at a real `node:http` server, and the
|
|
279
|
+
* groups came out disjoint:
|
|
280
|
+
*
|
|
281
|
+
* | rejection | `isAxiosError` | `request` | `response` |
|
|
282
|
+
* | ----------------------------------------------- | -------------- | --------- | ---------- |
|
|
283
|
+
* | connection refused / reset, DNS, timeout, abort | `true` | yes | no |
|
|
284
|
+
* | the same, rethrown by a rejection interceptor | `true` | yes | no |
|
|
285
|
+
* | a 401 or 500 the server really sent | `true` | yes | yes |
|
|
286
|
+
* | interceptor rejects with `new Error(…)` | absent | no | no |
|
|
287
|
+
* | …the same, but copying `error.config` across | absent | no | no |
|
|
288
|
+
* | …the same, copying `config` and `request` | absent | yes | no |
|
|
289
|
+
* | unsupported protocol, signal aborted before call | `true` | no | no |
|
|
290
|
+
* | request interceptor throws, malformed URL | absent | no | no |
|
|
291
|
+
*
|
|
292
|
+
* Three readings follow from that table, and only the first is free of choice:
|
|
293
|
+
*
|
|
294
|
+
* - `response` present means the server answered, whatever else is set.
|
|
295
|
+
* - `request` present without it is axios's "made, nothing came back". The
|
|
296
|
+
* browser and `fetch` adapters attach it too — an `XMLHttpRequest` and a
|
|
297
|
+
* `Request` respectively — so the reading is not Node-only.
|
|
298
|
+
* - Requiring `isAxiosError` on top of that is the decision. It removes the
|
|
299
|
+
* ordinary interceptor that copies `config` and `request` onto a hand-built
|
|
300
|
+
* `new Error`, which is shape-wise axios's no-response form after the server
|
|
301
|
+
* had answered.
|
|
302
|
+
*
|
|
303
|
+
* The previous reading was `config` without `response`, which is not axios's
|
|
304
|
+
* statement about anything: `config` is echoed on every axios error including
|
|
305
|
+
* the ones carrying a 401, and it is the field an interceptor is most likely to
|
|
306
|
+
* carry over when it replaces the rejection. It matched three rows above that
|
|
307
|
+
* mean the opposite of a transport failure.
|
|
308
|
+
*
|
|
309
|
+
* ## What this cannot decide, and which way it errs
|
|
310
|
+
*
|
|
311
|
+
* This is read *after* the consumer's interceptors have run — after the one
|
|
312
|
+
* place that can set or delete any field on the rejection. Both readings are
|
|
313
|
+
* therefore forgeable, in both directions, and each was reproduced:
|
|
314
|
+
*
|
|
315
|
+
* - An interceptor that **drops** `request` — `AxiosError.from(err, code,
|
|
316
|
+
* config)` without its fourth argument, `err.toJSON()`, or a `delete
|
|
317
|
+
* err.request` before logging — leaves a genuine `ECONNREFUSED` unbranded.
|
|
318
|
+
* The operator then reads `connect ECONNREFUSED 127.0.0.1:44947` instead of
|
|
319
|
+
* the localized sentence.
|
|
320
|
+
* - An interceptor that **builds** one — `AxiosError.from(msg, code,
|
|
321
|
+
* error.config, error.request)` after an answered 401 — is branded. Nothing
|
|
322
|
+
* distinguishes it: `AxiosError.from` is public API, so `isAxiosError` is
|
|
323
|
+
* available to user code as well.
|
|
324
|
+
*
|
|
325
|
+
* Neither is closable by a better predicate; the fields simply do not carry the
|
|
326
|
+
* fact by then. So the reading errs deliberately toward *not* branding, because
|
|
327
|
+
* the two mistakes do not cost the same: an unbranded transport failure shows a
|
|
328
|
+
* true sentence in the wrong register, while a branded application failure tells
|
|
329
|
+
* the operator to check a connection that is fine. Saying less beats saying
|
|
330
|
+
* something false.
|
|
331
|
+
*
|
|
332
|
+
* An interceptor that rewrites rejections should say what it means with
|
|
333
|
+
* `markTransportFailure`, which is exported for exactly this. It is checked
|
|
334
|
+
* first and settles the case.
|
|
335
|
+
*/
|
|
336
|
+
declare function isAxiosNoResponseError(value: unknown): boolean;
|
|
337
|
+
/**
|
|
338
|
+
* Reads the human-readable message out of a response body.
|
|
339
|
+
*
|
|
340
|
+
* Covers the two shapes the platform and its host produce: a coded platform
|
|
341
|
+
* error (`{ code, message }`) carries a string, while a NestJS
|
|
342
|
+
* `ValidationPipe` rejection carries `message: string[]` — one entry per
|
|
343
|
+
* failed constraint. Joining them is what keeps a validation error readable
|
|
344
|
+
* instead of rendering as `[object Object]`.
|
|
345
|
+
*
|
|
346
|
+
* Exported because every place that builds an `AdminError` from a response
|
|
347
|
+
* needs the same answer. It had two implementations for one release and they
|
|
348
|
+
* disagreed: the one in `http-json.ts` accepted only a string, so a validation
|
|
349
|
+
* rejection arriving through `getJson`/`postJson` lost its constraints
|
|
350
|
+
* entirely and the operator was shown the generic fallback.
|
|
351
|
+
*/
|
|
352
|
+
declare function readErrorDetail(body: unknown): string | undefined;
|
|
353
|
+
/** Reads the machine-readable code out of a response body, if it carries one. */
|
|
354
|
+
declare function readErrorCode(body: unknown): string | undefined;
|
|
355
|
+
/**
|
|
356
|
+
* Turns anything that was caught into an `AdminError`.
|
|
357
|
+
*
|
|
358
|
+
* Recognises, in order: an `AdminError` (from any bundle copy), an axios-style
|
|
359
|
+
* rejection, an error carrying a numeric `status` — which is every one of the
|
|
360
|
+
* package's own `*ApiError` classes — and finally any `Error`, string or
|
|
361
|
+
* unknown value.
|
|
362
|
+
*/
|
|
363
|
+
declare function toAdminError(err: unknown): AdminError;
|
|
364
|
+
/**
|
|
365
|
+
* Turns anything that was caught into text for a user.
|
|
366
|
+
*
|
|
367
|
+
* What the failing side said outranks anything this package could guess, so a
|
|
368
|
+
* `detail` wins whenever there is one. After that come the two facts a seam
|
|
369
|
+
* declared about a request with no HTTP status — they need opposite sentences
|
|
370
|
+
* and no number can tell them apart — and only then the status.
|
|
371
|
+
*
|
|
372
|
+
* The last line is the honest one. An error with no status, no text and no
|
|
373
|
+
* declaration is an error nothing knows anything about; "check your connection"
|
|
374
|
+
* used to be the answer, and it sent an operator after their router for a null
|
|
375
|
+
* dereference in a page. Whoever knows better says so with
|
|
376
|
+
* `markTransportFailure` or `markEmptyResponse`.
|
|
377
|
+
*
|
|
378
|
+
* Pages do not call this — `useAsyncAction` and the error banner do.
|
|
379
|
+
*/
|
|
380
|
+
declare function adminErrorMessage(err: unknown, msgs: SaMessages['errors']): string;
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Fails, at the seam that can still tell, when the client resolved without an
|
|
384
|
+
* HTTP status: the request never reached the server.
|
|
385
|
+
*
|
|
386
|
+
* Every caller below then knows that an absent body means the server answered
|
|
387
|
+
* without one, which is the precondition the empty-response sentinel needs and
|
|
388
|
+
* did not have — `if (!data)` was true for both facts, and the mutation
|
|
389
|
+
* sentinel told the operator of a request that never left the machine to go
|
|
390
|
+
* check whether their change had been applied.
|
|
391
|
+
*
|
|
392
|
+
* `raise` builds the error class of the calling seam from the diagnostic, so
|
|
393
|
+
* the caught error keeps saying which API it came from.
|
|
394
|
+
*/
|
|
395
|
+
declare function requireServerAnswer(status: number, method: string, url: string, raise: (diagnostic: string) => Error): void;
|
|
396
|
+
/**
|
|
397
|
+
* @deprecated Renamed to {@link AdminError}, which is the same class: an
|
|
398
|
+
* `instanceof HttpJsonError` check keeps working and now also matches errors
|
|
399
|
+
* raised elsewhere in the package. Construction changed — `AdminError` takes
|
|
400
|
+
* one options object instead of `(status, code)`.
|
|
401
|
+
*/
|
|
402
|
+
declare const HttpJsonError: typeof AdminError;
|
|
403
|
+
type HttpJsonError = AdminError;
|
|
17
404
|
/**
|
|
18
405
|
* Removes trailing slashes so an API prefix can be concatenated with paths
|
|
19
406
|
* that start with `/`. Deliberately index-based instead of
|
|
@@ -65,6 +452,11 @@ interface ManifestLoaderOptions {
|
|
|
65
452
|
*/
|
|
66
453
|
getAuthToken?: () => string | null;
|
|
67
454
|
}
|
|
455
|
+
/**
|
|
456
|
+
* The manifest could not be loaded. Its `message` is a diagnostic for the log,
|
|
457
|
+
* never text for a screen — `markPlatformError` is what tells `toAdminError`
|
|
458
|
+
* so, and it is a promise this class has to keep at every throw site.
|
|
459
|
+
*/
|
|
68
460
|
declare class ManifestLoadError extends Error {
|
|
69
461
|
readonly status: number;
|
|
70
462
|
constructor(status: number, message: string);
|
|
@@ -84,8 +476,21 @@ declare class ManifestLoader {
|
|
|
84
476
|
/**
|
|
85
477
|
* Loads the current manifest. On a cache hit (304) the cached
|
|
86
478
|
* body is returned — otherwise the fresh server body.
|
|
479
|
+
*
|
|
480
|
+
* A 304 with no usable cached body is not a failure to report but one to
|
|
481
|
+
* undo: the request only carried `If-None-Match` because this loader put
|
|
482
|
+
* the ETag there, and the cache it validated against is this loader's own.
|
|
483
|
+
* So it drops the pair and asks once more without the header, which is the
|
|
484
|
+
* same recovery a person would have had to trigger by hand — except that
|
|
485
|
+
* the person reading an admin screen has neither this loader nor a
|
|
486
|
+
* console. Exactly one retry: a 304 to a request that asked nothing
|
|
487
|
+
* conditional is a server fault, and no repetition fixes it.
|
|
87
488
|
*/
|
|
88
489
|
load(): Promise<AdminManifest>;
|
|
490
|
+
/** Sends the manifest GET, conditional when an ETag is supplied. */
|
|
491
|
+
private request;
|
|
492
|
+
/** Takes a non-304 response as the current manifest and caches it. */
|
|
493
|
+
private acceptFresh;
|
|
89
494
|
/** Reads the cached manifest body from storage; null if absent. */
|
|
90
495
|
readCachedBody(): CachedManifestEntry | null;
|
|
91
496
|
/** Clears the cache — e.g. on logout or after `manifest reload`. */
|
|
@@ -458,4 +863,4 @@ declare function identityAccentFor(key: string, overrides?: Readonly<Record<stri
|
|
|
458
863
|
*/
|
|
459
864
|
declare function identityChipStyle(accent: string): Record<string, string>;
|
|
460
865
|
|
|
461
|
-
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, IDENTITY_ACCENTS, IDENTITY_ACCENT_VALUES, IDENTITY_NEUTRAL, IDENTITY_NEUTRAL_VALUE, KvStore, type LoginBootProject, type LoginBrandFallback, type LoginBranding, ManifestLoadError, ManifestLoader, type ManifestLoaderOptions, type MessageParams, type NavBuilderOptions, type ParamStyle, type PlanCounts, type PlanRowLike, type PlanVersionLike, type ResolvePlansInput, type ResolvedPlan, SaLocale, type SidebarItem, type SidebarSection, buildRoutes, buildSidebar, countPlans, createAdminResourceClient, defaultSectionOrder, formatCurrency, formatMessage, getJson, identityAccentAt, identityAccentFor, identityChipStyle, isCurrentlyValid, isExpired, isFutureScheduled, isProductionBoot, postJson, resolveExtension, resolveLoginBranding, resolvePlans, todayIsoDate, trimTrailingSlashes };
|
|
866
|
+
export { ADMIN_UI_VERSION, AdminError, type AdminErrorInit, type AdminPromoListFilter, type AdminPromoListRow, type AdminResourceClientOptions, type AxiosHttpClientOptions, type AxiosLike, type AxiosLikeConfig, type AxiosLikeResponse, type AxiosLikeResponseConfig, type AxiosResponseBody, type BatchColumnData, BatchColumnDriftError, BatchColumnFetcher, type BatchColumnFetcherOptions, type BatchColumnRow, type BatchColumnValue, BootLoadError, BootLoader, type BootLoaderOptions, type BuildRouteEntry, type CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, type FetchHttpClientOptions, HttpClient, HttpJsonError, IDENTITY_ACCENTS, IDENTITY_ACCENT_VALUES, IDENTITY_NEUTRAL, IDENTITY_NEUTRAL_VALUE, KvStore, type LoginBootProject, type LoginBrandFallback, type LoginBranding, ManifestLoadError, ManifestLoader, type ManifestLoaderOptions, type MessageParams, type NavBuilderOptions, type ParamStyle, type PlanCounts, type PlanRowLike, type PlanVersionLike, type ResolvePlansInput, type ResolvedPlan, type ResourceRequestInit, SaLocale, SaMessages, type SidebarItem, type SidebarSection, adminErrorMessage, buildRoutes, buildSidebar, countPlans, createAdminResourceClient, createAxiosHttpClient, createFetchHttpClient, defaultSectionOrder, formatCurrency, formatMessage, getJson, identityAccentAt, identityAccentFor, identityChipStyle, isAdminError, isAxiosNoResponseError, isCurrentlyValid, isEmptyResponse, isExpired, isFutureScheduled, isPlatformError, isProductionBoot, isTransportFailure, markEmptyResponse, markPlatformError, markTransportFailure, postJson, readErrorCode, readErrorDetail, requestJson, requestJsonBody, requireServerAnswer, resolveExtension, resolveLoginBranding, resolvePlans, toAdminError, todayIsoDate, trimTrailingSlashes };
|
package/dist/client/index.js
CHANGED
|
@@ -4,23 +4,18 @@ import {
|
|
|
4
4
|
ActionRegistry,
|
|
5
5
|
BatchColumnDriftError,
|
|
6
6
|
BatchColumnFetcher,
|
|
7
|
-
BootLoadError,
|
|
8
|
-
BootLoader,
|
|
9
7
|
DEFAULT_STANDARD_PAGE_ROUTES,
|
|
10
|
-
HttpJsonError,
|
|
11
8
|
IDENTITY_ACCENTS,
|
|
12
9
|
IDENTITY_ACCENT_VALUES,
|
|
13
10
|
IDENTITY_NEUTRAL,
|
|
14
11
|
IDENTITY_NEUTRAL_VALUE,
|
|
15
|
-
ManifestLoadError,
|
|
16
|
-
ManifestLoader,
|
|
17
12
|
MissingHandlerError,
|
|
18
13
|
buildRoutes,
|
|
19
14
|
buildSidebar,
|
|
20
15
|
countPlans,
|
|
21
16
|
createAdminResourceClient,
|
|
17
|
+
createAxiosHttpClient,
|
|
22
18
|
defaultSectionOrder,
|
|
23
|
-
getJson,
|
|
24
19
|
identityAccentAt,
|
|
25
20
|
identityAccentFor,
|
|
26
21
|
identityChipStyle,
|
|
@@ -28,33 +23,75 @@ import {
|
|
|
28
23
|
isExpired,
|
|
29
24
|
isFutureScheduled,
|
|
30
25
|
isProductionBoot,
|
|
31
|
-
postJson,
|
|
32
26
|
resolveExtension,
|
|
33
27
|
resolveLoginBranding,
|
|
34
28
|
resolvePlans,
|
|
35
|
-
todayIsoDate
|
|
36
|
-
|
|
37
|
-
} from "../chunk-D74FFCCP.js";
|
|
29
|
+
todayIsoDate
|
|
30
|
+
} from "../chunk-NEXTZZRQ.js";
|
|
38
31
|
import {
|
|
32
|
+
AdminError,
|
|
33
|
+
BootLoadError,
|
|
34
|
+
BootLoader,
|
|
39
35
|
DEFAULT_SA_LOCALE,
|
|
36
|
+
HttpJsonError,
|
|
37
|
+
LIST_FIRST_PAGE,
|
|
38
|
+
LIST_PAGE_SIZE_DEFAULT,
|
|
39
|
+
LIST_PAGE_SIZE_MAX,
|
|
40
|
+
LIST_PAGINATION_PARAMS,
|
|
41
|
+
ManifestLoadError,
|
|
42
|
+
ManifestLoader,
|
|
40
43
|
SA_INTL_LOCALES,
|
|
41
44
|
SA_LOCALES,
|
|
42
45
|
SA_LOCALE_LABELS,
|
|
43
46
|
SA_MESSAGES,
|
|
47
|
+
adminErrorMessage,
|
|
48
|
+
auditResource,
|
|
49
|
+
bindResource,
|
|
50
|
+
clampListPage,
|
|
51
|
+
clampListPageSize,
|
|
52
|
+
createFetchHttpClient,
|
|
44
53
|
createSaCatalog,
|
|
45
54
|
defaultHttpClient,
|
|
46
55
|
defaultKvStore,
|
|
56
|
+
defineListOp,
|
|
47
57
|
defineMessages,
|
|
58
|
+
defineResource,
|
|
59
|
+
filterQueryString,
|
|
48
60
|
formatCurrency,
|
|
49
61
|
formatMessage,
|
|
62
|
+
getJson,
|
|
63
|
+
isAdminError,
|
|
64
|
+
isAxiosNoResponseError,
|
|
65
|
+
isEmptyResponse,
|
|
66
|
+
isPlatformError,
|
|
50
67
|
isSaBuiltinLocale,
|
|
68
|
+
isSentInQuery,
|
|
69
|
+
isTransportFailure,
|
|
70
|
+
listUrl,
|
|
71
|
+
markEmptyResponse,
|
|
72
|
+
markPlatformError,
|
|
73
|
+
markTransportFailure,
|
|
51
74
|
mergeMessages,
|
|
52
|
-
|
|
53
|
-
|
|
75
|
+
planVersionsResource,
|
|
76
|
+
plansResource,
|
|
77
|
+
platformResources,
|
|
78
|
+
postJson,
|
|
79
|
+
readErrorCode,
|
|
80
|
+
readErrorDetail,
|
|
81
|
+
readListPage,
|
|
82
|
+
requestJson,
|
|
83
|
+
requestJsonBody,
|
|
84
|
+
requireServerAnswer,
|
|
85
|
+
resolveMessages,
|
|
86
|
+
tenantsResource,
|
|
87
|
+
toAdminError,
|
|
88
|
+
trimTrailingSlashes
|
|
89
|
+
} from "../chunk-BPF2BMCQ.js";
|
|
54
90
|
export {
|
|
55
91
|
ADMIN_UI_VERSION,
|
|
56
92
|
ActionDefNotInManifestError,
|
|
57
93
|
ActionRegistry,
|
|
94
|
+
AdminError,
|
|
58
95
|
BatchColumnDriftError,
|
|
59
96
|
BatchColumnFetcher,
|
|
60
97
|
BootLoadError,
|
|
@@ -66,6 +103,10 @@ export {
|
|
|
66
103
|
IDENTITY_ACCENT_VALUES,
|
|
67
104
|
IDENTITY_NEUTRAL,
|
|
68
105
|
IDENTITY_NEUTRAL_VALUE,
|
|
106
|
+
LIST_FIRST_PAGE,
|
|
107
|
+
LIST_PAGE_SIZE_DEFAULT,
|
|
108
|
+
LIST_PAGE_SIZE_MAX,
|
|
109
|
+
LIST_PAGINATION_PARAMS,
|
|
69
110
|
ManifestLoadError,
|
|
70
111
|
ManifestLoader,
|
|
71
112
|
MissingHandlerError,
|
|
@@ -73,32 +114,63 @@ export {
|
|
|
73
114
|
SA_LOCALES,
|
|
74
115
|
SA_LOCALE_LABELS,
|
|
75
116
|
SA_MESSAGES,
|
|
117
|
+
adminErrorMessage,
|
|
118
|
+
auditResource,
|
|
119
|
+
bindResource,
|
|
76
120
|
buildRoutes,
|
|
77
121
|
buildSidebar,
|
|
122
|
+
clampListPage,
|
|
123
|
+
clampListPageSize,
|
|
78
124
|
countPlans,
|
|
79
125
|
createAdminResourceClient,
|
|
126
|
+
createAxiosHttpClient,
|
|
127
|
+
createFetchHttpClient,
|
|
80
128
|
createSaCatalog,
|
|
81
129
|
defaultHttpClient,
|
|
82
130
|
defaultKvStore,
|
|
83
131
|
defaultSectionOrder,
|
|
132
|
+
defineListOp,
|
|
84
133
|
defineMessages,
|
|
134
|
+
defineResource,
|
|
135
|
+
filterQueryString,
|
|
85
136
|
formatCurrency,
|
|
86
137
|
formatMessage,
|
|
87
138
|
getJson,
|
|
88
139
|
identityAccentAt,
|
|
89
140
|
identityAccentFor,
|
|
90
141
|
identityChipStyle,
|
|
142
|
+
isAdminError,
|
|
143
|
+
isAxiosNoResponseError,
|
|
91
144
|
isCurrentlyValid,
|
|
145
|
+
isEmptyResponse,
|
|
92
146
|
isExpired,
|
|
93
147
|
isFutureScheduled,
|
|
148
|
+
isPlatformError,
|
|
94
149
|
isProductionBoot,
|
|
95
150
|
isSaBuiltinLocale,
|
|
151
|
+
isSentInQuery,
|
|
152
|
+
isTransportFailure,
|
|
153
|
+
listUrl,
|
|
154
|
+
markEmptyResponse,
|
|
155
|
+
markPlatformError,
|
|
156
|
+
markTransportFailure,
|
|
96
157
|
mergeMessages,
|
|
158
|
+
planVersionsResource,
|
|
159
|
+
plansResource,
|
|
160
|
+
platformResources,
|
|
97
161
|
postJson,
|
|
162
|
+
readErrorCode,
|
|
163
|
+
readErrorDetail,
|
|
164
|
+
readListPage,
|
|
165
|
+
requestJson,
|
|
166
|
+
requestJsonBody,
|
|
167
|
+
requireServerAnswer,
|
|
98
168
|
resolveExtension,
|
|
99
169
|
resolveLoginBranding,
|
|
100
170
|
resolveMessages,
|
|
101
171
|
resolvePlans,
|
|
172
|
+
tenantsResource,
|
|
173
|
+
toAdminError,
|
|
102
174
|
todayIsoDate,
|
|
103
175
|
trimTrailingSlashes
|
|
104
176
|
};
|