@saasicat/ui-vue 0.26.0 → 0.26.1

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 CHANGED
@@ -22,6 +22,29 @@ root config) enforces the boundaries in CI.
22
22
  | `@saasicat/ui-vue/quasar` | `src/quasar/` | everything above + Quasar | `createSuperAdminApp()` bootstrap and the Quasar notify-port implementation. |
23
23
  | `@saasicat/ui-vue/pages-standard/*`, `/pages-tenant/*`, `/components/*` | SFC directories | everything | The Quasar reference UI, shipped as raw `.vue` from `src/` (compiled by the consumer's Vite). |
24
24
 
25
+ ### The shipped source has a language floor
26
+
27
+ The last row is not a build output: those subpaths hand out `.vue` and `.ts`
28
+ straight from `src/`, so **your** `tsconfig` compiles them, not ours. Anything
29
+ they reach — which includes `src/client/` and `src/vue/` — therefore has to
30
+ compile under the oldest language level a consumer uses.
31
+
32
+ That floor is **ES2021** (`lib: ES2021, DOM`), with **TypeScript 5.0** as the
33
+ minimum compiler. The language level is checked rather than promised:
34
+ `pnpm --filter @saasicat/ui-vue test:shipped-source` compiles the closure
35
+ reachable from every source-shipping subpath at that level, with
36
+ `isolatedModules`, `useDefineForClassFields` and `strictPropertyInitialization`
37
+ set the way a Vite app sets them, and CI runs it. The directories come from the export map, so a new source subpath
38
+ is covered the day it is added. The compiler version is not checked — `satisfies`
39
+ in the shipped source needs 4.9 or newer whatever `lib` says, and testing that
40
+ would mean installing old compilers.
41
+
42
+ Practically this rules out a handful of ES2022 conveniences in shipped code —
43
+ `new Error(msg, { cause })` and `Object.hasOwn` are the two that have come up.
44
+ Use `attachCause()` from `src/client/attach-cause.ts` and
45
+ `Object.prototype.hasOwnProperty.call()` instead. Code that only ever runs from
46
+ `dist/` is unaffected.
47
+
25
48
  Rules of thumb when contributing:
26
49
 
27
50
  - New page/business logic starts as a composable in `src/vue/` (or, if
@@ -4,6 +4,16 @@ function formatMessage(template, params) {
4
4
  return formatErrorMessage(template, params);
5
5
  }
6
6
 
7
+ // src/client/attach-cause.ts
8
+ function attachCause(error, cause) {
9
+ Object.defineProperty(error, "cause", {
10
+ value: cause,
11
+ configurable: true,
12
+ writable: true
13
+ });
14
+ return error;
15
+ }
16
+
7
17
  // src/client/admin-error.ts
8
18
  var ADMIN_ERROR = /* @__PURE__ */ Symbol.for("@saasicat/ui-vue/AdminError");
9
19
  var PLATFORM_ERROR = /* @__PURE__ */ Symbol.for("@saasicat/ui-vue/PlatformError");
@@ -63,7 +73,8 @@ var AdminError = class extends Error {
63
73
  /** The request never reached the server. See `AdminErrorInit`. */
64
74
  transportFailure;
65
75
  constructor(init = {}) {
66
- super(init.message ?? describe(init), { cause: init.cause });
76
+ super(init.message ?? describe(init));
77
+ if (init.cause !== void 0) attachCause(this, init.cause);
67
78
  this.name = "AdminError";
68
79
  this.status = init.status ?? 0;
69
80
  this.code = init.code;
@@ -4,7 +4,7 @@ import {
4
4
  bindResource,
5
5
  createSaCatalog,
6
6
  defaultKvStore
7
- } from "./chunk-BPF2BMCQ.js";
7
+ } from "./chunk-COVQLDBZ.js";
8
8
 
9
9
  // src/vue/super-admin-context.ts
10
10
  var SUPER_ADMIN_BRAND_KEY = /* @__PURE__ */ Symbol.for(
@@ -7,7 +7,7 @@ import {
7
7
  markTransportFailure,
8
8
  navMessages,
9
9
  trimTrailingSlashes
10
- } from "./chunk-BPF2BMCQ.js";
10
+ } from "./chunk-COVQLDBZ.js";
11
11
 
12
12
  // src/client/version.ts
13
13
  var ADMIN_UI_VERSION = "1.2.0";
@@ -116,7 +116,7 @@ var DEFAULT_STANDARD_PAGE_ROUTES = {
116
116
  platformEmailHistory: "/admin/platform-email-history"
117
117
  };
118
118
  function isSupportedStandardPageKey(key) {
119
- return Object.hasOwn(DEFAULT_STANDARD_PAGE_ROUTES, key);
119
+ return Object.prototype.hasOwnProperty.call(DEFAULT_STANDARD_PAGE_ROUTES, key);
120
120
  }
121
121
  var DEFAULT_ICONS = {
122
122
  dashboard: "dashboard",
@@ -111,6 +111,16 @@ module.exports = __toCommonJS(client_exports);
111
111
  // src/client/version.ts
112
112
  var ADMIN_UI_VERSION = "1.2.0";
113
113
 
114
+ // src/client/attach-cause.ts
115
+ function attachCause(error, cause) {
116
+ Object.defineProperty(error, "cause", {
117
+ value: cause,
118
+ configurable: true,
119
+ writable: true
120
+ });
121
+ return error;
122
+ }
123
+
114
124
  // src/client/i18n/format.ts
115
125
  var import_types = require("@saasicat/types");
116
126
  function formatMessage(template, params) {
@@ -176,7 +186,8 @@ var AdminError = class extends Error {
176
186
  /** The request never reached the server. See `AdminErrorInit`. */
177
187
  transportFailure;
178
188
  constructor(init = {}) {
179
- super(init.message ?? describe(init), { cause: init.cause });
189
+ super(init.message ?? describe(init));
190
+ if (init.cause !== void 0) attachCause(this, init.cause);
180
191
  this.name = "AdminError";
181
192
  this.status = init.status ?? 0;
182
193
  this.code = init.code;
@@ -1003,7 +1014,7 @@ var DEFAULT_STANDARD_PAGE_ROUTES = {
1003
1014
  platformEmailHistory: "/admin/platform-email-history"
1004
1015
  };
1005
1016
  function isSupportedStandardPageKey(key) {
1006
- return Object.hasOwn(DEFAULT_STANDARD_PAGE_ROUTES, key);
1017
+ return Object.prototype.hasOwnProperty.call(DEFAULT_STANDARD_PAGE_ROUTES, key);
1007
1018
  }
1008
1019
  var DEFAULT_ICONS = {
1009
1020
  dashboard: "dashboard",
@@ -260,6 +260,21 @@ declare class AdminError extends Error {
260
260
  readonly emptyResponse: boolean;
261
261
  /** The request never reached the server. See `AdminErrorInit`. */
262
262
  readonly transportFailure: boolean;
263
+ /**
264
+ * The error this one was raised from, when `AdminErrorInit` carried one.
265
+ *
266
+ * `declare` because the property is real but not emitted here: `attachCause`
267
+ * defines it, exactly as the ES2022 `Error` constructor would. The
268
+ * declaration is what makes it *readable* — `Error.cause` lives in
269
+ * `lib.es2022.error.d.ts`, and this package supports consumers on ES2021,
270
+ * where taking a cause in and never being able to read it out would be a
271
+ * one-way public API.
272
+ *
273
+ * Not `readonly`, unlike its siblings: the inherited `Error.cause` is
274
+ * writable, and narrowing that in a patch release would reject assignments
275
+ * a consumer can make today on ES2022.
276
+ */
277
+ cause?: unknown;
263
278
  constructor(init?: AdminErrorInit);
264
279
  }
265
280
  /** Whether `err` is an `AdminError`, including one from another bundle copy. */
@@ -260,6 +260,21 @@ declare class AdminError extends Error {
260
260
  readonly emptyResponse: boolean;
261
261
  /** The request never reached the server. See `AdminErrorInit`. */
262
262
  readonly transportFailure: boolean;
263
+ /**
264
+ * The error this one was raised from, when `AdminErrorInit` carried one.
265
+ *
266
+ * `declare` because the property is real but not emitted here: `attachCause`
267
+ * defines it, exactly as the ES2022 `Error` constructor would. The
268
+ * declaration is what makes it *readable* — `Error.cause` lives in
269
+ * `lib.es2022.error.d.ts`, and this package supports consumers on ES2021,
270
+ * where taking a cause in and never being able to read it out would be a
271
+ * one-way public API.
272
+ *
273
+ * Not `readonly`, unlike its siblings: the inherited `Error.cause` is
274
+ * writable, and narrowing that in a patch release would reject assignments
275
+ * a consumer can make today on ES2022.
276
+ */
277
+ cause?: unknown;
263
278
  constructor(init?: AdminErrorInit);
264
279
  }
265
280
  /** Whether `err` is an `AdminError`, including one from another bundle copy. */
@@ -27,7 +27,7 @@ import {
27
27
  resolveLoginBranding,
28
28
  resolvePlans,
29
29
  todayIsoDate
30
- } from "../chunk-NEXTZZRQ.js";
30
+ } from "../chunk-O3Y3BYYS.js";
31
31
  import {
32
32
  AdminError,
33
33
  BootLoadError,
@@ -86,7 +86,7 @@ import {
86
86
  tenantsResource,
87
87
  toAdminError,
88
88
  trimTrailingSlashes
89
- } from "../chunk-BPF2BMCQ.js";
89
+ } from "../chunk-COVQLDBZ.js";
90
90
  export {
91
91
  ADMIN_UI_VERSION,
92
92
  ActionDefNotInManifestError,
package/dist/index.cjs CHANGED
@@ -206,6 +206,16 @@ module.exports = __toCommonJS(src_exports);
206
206
  // src/client/version.ts
207
207
  var ADMIN_UI_VERSION = "1.2.0";
208
208
 
209
+ // src/client/attach-cause.ts
210
+ function attachCause(error, cause) {
211
+ Object.defineProperty(error, "cause", {
212
+ value: cause,
213
+ configurable: true,
214
+ writable: true
215
+ });
216
+ return error;
217
+ }
218
+
209
219
  // src/client/i18n/format.ts
210
220
  var import_types = require("@saasicat/types");
211
221
  function formatMessage(template, params) {
@@ -271,7 +281,8 @@ var AdminError = class extends Error {
271
281
  /** The request never reached the server. See `AdminErrorInit`. */
272
282
  transportFailure;
273
283
  constructor(init = {}) {
274
- super(init.message ?? describe(init), { cause: init.cause });
284
+ super(init.message ?? describe(init));
285
+ if (init.cause !== void 0) attachCause(this, init.cause);
275
286
  this.name = "AdminError";
276
287
  this.status = init.status ?? 0;
277
288
  this.code = init.code;
@@ -1098,7 +1109,7 @@ var DEFAULT_STANDARD_PAGE_ROUTES = {
1098
1109
  platformEmailHistory: "/admin/platform-email-history"
1099
1110
  };
1100
1111
  function isSupportedStandardPageKey(key) {
1101
- return Object.hasOwn(DEFAULT_STANDARD_PAGE_ROUTES, key);
1112
+ return Object.prototype.hasOwnProperty.call(DEFAULT_STANDARD_PAGE_ROUTES, key);
1102
1113
  }
1103
1114
  var DEFAULT_ICONS = {
1104
1115
  dashboard: "dashboard",
package/dist/index.js CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  resolveLoginBranding,
28
28
  resolvePlans,
29
29
  todayIsoDate
30
- } from "./chunk-NEXTZZRQ.js";
30
+ } from "./chunk-O3Y3BYYS.js";
31
31
  import {
32
32
  SA_COLOR_SCHEMES,
33
33
  SA_LOCALE_STORAGE_KEY,
@@ -55,7 +55,7 @@ import {
55
55
  useSaMessages,
56
56
  useSaTheme,
57
57
  useSuperAdminI18n
58
- } from "./chunk-O3J3ITF2.js";
58
+ } from "./chunk-DT25QAU2.js";
59
59
  import {
60
60
  AdminError,
61
61
  BootLoadError,
@@ -114,7 +114,7 @@ import {
114
114
  tenantsResource,
115
115
  toAdminError,
116
116
  trimTrailingSlashes
117
- } from "./chunk-BPF2BMCQ.js";
117
+ } from "./chunk-COVQLDBZ.js";
118
118
 
119
119
  // src/vue/use-super-admin-context.ts
120
120
  import { inject } from "vue";
@@ -38,6 +38,16 @@ var import_quasar4 = require("quasar");
38
38
  var import_pinia = require("pinia");
39
39
  var import_vue_router = require("vue-router");
40
40
 
41
+ // src/client/attach-cause.ts
42
+ function attachCause(error, cause) {
43
+ Object.defineProperty(error, "cause", {
44
+ value: cause,
45
+ configurable: true,
46
+ writable: true
47
+ });
48
+ return error;
49
+ }
50
+
41
51
  // src/client/i18n/format.ts
42
52
  var import_types = require("@saasicat/types");
43
53
 
@@ -86,7 +96,8 @@ var AdminError = class extends Error {
86
96
  /** The request never reached the server. See `AdminErrorInit`. */
87
97
  transportFailure;
88
98
  constructor(init = {}) {
89
- super(init.message ?? describe(init), { cause: init.cause });
99
+ super(init.message ?? describe(init));
100
+ if (init.cause !== void 0) attachCause(this, init.cause);
90
101
  this.name = "AdminError";
91
102
  this.status = init.status ?? 0;
92
103
  this.code = init.code;
@@ -17,11 +17,11 @@ import {
17
17
  createSaTheme,
18
18
  createSuperAdminI18n,
19
19
  resolveSuperAdminEndpoints
20
- } from "../chunk-O3J3ITF2.js";
20
+ } from "../chunk-DT25QAU2.js";
21
21
  import {
22
22
  defaultHttpClient,
23
23
  platformResources
24
- } from "../chunk-BPF2BMCQ.js";
24
+ } from "../chunk-COVQLDBZ.js";
25
25
 
26
26
  // src/quasar/create-super-admin-app.ts
27
27
  import { createApp } from "vue";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saasicat/ui-vue",
3
- "version": "0.26.0",
3
+ "version": "0.26.1",
4
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",
@@ -61,7 +61,7 @@
61
61
  "src"
62
62
  ],
63
63
  "dependencies": {
64
- "@saasicat/types": "^0.26.0"
64
+ "@saasicat/types": "^0.26.1"
65
65
  },
66
66
  "peerDependencies": {
67
67
  "pinia": "^2.0.0 || ^3.0.0",
@@ -121,6 +121,7 @@
121
121
  "test:component": "vitest run --config vitest.config.ts",
122
122
  "test:e2e": "playwright test",
123
123
  "test:visual": "playwright test --project=visual",
124
- "test:visual:update": "playwright test --project=visual --update-snapshots"
124
+ "test:visual:update": "playwright test --project=visual --update-snapshots",
125
+ "test:shipped-source": "node scripts/check-shipped-source.mjs"
125
126
  }
126
127
  }
@@ -19,6 +19,7 @@
19
19
  // `adminErrorMessage()` is what turns an error into user-facing text; it is
20
20
  // the only place that decides between `detail` and a translated fallback.
21
21
 
22
+ import { attachCause } from './attach-cause.js';
22
23
  import { formatMessage } from './i18n/format.js';
23
24
  import type { SaMessages } from './i18n/messages.js';
24
25
 
@@ -234,9 +235,25 @@ export class AdminError extends Error {
234
235
  readonly emptyResponse: boolean;
235
236
  /** The request never reached the server. See `AdminErrorInit`. */
236
237
  readonly transportFailure: boolean;
238
+ /**
239
+ * The error this one was raised from, when `AdminErrorInit` carried one.
240
+ *
241
+ * `declare` because the property is real but not emitted here: `attachCause`
242
+ * defines it, exactly as the ES2022 `Error` constructor would. The
243
+ * declaration is what makes it *readable* — `Error.cause` lives in
244
+ * `lib.es2022.error.d.ts`, and this package supports consumers on ES2021,
245
+ * where taking a cause in and never being able to read it out would be a
246
+ * one-way public API.
247
+ *
248
+ * Not `readonly`, unlike its siblings: the inherited `Error.cause` is
249
+ * writable, and narrowing that in a patch release would reject assignments
250
+ * a consumer can make today on ES2022.
251
+ */
252
+ declare cause?: unknown;
237
253
 
238
254
  constructor(init: AdminErrorInit = {}) {
239
- super(init.message ?? describe(init), { cause: init.cause });
255
+ super(init.message ?? describe(init));
256
+ if (init.cause !== undefined) attachCause(this, init.cause);
240
257
  this.name = 'AdminError';
241
258
  this.status = init.status ?? 0;
242
259
  this.code = init.code;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Attach a cause to an error without the ES2022 `Error` constructor option.
3
+ *
4
+ * `new Error(message, { cause })` needs `lib: ES2022`. This package ships four
5
+ * of its export subpaths as `.vue`/`.ts` **source** — a consumer compiles those
6
+ * files, and everything they reach, with their own `tsconfig`. One of them is on
7
+ * ES2021, where that second argument is a compile error in code they did not
8
+ * write.
9
+ *
10
+ * Defining the property afterwards reads identically to anything inspecting
11
+ * `error.cause`, and needs nothing above ES5. `scripts/check-shipped-source.mjs`
12
+ * holds the floor.
13
+ */
14
+ export function attachCause<E extends Error>(error: E, cause: unknown): E {
15
+ Object.defineProperty(error, 'cause', {
16
+ value: cause,
17
+ configurable: true,
18
+ writable: true,
19
+ });
20
+ return error;
21
+ }
@@ -36,7 +36,9 @@ export const DEFAULT_STANDARD_PAGE_ROUTES: Record<StandardPageKey, string> = {
36
36
  };
37
37
 
38
38
  function isSupportedStandardPageKey(key: string): key is StandardPageKey {
39
- return Object.hasOwn(DEFAULT_STANDARD_PAGE_ROUTES, key);
39
+ // `Object.hasOwn` is ES2022 and this file is compiled by consumers.
40
+ // See `attach-cause.ts` for why the floor is ES2021.
41
+ return Object.prototype.hasOwnProperty.call(DEFAULT_STANDARD_PAGE_ROUTES, key);
40
42
  }
41
43
 
42
44
  export interface BuildRouteEntry {
@@ -151,6 +151,7 @@
151
151
  </template>
152
152
 
153
153
  <script setup lang="ts">
154
+ import { attachCause } from '../client/attach-cause.js';
154
155
  import { computed, reactive, ref } from 'vue';
155
156
  import { SETUP_ERROR_CODES, type SetupConfirmMfaResponse, type SetupResult } from '@saasicat/types';
156
157
 
@@ -237,10 +238,12 @@ async function postJson<T>(path: string, body: unknown): Promise<T> {
237
238
  if (err instanceof HttpJsonError) {
238
239
  // The message is translated for the user; `cause` keeps the status
239
240
  // and the machine-readable code reachable for anything upstream.
240
- throw new Error(
241
- (err.code && errorByCode.value[err.code]) ||
242
- formatMessage(msg.value.setup.errorHttp, { status: err.status }),
243
- { cause: err },
241
+ throw attachCause(
242
+ new Error(
243
+ (err.code && errorByCode.value[err.code]) ||
244
+ formatMessage(msg.value.setup.errorHttp, { status: err.status }),
245
+ ),
246
+ err,
244
247
  );
245
248
  }
246
249
  throw err;