@antelopejs/dms 0.3.8 → 0.4.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/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.4.0
4
+
5
+ [compare changes](https://github.com/AntelopeJS/dms/compare/v0.3.8...v0.4.0)
6
+
7
+ ### 💅 Refactors
8
+
9
+ - **build:** Merge tsconfig.build.json into tsconfig.json ([#39](https://github.com/AntelopeJS/dms/pull/39))
10
+ - **package:** ⚠️ Drop moduleResolution node support and pack-based checks ([#41](https://github.com/AntelopeJS/dms/pull/41))
11
+
12
+ ### 🏡 Chore
13
+
14
+ - **release:** @antelopejs/interface-dms v0.2.0 ([98ad6f4](https://github.com/AntelopeJS/dms/commit/98ad6f4))
15
+
16
+ ### 🤖 CI
17
+
18
+ - **release:** Release next from a dedicated branch and restore requireCommits ([#38](https://github.com/AntelopeJS/dms/pull/38))
19
+ - **release:** Reference the shared release workflows through v1 ([#40](https://github.com/AntelopeJS/dms/pull/40))
20
+
21
+ #### ⚠️ Breaking Changes
22
+
23
+ - **package:** ⚠️ Drop moduleResolution node support and pack-based checks ([#41](https://github.com/AntelopeJS/dms/pull/41))
24
+
25
+ ### ❤️ Contributors
26
+
27
+ - Antony Rizzitelli <rizzitelli.antony@pm.me>
28
+
3
29
  ## v0.3.8
4
30
 
5
31
  [compare changes](https://github.com/AntelopeJS/dms/compare/v0.3.7...v0.3.8)
@@ -3,5 +3,5 @@ import { Action, type ComponentTargetInput } from "@antelopejs/interface-dms/com
3
3
  import type { TenantGuardOptions } from "@antelopejs/interface-dms/guards";
4
4
  import type { TenantTokenInput } from "@antelopejs/interface-dms/auth";
5
5
  export declare namespace internal {
6
- const AuthUserWithPermissionValidator: (target: ComponentTargetInput | ControllerClass | Action, data: TenantTokenInput, options?: TenantGuardOptions) => Promise<false | import("@antelopejs/interface-dms/dist/auth/db").User>;
6
+ const AuthUserWithPermissionValidator: (target: ComponentTargetInput | ControllerClass | Action, data: TenantTokenInput, options?: TenantGuardOptions) => Promise<false | import("@antelopejs/interface-dms/auth/db").User>;
7
7
  }
@@ -22,7 +22,7 @@ export declare function startExport(controller: DataControllerThis, ctx: Request
22
22
  format: string;
23
23
  extension: string;
24
24
  }>;
25
- export declare function getExportStatus(controller: DataControllerThis, ctx: RequestContext, exportId: string, user?: User): Promise<import("@antelopejs/interface-dms/dist/base/export-jobs").ExportJobStatus>;
25
+ export declare function getExportStatus(controller: DataControllerThis, ctx: RequestContext, exportId: string, user?: User): Promise<import("@antelopejs/interface-dms/base").ExportJobStatus>;
26
26
  export declare function downloadExport(controller: DataControllerThis, ctx: RequestContext, exportId: string, user?: User): Promise<void>;
27
27
  interface RuleValidationResult {
28
28
  eligibleIds: string[];
@@ -1 +1 @@
1
- export declare const userCategory: import("@antelopejs/interface-dms/page").CategoryInfo;
1
+ export declare const userCategory: import("@antelopejs/interface-dms").CategoryInfo;
@@ -1,7 +1,7 @@
1
1
  import { type RequestContext } from "@antelopejs/interface-api";
2
2
  import type { Action } from "@antelopejs/interface-dms/component";
3
3
  import { type User, UserModel } from "@antelopejs/interface-dms/auth/db";
4
- export declare const membersTable: import("@antelopejs/interface-dms/component").ComponentBuilder<import("@antelopejs/interface-dms/base").TableViewOptionsSerialized>;
4
+ export declare const membersTable: import("@antelopejs/interface-dms").ComponentBuilder<import("@antelopejs/interface-dms/base").TableViewOptionsSerialized>;
5
5
  export declare const membersTableAddAction: Action;
6
6
  declare const MembersSettingsController_base: {
7
7
  new (...args: any[]): {};
@@ -9,7 +9,7 @@ declare const MembersSettingsController_base: {
9
9
  location: string;
10
10
  };
11
11
  export declare class MembersSettingsController extends MembersSettingsController_base {
12
- static table: import("@antelopejs/interface-dms/component").ComponentBuilder<import("@antelopejs/interface-dms/base").TableViewOptionsSerialized>;
12
+ static table: import("@antelopejs/interface-dms").ComponentBuilder<import("@antelopejs/interface-dms/base").TableViewOptionsSerialized>;
13
13
  invite(ctx: RequestContext, _user: User, userModel: UserModel, body: unknown): Promise<{
14
14
  redirectPath: string;
15
15
  }>;
@@ -15,8 +15,8 @@ export declare class NotificationsApiController extends NotificationsApiControll
15
15
  getPreferences(preferencesModel: UserNotificationPreferencesModel): Promise<Record<string, boolean>>;
16
16
  updatePreferences(body: unknown, preferencesModel: UserNotificationPreferencesModel): Promise<Record<string, boolean>>;
17
17
  getCategories(): Promise<{
18
- categories: import("@antelopejs/interface-dms/dist/notifications/types").NotificationCategoryInfo[];
19
- subjects: import("@antelopejs/interface-dms/dist/notifications/types").NotificationSubjectInfo[];
18
+ categories: import("@antelopejs/interface-dms/notifications/types").NotificationCategoryInfo[];
19
+ subjects: import("@antelopejs/interface-dms/notifications/types").NotificationSubjectInfo[];
20
20
  }>;
21
21
  getNotifications(notificationsModel: UserNotificationsModel, limitParam?: string, offsetParam?: string): Promise<import("../../../db").UserNotification[]>;
22
22
  getUnreadCount(notificationsModel: UserNotificationsModel): Promise<{
@@ -5,10 +5,10 @@ declare const NativeFilePage_base: {
5
5
  location: string;
6
6
  };
7
7
  export declare class NativeFilePage extends NativeFilePage_base {
8
- static content: import("@antelopejs/interface-dms").ComponentBuilder<import("@antelopejs/interface-dms/base/table-view").TableViewOptionsSerialized>;
8
+ static content: import("@antelopejs/interface-dms").ComponentBuilder<import("@antelopejs/interface-dms/base").TableViewOptionsSerialized>;
9
9
  }
10
10
  declare const NativeAttachmentFormController_base: import("@antelopejs/interface-api").ControllerClass<object>;
11
11
  export declare class NativeAttachmentFormController extends NativeAttachmentFormController_base {
12
- get(_user: User): Promise<import("@antelopejs/interface-dms").ComponentInfoSerialized<import("@antelopejs/interface-dms/base/table-view").TableViewOptionsSerialized>>;
12
+ get(_user: User): Promise<import("@antelopejs/interface-dms").ComponentInfoSerialized<import("@antelopejs/interface-dms/base").TableViewOptionsSerialized>>;
13
13
  }
14
14
  export {};
@@ -7,29 +7,29 @@ export declare const authSchema: {
7
7
  lang: z.ZodString;
8
8
  token: z.ZodString;
9
9
  }, "strip", z.ZodTypeAny, {
10
- name: string;
11
- lang: string;
12
- email: string;
13
10
  token: string;
14
- password: string;
15
- }, {
16
11
  name: string;
17
- lang: string;
12
+ password: string;
18
13
  email: string;
14
+ lang: string;
15
+ }, {
19
16
  token: string;
17
+ name: string;
20
18
  password: string;
19
+ email: string;
20
+ lang: string;
21
21
  }>;
22
22
  login: z.ZodObject<{
23
23
  email: z.ZodString;
24
24
  password: z.ZodString;
25
25
  keep_login: z.ZodOptional<z.ZodBoolean>;
26
26
  }, "strip", z.ZodTypeAny, {
27
- email: string;
28
27
  password: string;
28
+ email: string;
29
29
  keep_login?: boolean | undefined;
30
30
  }, {
31
- email: string;
32
31
  password: string;
32
+ email: string;
33
33
  keep_login?: boolean | undefined;
34
34
  }>;
35
35
  oauthCallback: z.ZodObject<{
@@ -42,14 +42,14 @@ export declare const authSchema: {
42
42
  code: string;
43
43
  state: string;
44
44
  state_cookie: string;
45
- language?: string | undefined;
46
45
  invite?: string | undefined;
46
+ language?: string | undefined;
47
47
  }, {
48
48
  code: string;
49
49
  state: string;
50
50
  state_cookie: string;
51
- language?: string | undefined;
52
51
  invite?: string | undefined;
52
+ language?: string | undefined;
53
53
  }>;
54
54
  refresh: z.ZodObject<{
55
55
  token: z.ZodString;
@@ -83,37 +83,37 @@ export declare const authSchema: {
83
83
  token: z.ZodString;
84
84
  email: z.ZodString;
85
85
  }, "strip", z.ZodTypeAny, {
86
- email: string;
87
86
  token: string;
88
- }, {
89
87
  email: string;
88
+ }, {
90
89
  token: string;
90
+ email: string;
91
91
  }>;
92
92
  reset: z.ZodObject<{
93
93
  token: z.ZodString;
94
94
  email: z.ZodString;
95
95
  password: z.ZodString;
96
96
  }, "strip", z.ZodTypeAny, {
97
- email: string;
98
97
  token: string;
99
98
  password: string;
100
- }, {
101
99
  email: string;
100
+ }, {
102
101
  token: string;
103
102
  password: string;
103
+ email: string;
104
104
  }>;
105
105
  verify2FA: z.ZodObject<{
106
106
  token: z.ZodString;
107
107
  code: z.ZodString;
108
108
  method: z.ZodEnum<["totp", "email", "backup"]>;
109
109
  }, "strip", z.ZodTypeAny, {
110
- code: string;
111
110
  method: "email" | "totp" | "backup";
112
111
  token: string;
113
- }, {
114
112
  code: string;
113
+ }, {
115
114
  method: "email" | "totp" | "backup";
116
115
  token: string;
116
+ code: string;
117
117
  }>;
118
118
  request2FAEmail: z.ZodObject<{
119
119
  token: z.ZodString;
@@ -133,11 +133,11 @@ export declare const authSchema: {
133
133
  method: z.ZodEnum<["totp", "email"]>;
134
134
  code: z.ZodString;
135
135
  }, "strip", z.ZodTypeAny, {
136
- code: string;
137
136
  method: "email" | "totp";
138
- }, {
139
137
  code: string;
138
+ }, {
140
139
  method: "email" | "totp";
140
+ code: string;
141
141
  }>;
142
142
  regenerateBackup: z.ZodObject<{
143
143
  code: z.ZodString;
@@ -5,18 +5,18 @@ export declare const onboardingRegisterAdminSchema: z.ZodEffects<z.ZodObject<{
5
5
  password: z.ZodString;
6
6
  }, "strip", z.ZodTypeAny, {
7
7
  name: string;
8
- email: string;
9
8
  password: string;
9
+ email: string;
10
10
  }, {
11
11
  name: string;
12
- email: string;
13
12
  password: string;
13
+ email: string;
14
14
  }>, {
15
15
  email: string;
16
16
  name: string;
17
17
  password: string;
18
18
  }, {
19
19
  name: string;
20
- email: string;
21
20
  password: string;
21
+ email: string;
22
22
  }>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antelopejs/dms",
3
- "version": "0.3.8",
3
+ "version": "0.4.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/AntelopeJS/dms.git"
@@ -9,6 +9,7 @@
9
9
  "types": "dist/index.d.ts",
10
10
  "files": [
11
11
  "dist",
12
+ "!dist/.tsbuildinfo",
12
13
  "frontend-vue",
13
14
  "skills",
14
15
  "package.json",
@@ -73,7 +74,7 @@
73
74
  "release-it-changelogen": "^0.1.0",
74
75
  "rimraf": "^6.1.3",
75
76
  "tsc-alias": "^1.9.1",
76
- "typescript": "^5.9.3"
77
+ "typescript": "^6.0.3"
77
78
  },
78
79
  "exports": {
79
80
  ".": {
@@ -83,13 +84,6 @@
83
84
  "./package.json": "./package.json",
84
85
  "./interfaces/*": null
85
86
  },
86
- "typesVersions": {
87
- "*": {
88
- "pages": [
89
- "dist/pages/index.d.ts"
90
- ]
91
- }
92
- },
93
87
  "publishConfig": {
94
88
  "access": "public",
95
89
  "provenance": true,
@@ -108,22 +102,17 @@
108
102
  }
109
103
  },
110
104
  "scripts": {
111
- "build": "pnpm --filter @antelopejs/interface-dms build && rimraf dist && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
105
+ "build": "pnpm --filter @antelopejs/interface-dms build && rimraf dist && tsc && tsc-alias",
112
106
  "format": "oxfmt . && pnpm --dir frontend-vue format",
113
107
  "dev": "ajs project run --inspect -w -p playground",
114
108
  "frontend:dev": "pnpm --dir playground frontend:dev",
115
109
  "lint:fix": "oxlint --fix --max-warnings=1000000 && oxfmt . && pnpm --dir frontend-vue lint:fix",
116
110
  "lint": "oxlint && oxfmt --check . && pnpm --dir frontend-vue lint",
117
- "performance:inertia-navigation": "node scripts/check-inertia-navigation.mjs",
118
- "check:inertia-runtime": "node scripts/check-inertia-runtime.mjs",
119
- "check:inertia-contracts": "node scripts/check-inertia-contracts.mjs",
120
- "check:inertia-modules": "node scripts/check-inertia-modules.mjs",
121
- "typecheck": "pnpm --filter @antelopejs/interface-dms build && tsc -p tsconfig.json",
122
- "check:package": "node scripts/check-package.mjs",
123
- "test": "pnpm run build && ajs module test . && pnpm run check:package",
111
+ "typecheck": "pnpm --filter @antelopejs/interface-dms build && tsc --noEmit",
112
+ "test": "pnpm run build && ajs module test .",
124
113
  "test:unit": "pnpm run build && DMS_TEST_DIR=dist/test/unit ajs module test .",
125
114
  "test:integration": "pnpm run build && DMS_TEST_DIR=dist/test/integration ajs module test .",
126
- "test:watch": "tsc -p tsconfig.build.json -w & tsc-alias -p tsconfig.build.json -w",
115
+ "test:watch": "tsc -w & tsc-alias -w",
127
116
  "release": "pnpm --filter @antelopejs/interface-dms build && pnpm --dir frontend-vue install --frozen-lockfile && release-it",
128
117
  "knip": "knip --dependencies",
129
118
  "knip:all": "knip"
@@ -15,8 +15,7 @@ List a section to see its files:
15
15
  | `docs/04.components/` | Component catalog: charts/widgets, layout, forms, tables, tree, DataTypes, DataController, file storage |
16
16
  | `docs/05.extending-the-dashboard/` | Dashboard chrome, theming, custom DataTypes (frontend side), table-view displays, component events, period filtering |
17
17
  | `docs/06.frontend-composables/` | Composables a custom frontend module's Vue calls: auth'd requests, realtime, page context, UI toolkit |
18
- | `docs/07.performance/` | Inertia navigation budgets and how to measure them |
19
- | `docs/08.interfaces/` | The contract reference for `@antelopejs/interface-dms`, one folder per domain: `core`, `auth`, `base`, `notifications`, `html-render` |
18
+ | `docs/07.interfaces/` | The contract reference for `@antelopejs/interface-dms`, one folder per domain: `core`, `auth`, `base`, `notifications`, `html-render` |
20
19
 
21
20
  ## Exact interface surfaces: don't memorize, look them up
22
21
 
@@ -37,7 +36,7 @@ Three ways to read a contract:
37
36
  node "<antelopejs-plugin>/scripts/resolve-interface.mjs" show <scope>/interface-<name>
38
37
  ```
39
38
 
40
- 2. **The prose reference** — `docs/08.interfaces/`, one folder per domain, with the whole subpath
39
+ 2. **The prose reference** — `docs/07.interfaces/`, one folder per domain, with the whole subpath
41
40
  map in its `index.md`.
42
41
 
43
42
  3. **The sources shipped with this skill** — this workspace carries the interface package; read
@@ -75,7 +75,7 @@ chatbox.
75
75
  ## Docs & exact interface surfaces (read for depth)
76
76
 
77
77
  Long-form reference docs live in this package's `docs/` directory (shipped with the package; also
78
- at the repo root), in eight numbered sections — the last, `docs/08.interfaces/`, is the contract
78
+ at the repo root), in seven numbered sections — the last, `docs/07.interfaces/`, is the contract
79
79
  reference for `@antelopejs/interface-dms` domain by domain. DataTypes, component builder options, and auth
80
80
  decorators are **versioned interface contracts** — look them up rather than hand-recalling; treat
81
81
  skill examples as patterns, not gospel. See [REFERENCE.md](REFERENCE.md) for the docs map and the
@@ -55,10 +55,9 @@ AntelopeJS — see the **antelopejs** plugin's author/consume skills. The DMS-sp
55
55
  `src/implementations/<name>/index.ts` in the module, **wire** with `ImplementInterface` in
56
56
  `construct` (the lifecycle entry in [SKILL.md](SKILL.md)). Keep `/** @internal */` on the
57
57
  `internal` namespace — the convention marking the registration surface as non-consumer API.
58
- - **Expose** each directory index as an explicit `exports` entry, plus the `typesVersions`
59
- mapping that lets a consumer on `moduleResolution: node` resolve the types. Consumers add
60
- the interface package to `dependencies` and
61
- `import { … } from "@antelopejs/interface-<name>"`.
58
+ - **Expose** each directory index as an explicit `exports` entry; consumers resolve it with
59
+ `moduleResolution: bundler`, `node16` or `nodenext`. Consumers add the interface package to
60
+ `dependencies` and `import { … } from "@antelopejs/interface-<name>"`.
62
61
  - Anything consumer-facing lives in the interface package; never re-export internal modules —
63
62
  if a helper needs internal infrastructure, use the hook-setter indirection pattern the
64
63
  existing modules use rather than exposing the internals. Runtime behaviour stays in the
@@ -76,7 +75,7 @@ AntelopeJS — see the **antelopejs** plugin's author/consume skills. The DMS-sp
76
75
  3. **Scaffold the layout above**: `src/index.ts`, `src/pages/`, `src/routes/` (if it serves data),
77
76
  `packages/interface-<name>/` + `src/implementations/<name>/` (only if it exposes one),
78
77
  `frontend-vue/` (components registered from the root `dms.frontend.ts`), and the manifest
79
- (`antelopeJs` block, plus the interface package's `exports`/`typesVersions`).
78
+ (`antelopeJs` block, plus the interface package's `exports`).
80
79
  4. **Wire the basics**: `RegisterModule({ id, title, icon, … })`, one `@RegisterPage()` page,
81
80
  the `AddFrontendModule` call. Add the `$dms_<name>.*` keys to **every** locale file under
82
81
  `frontend-vue/i18n/locales/`.
@@ -25,7 +25,7 @@ defining the module's own interface, and the scaffolding checklist.
25
25
  ## The `package.json` manifest
26
26
 
27
27
  The `antelopeJs` block is what makes it a DMS module ([REFERENCE.md](REFERENCE.md) has the full
28
- manifest, including the `exports`/`typesVersions` entries for an interface subpath).
28
+ manifest, including the `exports` entries for an interface subpath).
29
29
  `implements` lists only the interfaces the module *provides* — the official modules keep it `[]`
30
30
  when they provide none (`dms-lang`, `dms-saas`); consumed interfaces are plain `dependencies`
31
31
  (no manifest field). Typical dependencies: `@antelopejs/dms` plus
@@ -1,130 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import { execFileSync } from "node:child_process";
3
- import { mkdirSync } from "node:fs";
4
- import { resolve } from "node:path";
5
-
6
- const [url, theme = "custom", screenshots] = process.argv.slice(2);
7
- if (!url)
8
- throw new Error(
9
- "Usage: node tests/theming-browser.mjs URL [custom|default] [screenshots]",
10
- );
11
- const session = "dms-theming-test";
12
- const transitionWait = "500";
13
- const browser = (...args) =>
14
- execFileSync("agent-browser", ["--session", session, ...args], {
15
- encoding: "utf8",
16
- }).trim();
17
- const evaluate = (expression) => JSON.parse(browser("eval", expression));
18
-
19
- function inspectTheme() {
20
- const root = getComputedStyle(document.documentElement);
21
- const probe = document.createElement("span");
22
- document.body.append(probe);
23
- const colors = ["--ui-primary", "--ui-color-primary-600", "--ui-success"].map(
24
- (token) => {
25
- probe.style.backgroundColor = `var(${token})`;
26
- return getComputedStyle(probe).backgroundColor;
27
- },
28
- );
29
- probe.remove();
30
- const background = (selector) =>
31
- getComputedStyle(document.querySelector(selector)).backgroundColor;
32
- const images = [...document.querySelectorAll("main img")].filter(
33
- (image) => image.getClientRects().length,
34
- );
35
- return {
36
- radius: root.getPropertyValue("--ui-radius").trim(),
37
- font: root.getPropertyValue("--font-sans"),
38
- accent: root.getPropertyValue("--dms-accent").trim(),
39
- accentPalette: ["500", "400"].map((shade) =>
40
- root.getPropertyValue(`--ui-color-primary-${shade}`).trim(),
41
- ),
42
- config: document.querySelector("#config").textContent,
43
- colors,
44
- button: background("#primary"),
45
- primary: background("#primary-switch"),
46
- success: background("#success-switch"),
47
- surface: background(".dms-card"),
48
- logosLoaded:
49
- images.length === 2 &&
50
- images.every((image) => image.complete && image.naturalWidth > 0),
51
- logos: images.map((image) => new URL(image.src).pathname),
52
- };
53
- }
54
-
55
- function checkLogos(result, mode) {
56
- assert.ok(result.logosLoaded, "logos loaded");
57
- const logoRoot = theme === "custom" ? "/brand" : "/images/antelope-logo";
58
- assert.deepEqual(result.logos, [
59
- `${logoRoot}/${mode}.svg`,
60
- `${logoRoot}/icon.svg`,
61
- ]);
62
- }
63
-
64
- function checkTheme(mode) {
65
- const result = evaluate(`(${inspectTheme.toString()})()`);
66
- const isCustom = theme === "custom";
67
- assert.ok(result.radius.endsWith("rem"), "radius unit");
68
- assert.equal(
69
- Number.parseFloat(result.radius),
70
- isCustom ? 0.5 : 0.25,
71
- "radius",
72
- );
73
- assert.ok(result.font.includes(isCustom ? "Georgia" : "Geist"), "font");
74
- assert.ok(
75
- result.config.includes(isCustom ? "example" : "dms"),
76
- "layer precedence",
77
- );
78
- assert.equal(result.button, result.colors[0], "primary action");
79
- assert.equal(result.primary, result.colors[1], "primary switch shade");
80
- assert.equal(
81
- result.success,
82
- result.colors[2],
83
- "success switch semantic color",
84
- );
85
- const darkSurface = isCustom ? "rgb(36, 21, 54)" : "rgb(16, 17, 25)";
86
- assert.equal(
87
- result.surface,
88
- mode === "dark" ? darkSurface : "rgb(255, 255, 255)",
89
- );
90
- assert.equal(
91
- result.accent,
92
- result.accentPalette[Number(mode === "dark")],
93
- "glow accent",
94
- );
95
- checkLogos(result, mode);
96
- console.log(`${theme}/${mode}: tokens, switches and logos passed`);
97
- }
98
-
99
- function checkMode(mode) {
100
- const modeCondition = `document.documentElement.classList.contains('dark') === ${mode === "dark"}`;
101
- if (!evaluate(modeCondition)) browser("click", "#mode");
102
- browser("wait", "--fn", modeCondition);
103
- browser("wait", transitionWait);
104
- checkTheme(mode);
105
- browser("click", "#primary-switch");
106
- browser(
107
- "wait",
108
- "--fn",
109
- 'document.querySelector("#primary-switch").getAttribute("aria-checked") === "false"',
110
- );
111
- browser("click", "#primary-switch");
112
- browser("wait", transitionWait);
113
- checkTheme(mode);
114
- if (!screenshots) return;
115
- mkdirSync(screenshots, { recursive: true });
116
- browser("screenshot", resolve(screenshots, `${theme}-${mode}.png`));
117
- }
118
-
119
- try {
120
- browser("open", url);
121
- browser("set", "viewport", "1280", "900", "2");
122
- browser(
123
- "wait",
124
- "--fn",
125
- 'document.querySelector("main")?.dataset.ready === "true"',
126
- );
127
- for (const mode of ["light", "dark"]) checkMode(mode);
128
- } finally {
129
- browser("close");
130
- }