@databehave/admin 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/LICENSE +21 -0
  3. package/README.md +39 -2
  4. package/assets/ui.css +1 -0
  5. package/assets/ui.html +13 -0
  6. package/assets/ui.js +233 -0
  7. package/dist/admin-plugin.d.ts +23 -0
  8. package/dist/admin-plugin.d.ts.map +1 -0
  9. package/dist/admin-plugin.js +71 -0
  10. package/dist/admin-plugin.js.map +1 -0
  11. package/dist/admin-routes.d.ts +22 -0
  12. package/dist/admin-routes.d.ts.map +1 -0
  13. package/dist/admin-routes.js +316 -0
  14. package/dist/admin-routes.js.map +1 -0
  15. package/dist/admin-types.d.ts +98 -0
  16. package/dist/admin-types.d.ts.map +1 -0
  17. package/dist/admin-types.js +2 -0
  18. package/dist/admin-types.js.map +1 -0
  19. package/dist/banner.d.ts +10 -0
  20. package/dist/banner.d.ts.map +1 -0
  21. package/dist/banner.js +5 -0
  22. package/dist/banner.js.map +1 -0
  23. package/dist/fault-plugin.d.ts +29 -0
  24. package/dist/fault-plugin.d.ts.map +1 -0
  25. package/dist/fault-plugin.js +32 -0
  26. package/dist/fault-plugin.js.map +1 -0
  27. package/dist/header-parser.d.ts +14 -0
  28. package/dist/header-parser.d.ts.map +1 -0
  29. package/dist/header-parser.js +171 -0
  30. package/dist/header-parser.js.map +1 -0
  31. package/dist/index.d.ts +10 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +5 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/inject.d.ts +35 -0
  36. package/dist/inject.d.ts.map +1 -0
  37. package/dist/inject.js +155 -0
  38. package/dist/inject.js.map +1 -0
  39. package/dist/open-browser-plugin.d.ts +6 -0
  40. package/dist/open-browser-plugin.d.ts.map +1 -0
  41. package/dist/open-browser-plugin.js +32 -0
  42. package/dist/open-browser-plugin.js.map +1 -0
  43. package/dist/overrides-store.d.ts +21 -0
  44. package/dist/overrides-store.d.ts.map +1 -0
  45. package/dist/overrides-store.js +114 -0
  46. package/dist/overrides-store.js.map +1 -0
  47. package/dist/resolve-cors.d.ts +6 -0
  48. package/dist/resolve-cors.d.ts.map +1 -0
  49. package/dist/resolve-cors.js +39 -0
  50. package/dist/resolve-cors.js.map +1 -0
  51. package/dist/scenarios-store.d.ts +8 -0
  52. package/dist/scenarios-store.d.ts.map +1 -0
  53. package/dist/scenarios-store.js +136 -0
  54. package/dist/scenarios-store.js.map +1 -0
  55. package/dist/scenarios.d.ts +9 -0
  56. package/dist/scenarios.d.ts.map +1 -0
  57. package/dist/scenarios.js +2 -0
  58. package/dist/scenarios.js.map +1 -0
  59. package/dist/validation.d.ts +17 -0
  60. package/dist/validation.d.ts.map +1 -0
  61. package/dist/validation.js +169 -0
  62. package/dist/validation.js.map +1 -0
  63. package/package.json +52 -3
@@ -0,0 +1,39 @@
1
+ const wildcard = (bind, cors) => cors === 'any' || (cors === 'auto' && bind === 'loopback-only');
2
+ /** Origin-less local clients are allowed; a present Origin must be a valid HTTP origin. */
3
+ export const isAdminOriginAllowed = (bind, cors, origin, requestUrl) => {
4
+ if (origin === undefined)
5
+ return true;
6
+ try {
7
+ const parsed = new URL(origin);
8
+ if (!['http:', 'https:'].includes(parsed.protocol) || parsed.origin !== origin)
9
+ return false;
10
+ }
11
+ catch {
12
+ return false;
13
+ }
14
+ if (origin === new URL(requestUrl).origin || wildcard(bind, cors))
15
+ return true;
16
+ if (typeof cors === 'object')
17
+ return typeof cors.origin === 'string' ? cors.origin === origin : cors.origin.includes(origin);
18
+ return false;
19
+ };
20
+ /** Admin owns response sharing; allowlists reflect exactly one permitted request origin. */
21
+ export const resolveAdminCors = (bind, cors, requestOrigin = '') => {
22
+ let origin;
23
+ if (wildcard(bind, cors))
24
+ origin = '*';
25
+ else if (typeof cors === 'object') {
26
+ const allowed = typeof cors.origin === 'string' ? [cors.origin] : cors.origin;
27
+ if (allowed.includes(requestOrigin))
28
+ origin = requestOrigin;
29
+ }
30
+ if (!origin)
31
+ return {};
32
+ return {
33
+ 'access-control-allow-origin': origin,
34
+ 'access-control-allow-methods': 'GET,POST,DELETE,OPTIONS',
35
+ 'access-control-allow-headers': 'content-type',
36
+ vary: 'Origin',
37
+ };
38
+ };
39
+ //# sourceMappingURL=resolve-cors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-cors.js","sourceRoot":"","sources":["../src/resolve-cors.ts"],"names":[],"mappings":"AAEA,MAAM,QAAQ,GAAG,CAAC,IAA6B,EAAE,IAAmB,EAAW,EAAE,CAC/E,IAAI,KAAK,KAAK,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,eAAe,CAAC,CAAA;AAEjE,2FAA2F;AAC3F,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,IAA6B,EAAE,IAAmB,EAAE,MAA0B,EAAE,UAAkB,EACzF,EAAE;IACX,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,IAAI,CAAA;IACrC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAA;QAC9B,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM;YAAE,OAAO,KAAK,CAAA;IAC9F,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,KAAK,CAAA;IAAC,CAAC;IACxB,IAAI,MAAM,KAAK,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IAC9E,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IAC5H,OAAO,KAAK,CAAA;AACd,CAAC,CAAA;AAED,4FAA4F;AAC5F,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,IAA6B,EAAE,IAAmB,EAAE,aAAa,GAAG,EAAE,EAC9C,EAAE;IAC1B,IAAI,MAA0B,CAAA;IAC9B,IAAI,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;QAAE,MAAM,GAAG,GAAG,CAAA;SACjC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,OAAO,GAAG,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAA;QAC7E,IAAI,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;YAAE,MAAM,GAAG,aAAa,CAAA;IAC7D,CAAC;IACD,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAA;IACtB,OAAO;QACL,6BAA6B,EAAE,MAAM;QACrC,8BAA8B,EAAE,yBAAyB;QACzD,8BAA8B,EAAE,cAAc;QAC9C,IAAI,EAAE,QAAQ;KACf,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,8 @@
1
+ import type { ScenariosStore } from './scenarios.js';
2
+ /** Filesystem scope explicitly chosen by application composition. */
3
+ export interface FileScenariosStoreOptions {
4
+ readonly dir: string;
5
+ }
6
+ /** Create a file adapter without reading, writing, or acquiring resources until called. */
7
+ export declare const fileScenariosStore: (opts: FileScenariosStoreOptions) => ScenariosStore;
8
+ //# sourceMappingURL=scenarios-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenarios-store.d.ts","sourceRoot":"","sources":["../src/scenarios-store.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEpD,qEAAqE;AACrE,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AAWD,2FAA2F;AAC3F,eAAO,MAAM,kBAAkB,GAC7B,MAAM,yBAAyB,KAC9B,cAuFF,CAAA"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * File-backed scenarios registry.
3
+ *
4
+ * A *scenario* is a named JSON snapshot of one or more sticky
5
+ * overrides. Scenarios live as `<name>.json` files inside the
6
+ * explicitly configured directory. Names are
7
+ * sanitised — only `[A-Za-z0-9_-]`, max 64 chars — so they map
8
+ * directly to safe filenames and round-trip through HTTP path
9
+ * segments without escaping.
10
+ *
11
+ * The directory is opt-in: a missing dir yields an empty list rather
12
+ * than throwing. The first save creates the dir.
13
+ *
14
+ * Writes are atomic: write to `<name>.json.<tmp>` then rename, so a
15
+ * partial write never produces a half-parsed file.
16
+ */
17
+ import { randomBytes } from 'node:crypto';
18
+ import { mkdir, open, readFile, readdir, rename, stat, unlink } from 'node:fs/promises';
19
+ import { join } from 'node:path';
20
+ import { validateOverrides, validateScenario, isValidScenarioName, ScenarioValidationError } from './validation.js';
21
+ const isENOENT = (err) => typeof err === 'object' && err !== null && err.code === 'ENOENT';
22
+ const parseScenario = (text, name) => {
23
+ let raw;
24
+ try {
25
+ raw = JSON.parse(text);
26
+ }
27
+ catch {
28
+ throw new ScenarioValidationError('Malformed scenario JSON');
29
+ }
30
+ return validateScenario(raw, name);
31
+ };
32
+ /** Create a file adapter without reading, writing, or acquiring resources until called. */
33
+ export const fileScenariosStore = (opts) => {
34
+ const { dir } = opts;
35
+ const filePath = (name) => join(dir, `${name}.json`);
36
+ const list = async () => {
37
+ let entries;
38
+ try {
39
+ entries = await readdir(dir);
40
+ }
41
+ catch (err) {
42
+ if (isENOENT(err))
43
+ return [];
44
+ throw err;
45
+ }
46
+ const out = [];
47
+ for (const entry of entries) {
48
+ if (!entry.endsWith('.json'))
49
+ continue;
50
+ const name = entry.slice(0, -5);
51
+ if (!isValidScenarioName(name))
52
+ continue;
53
+ try {
54
+ const full = join(dir, entry);
55
+ const [text, st] = await Promise.all([readFile(full, 'utf8'), stat(full)]);
56
+ const parsed = parseScenario(text, name);
57
+ out.push({
58
+ name,
59
+ count: parsed.overrides.length,
60
+ created: parsed.created ?? st.mtime.toISOString(),
61
+ });
62
+ }
63
+ catch {
64
+ // skip unreadable / malformed files; the UI still works.
65
+ }
66
+ }
67
+ out.sort((a, b) => a.name.localeCompare(b.name));
68
+ return out;
69
+ };
70
+ const get = async (name) => {
71
+ if (!isValidScenarioName(name))
72
+ return null;
73
+ try {
74
+ const text = await readFile(filePath(name), 'utf8');
75
+ const parsed = parseScenario(text, name);
76
+ return parsed;
77
+ }
78
+ catch (err) {
79
+ if (isENOENT(err))
80
+ return null;
81
+ throw err;
82
+ }
83
+ };
84
+ const save = async (name, overrides) => {
85
+ if (!isValidScenarioName(name)) {
86
+ throw new Error(`@databehave/admin: invalid scenario name: ${JSON.stringify(name)}`);
87
+ }
88
+ const validated = validateOverrides(overrides);
89
+ const scenario = {
90
+ version: 1,
91
+ name,
92
+ overrides: validated,
93
+ created: new Date().toISOString(),
94
+ };
95
+ const serialized = JSON.stringify(scenario, null, 2);
96
+ await mkdir(dir, { recursive: true });
97
+ const final = filePath(name);
98
+ const tmp = `${final}.${randomBytes(6).toString('hex')}.tmp`;
99
+ const handle = await open(tmp, 'wx');
100
+ try {
101
+ try {
102
+ await handle.writeFile(serialized, 'utf8');
103
+ }
104
+ finally {
105
+ await handle.close();
106
+ }
107
+ await rename(tmp, final);
108
+ }
109
+ catch (error) {
110
+ try {
111
+ await unlink(tmp);
112
+ }
113
+ catch (cleanupError) {
114
+ if (!isENOENT(cleanupError))
115
+ throw new AggregateError([error, cleanupError], 'Scenario save and temporary cleanup failed');
116
+ }
117
+ throw error;
118
+ }
119
+ return scenario;
120
+ };
121
+ const remove = async (name) => {
122
+ if (!isValidScenarioName(name))
123
+ return false;
124
+ try {
125
+ await unlink(filePath(name));
126
+ return true;
127
+ }
128
+ catch (err) {
129
+ if (isENOENT(err))
130
+ return false;
131
+ throw err;
132
+ }
133
+ };
134
+ return { list, get, save, remove };
135
+ };
136
+ //# sourceMappingURL=scenarios-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenarios-store.js","sourceRoot":"","sources":["../src/scenarios-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Scenario, ScenarioSummary, StickyOverride } from './admin-types.js';
2
+ /** Storage-neutral persistence supplied explicitly to admin. Implementations own I/O and atomic saves. */
3
+ export interface ScenariosStore {
4
+ list(): Promise<ScenarioSummary[]>;
5
+ get(name: string): Promise<Scenario | null>;
6
+ save(name: string, overrides: readonly StickyOverride[]): Promise<Scenario>;
7
+ remove(name: string): Promise<boolean>;
8
+ }
9
+ //# sourceMappingURL=scenarios.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenarios.d.ts","sourceRoot":"","sources":["../src/scenarios.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEjF,0GAA0G;AAC1G,MAAM,WAAW,cAAc;IAC7B,IAAI,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAAA;IAClC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAA;IAC3C,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,cAAc,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC3E,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CACvC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=scenarios.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenarios.js","sourceRoot":"","sources":["../src/scenarios.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ import type { ErrorMode, OverrideMatcher, StickyOverride, Scenario } from './admin-types.js';
2
+ export declare const isPlainObject: (v: unknown) => v is Record<string, unknown>;
3
+ export declare const validateMode: (raw: unknown) => [ErrorMode | null, string | null];
4
+ export declare const validateMatcher: (raw: unknown) => [OverrideMatcher | null, string | null];
5
+ /** Invalid external scenario or override data. No state or file has changed. */
6
+ export declare class ScenarioValidationError extends Error {
7
+ readonly name = "ScenarioValidationError";
8
+ }
9
+ /** Complete validation shared by HTTP requests, disk reads and atomic replacement. */
10
+ export declare const validateOverrides: (raw: unknown) => readonly StickyOverride[];
11
+ /** Versionless legacy scenarios and version 1 share the validated override format. */
12
+ export declare const validateScenarioVersion: (version: unknown) => void;
13
+ /** Names accepted by all scenario endpoints and the file adapter. */
14
+ export declare const isValidScenarioName: (name: string) => boolean;
15
+ /** Validate a complete provider or legacy disk result before it can become live state. */
16
+ export declare const validateScenario: (raw: unknown, name: string) => Scenario;
17
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAE5F,eAAO,MAAM,aAAa,GAAI,GAAG,OAAO,KAAG,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CACZ,CAAA;AAE1D,eAAO,MAAM,YAAY,GAAI,KAAK,OAAO,KAAG,CAAC,SAAS,GAAG,IAAI,EAAE,MAAM,GAAG,IAAI,CAqF3E,CAAA;AAED,eAAO,MAAM,eAAe,GAC1B,KAAK,OAAO,KACX,CAAC,eAAe,GAAG,IAAI,EAAE,MAAM,GAAG,IAAI,CAkCxC,CAAA;AAED,gFAAgF;AAChF,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,SAAkB,IAAI,6BAA4B;CACnD;AAED,sFAAsF;AACtF,eAAO,MAAM,iBAAiB,GAAI,KAAK,OAAO,KAAG,SAAS,cAAc,EAgBvE,CAAA;AAED,sFAAsF;AACtF,eAAO,MAAM,uBAAuB,GAAI,SAAS,OAAO,KAAG,IAI1D,CAAA;AAED,qEAAqE;AACrE,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,KAAG,OAA6C,CAAA;AAEhG,0FAA0F;AAC1F,eAAO,MAAM,gBAAgB,GAAI,KAAK,OAAO,EAAE,MAAM,MAAM,KAAG,QAQ7D,CAAA"}
@@ -0,0 +1,169 @@
1
+ export const isPlainObject = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
2
+ export const validateMode = (raw) => {
3
+ if (!isPlainObject(raw) || typeof raw.kind !== 'string') {
4
+ return [null, 'mode.kind must be a string'];
5
+ }
6
+ switch (raw.kind) {
7
+ case 'http-status':
8
+ if (typeof raw.status !== 'number' || !Number.isInteger(raw.status) || raw.status < 200 || raw.status > 599)
9
+ return [null, 'http-status.status must be number'];
10
+ return [{ kind: 'http-status', status: raw.status }, null];
11
+ case 'business-failure': {
12
+ if (typeof raw.message !== 'string')
13
+ return [null, 'business-failure.message must be string'];
14
+ const mode = { kind: 'business-failure', message: raw.message };
15
+ if (raw.extra !== undefined) {
16
+ if (!isPlainObject(raw.extra))
17
+ return [null, 'business-failure.extra must be a plain object'];
18
+ mode.extra = raw.extra;
19
+ }
20
+ return [mode, null];
21
+ }
22
+ case 'custom-body': {
23
+ if (!('body' in raw))
24
+ return [null, 'custom-body.body is required'];
25
+ const mode = { kind: 'custom-body', body: raw.body };
26
+ if (raw.status !== undefined) {
27
+ if (typeof raw.status !== 'number' || !Number.isInteger(raw.status) || raw.status < 200 || raw.status > 599)
28
+ return [null, 'custom-body.status must be number'];
29
+ mode.status = raw.status;
30
+ }
31
+ if (raw.contentType !== undefined) {
32
+ if (typeof raw.contentType !== 'string')
33
+ return [null, 'custom-body.contentType must be string'];
34
+ mode.contentType = raw.contentType;
35
+ }
36
+ return [mode, null];
37
+ }
38
+ case 'empty-body': {
39
+ const mode = { kind: 'empty-body' };
40
+ if (raw.status !== undefined) {
41
+ if (typeof raw.status !== 'number' || !Number.isInteger(raw.status) || raw.status < 200 || raw.status > 599)
42
+ return [null, 'empty-body.status must be number'];
43
+ mode.status = raw.status;
44
+ }
45
+ return [mode, null];
46
+ }
47
+ case 'malformed-json': {
48
+ const mode = { kind: 'malformed-json' };
49
+ if (raw.status !== undefined) {
50
+ if (typeof raw.status !== 'number' || !Number.isInteger(raw.status) || raw.status < 200 || raw.status > 599)
51
+ return [null, 'malformed-json.status must be number'];
52
+ mode.status = raw.status;
53
+ }
54
+ return [mode, null];
55
+ }
56
+ case 'delay': {
57
+ if (typeof raw.ms !== 'number' || !Number.isFinite(raw.ms) || raw.ms < 0 || raw.ms > 2_147_483_647)
58
+ return [null, 'delay.ms must be a non-negative number'];
59
+ if (raw.then === undefined)
60
+ return [{ kind: 'delay', ms: raw.ms }, null];
61
+ const [inner, err] = validateMode(raw.then);
62
+ if (!inner)
63
+ return [null, `delay.then: ${err}`];
64
+ if (inner.kind === 'delay' ||
65
+ inner.kind === 'hang' ||
66
+ inner.kind === 'destroy') {
67
+ return [null, `delay.then cannot be ${inner.kind}`];
68
+ }
69
+ return [
70
+ {
71
+ kind: 'delay',
72
+ ms: raw.ms,
73
+ then: inner,
74
+ },
75
+ null,
76
+ ];
77
+ }
78
+ case 'hang':
79
+ return [{ kind: 'hang' }, null];
80
+ case 'destroy':
81
+ return [{ kind: 'destroy' }, null];
82
+ default:
83
+ return [null, `unknown mode.kind: ${String(raw.kind)}`];
84
+ }
85
+ };
86
+ export const validateMatcher = (raw) => {
87
+ if (!isPlainObject(raw) || typeof raw.kind !== 'string') {
88
+ return [null, 'matcher.kind must be a string'];
89
+ }
90
+ switch (raw.kind) {
91
+ case 'exact':
92
+ if (typeof raw.method !== 'string' || !/^[A-Za-z]+$/.test(raw.method))
93
+ return [null, 'matcher.method must be string'];
94
+ if (typeof raw.path !== 'string' || !raw.path.startsWith('/'))
95
+ return [null, 'matcher.path must start with "/"'];
96
+ return [{ kind: 'exact', method: raw.method, path: raw.path }, null];
97
+ case 'path':
98
+ if (typeof raw.path !== 'string' || !raw.path.startsWith('/'))
99
+ return [null, 'matcher.path must start with "/"'];
100
+ return [{ kind: 'path', path: raw.path }, null];
101
+ case 'global': {
102
+ if (raw.methods === undefined)
103
+ return [{ kind: 'global' }, null];
104
+ if (!Array.isArray(raw.methods))
105
+ return [null, 'matcher.methods must be an array of strings'];
106
+ const methods = [];
107
+ for (const m of raw.methods) {
108
+ if (typeof m !== 'string')
109
+ return [null, 'matcher.methods must be an array of strings'];
110
+ const trimmed = m.trim();
111
+ if (trimmed.length === 0)
112
+ return [null, 'matcher.methods entries must be non-empty'];
113
+ methods.push(trimmed.toUpperCase());
114
+ }
115
+ if (methods.length === 0)
116
+ return [{ kind: 'global' }, null];
117
+ return [{ kind: 'global', methods }, null];
118
+ }
119
+ default:
120
+ return [null, `unknown matcher.kind: ${String(raw.kind)}`];
121
+ }
122
+ };
123
+ /** Invalid external scenario or override data. No state or file has changed. */
124
+ export class ScenarioValidationError extends Error {
125
+ name = 'ScenarioValidationError';
126
+ }
127
+ /** Complete validation shared by HTTP requests, disk reads and atomic replacement. */
128
+ export const validateOverrides = (raw) => {
129
+ if (!Array.isArray(raw))
130
+ throw new ScenarioValidationError('overrides must be an array');
131
+ return raw.map((entry, index) => {
132
+ if (!isPlainObject(entry))
133
+ throw new ScenarioValidationError(`overrides[${index}] must be an object`);
134
+ const [matcher, matcherError] = validateMatcher(entry.matcher);
135
+ const [mode, modeError] = validateMode(entry.mode);
136
+ if (!matcher || !mode)
137
+ throw new ScenarioValidationError(`overrides[${index}]: ${matcherError ?? modeError}`);
138
+ if (typeof entry.id !== 'string' || typeof entry.createdAt !== 'string') {
139
+ throw new ScenarioValidationError(`overrides[${index}] requires id and createdAt strings`);
140
+ }
141
+ if (entry.description !== undefined && typeof entry.description !== 'string') {
142
+ throw new ScenarioValidationError(`overrides[${index}].description must be a string`);
143
+ }
144
+ return { id: entry.id, createdAt: entry.createdAt, matcher, mode,
145
+ ...(entry.description !== undefined ? { description: entry.description } : {}) };
146
+ });
147
+ };
148
+ /** Versionless legacy scenarios and version 1 share the validated override format. */
149
+ export const validateScenarioVersion = (version) => {
150
+ if (version !== undefined && version !== 1) {
151
+ throw new ScenarioValidationError(`Unsupported scenario version: ${String(version)}`);
152
+ }
153
+ };
154
+ /** Names accepted by all scenario endpoints and the file adapter. */
155
+ export const isValidScenarioName = (name) => /^[A-Za-z0-9_-]{1,64}$/.test(name);
156
+ /** Validate a complete provider or legacy disk result before it can become live state. */
157
+ export const validateScenario = (raw, name) => {
158
+ if (!isPlainObject(raw))
159
+ throw new ScenarioValidationError('Scenario must be an object');
160
+ validateScenarioVersion(raw.version);
161
+ if (raw.name !== undefined && typeof raw.name !== 'string')
162
+ throw new ScenarioValidationError('Scenario name must be a string');
163
+ if (raw.created !== undefined && typeof raw.created !== 'string')
164
+ throw new ScenarioValidationError('Scenario created must be a string');
165
+ return { name, overrides: validateOverrides(raw.overrides),
166
+ ...(raw.created !== undefined ? { created: raw.created } : {}),
167
+ ...(raw.version === 1 ? { version: 1 } : {}) };
168
+ };
169
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAU,EAAgC,EAAE,CACxE,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;AAE1D,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAY,EAAqC,EAAE;IAC9E,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACxD,OAAO,CAAC,IAAI,EAAE,4BAA4B,CAAC,CAAA;IAC7C,CAAC;IACD,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;QACjB,KAAK,aAAa;YAChB,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG;gBACzG,OAAO,CAAC,IAAI,EAAE,mCAAmC,CAAC,CAAA;YACpD,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAA;QAC5D,KAAK,kBAAkB,CAAC,CAAC,CAAC;YACxB,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ;gBACjC,OAAO,CAAC,IAAI,EAAE,yCAAyC,CAAC,CAAA;YAC1D,MAAM,IAAI,GAAc,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAA;YAC1E,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBAC5B,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC;oBAC3B,OAAO,CAAC,IAAI,EAAE,+CAA+C,CAAC,CAC/D;gBAAC,IAA4C,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAA;YAClE,CAAC;YACD,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QACrB,CAAC;QACD,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,IAAI,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC;gBAAE,OAAO,CAAC,IAAI,EAAE,8BAA8B,CAAC,CAAA;YACnE,MAAM,IAAI,GAAc,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAA;YAC/D,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC7B,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG;oBACzG,OAAO,CAAC,IAAI,EAAE,mCAAmC,CAAC,CACnD;gBAAC,IAA4B,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAA;YACpD,CAAC;YACD,IAAI,GAAG,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;gBAClC,IAAI,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ;oBACrC,OAAO,CAAC,IAAI,EAAE,wCAAwC,CAAC,CACxD;gBAAC,IAAiC,CAAC,WAAW,GAAG,GAAG,CAAC,WAAW,CAAA;YACnE,CAAC;YACD,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QACrB,CAAC;QACD,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,MAAM,IAAI,GAAc,EAAE,IAAI,EAAE,YAAY,EAAE,CAAA;YAC9C,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC7B,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG;oBACzG,OAAO,CAAC,IAAI,EAAE,kCAAkC,CAAC,CAClD;gBAAC,IAA4B,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAA;YACpD,CAAC;YACD,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QACrB,CAAC;QACD,KAAK,gBAAgB,CAAC,CAAC,CAAC;YACtB,MAAM,IAAI,GAAc,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAA;YAClD,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC7B,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG;oBACzG,OAAO,CAAC,IAAI,EAAE,sCAAsC,CAAC,CACtD;gBAAC,IAA4B,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAA;YACpD,CAAC;YACD,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QACrB,CAAC;QACD,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,IAAI,OAAO,GAAG,CAAC,EAAE,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC,EAAE,GAAG,aAAa;gBAChG,OAAO,CAAC,IAAI,EAAE,wCAAwC,CAAC,CAAA;YACzD,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS;gBAAE,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,CAAA;YACxE,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YAC3C,IAAI,CAAC,KAAK;gBAAE,OAAO,CAAC,IAAI,EAAE,eAAe,GAAG,EAAE,CAAC,CAAA;YAC/C,IACE,KAAK,CAAC,IAAI,KAAK,OAAO;gBACtB,KAAK,CAAC,IAAI,KAAK,MAAM;gBACrB,KAAK,CAAC,IAAI,KAAK,SAAS,EACxB,CAAC;gBACD,OAAO,CAAC,IAAI,EAAE,wBAAwB,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;YACrD,CAAC;YACD,OAAO;gBACL;oBACE,IAAI,EAAE,OAAO;oBACb,EAAE,EAAE,GAAG,CAAC,EAAE;oBACV,IAAI,EAAE,KAGL;iBACF;gBACD,IAAI;aACL,CAAA;QACH,CAAC;QACD,KAAK,MAAM;YACT,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,CAAA;QACjC,KAAK,SAAS;YACZ,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,IAAI,CAAC,CAAA;QACpC;YACE,OAAO,CAAC,IAAI,EAAE,sBAAsB,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAC3D,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,GAAY,EAC6B,EAAE;IAC3C,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACxD,OAAO,CAAC,IAAI,EAAE,+BAA+B,CAAC,CAAA;IAChD,CAAC;IACD,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;QACjB,KAAK,OAAO;YACV,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;gBACnE,OAAO,CAAC,IAAI,EAAE,+BAA+B,CAAC,CAAA;YAChD,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBAC3D,OAAO,CAAC,IAAI,EAAE,kCAAkC,CAAC,CAAA;YACnD,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,CAAA;QACtE,KAAK,MAAM;YACT,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBAC3D,OAAO,CAAC,IAAI,EAAE,kCAAkC,CAAC,CAAA;YACnD,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,CAAA;QACjD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS;gBAAE,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,IAAI,CAAC,CAAA;YAChE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;gBAC7B,OAAO,CAAC,IAAI,EAAE,6CAA6C,CAAC,CAAA;YAC9D,MAAM,OAAO,GAAa,EAAE,CAAA;YAC5B,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;gBAC5B,IAAI,OAAO,CAAC,KAAK,QAAQ;oBACvB,OAAO,CAAC,IAAI,EAAE,6CAA6C,CAAC,CAAA;gBAC9D,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;gBACxB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;oBACtB,OAAO,CAAC,IAAI,EAAE,2CAA2C,CAAC,CAAA;gBAC5D,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAA;YACrC,CAAC;YACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,IAAI,CAAC,CAAA;YAC3D,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,IAAI,CAAC,CAAA;QAC5C,CAAC;QACD;YACE,OAAO,CAAC,IAAI,EAAE,yBAAyB,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAC9D,CAAC;AACH,CAAC,CAAA;AAED,gFAAgF;AAChF,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAC9B,IAAI,GAAG,yBAAyB,CAAA;CACnD;AAED,sFAAsF;AACtF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,GAAY,EAA6B,EAAE;IAC3E,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,uBAAuB,CAAC,4BAA4B,CAAC,CAAA;IACxF,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,KAAc,EAAE,KAAK,EAAE,EAAE;QACvC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC;YAAE,MAAM,IAAI,uBAAuB,CAAC,aAAa,KAAK,qBAAqB,CAAC,CAAA;QACrG,MAAM,CAAC,OAAO,EAAE,YAAY,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAC9D,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAClD,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,uBAAuB,CAAC,aAAa,KAAK,MAAM,YAAY,IAAI,SAAS,EAAE,CAAC,CAAA;QAC7G,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;YACxE,MAAM,IAAI,uBAAuB,CAAC,aAAa,KAAK,qCAAqC,CAAC,CAAA;QAC5F,CAAC;QACD,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;YAC7E,MAAM,IAAI,uBAAuB,CAAC,aAAa,KAAK,gCAAgC,CAAC,CAAA;QACvF,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI;YAC9D,GAAG,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAA;IACpF,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,sFAAsF;AACtF,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,OAAgB,EAAQ,EAAE;IAChE,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,uBAAuB,CAAC,iCAAiC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IACvF,CAAC;AACH,CAAC,CAAA;AAED,qEAAqE;AACrE,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAEhG,0FAA0F;AAC1F,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,GAAY,EAAE,IAAY,EAAY,EAAE;IACvE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,uBAAuB,CAAC,4BAA4B,CAAC,CAAA;IACxF,uBAAuB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACpC,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ;QAAE,MAAM,IAAI,uBAAuB,CAAC,gCAAgC,CAAC,CAAA;IAC/H,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ;QAAE,MAAM,IAAI,uBAAuB,CAAC,mCAAmC,CAAC,CAAA;IACxI,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC;QACxD,GAAG,CAAC,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,GAAG,CAAC,GAAG,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAA;AAClD,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,55 @@
1
1
  {
2
2
  "name": "@databehave/admin",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.2.0",
4
+ "description": "Explicit fault injection and Web Components admin plugins for Databehave",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ },
14
+ "./assets/*": "./assets/*"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "assets",
19
+ "README.md",
20
+ "LICENSE",
21
+ "CHANGELOG.md"
22
+ ],
23
+ "engines": {
24
+ "node": "^24.22.1 || ^26.12.1"
25
+ },
26
+ "dependencies": {
27
+ "@databehave/core": "0.2.0",
28
+ "@databehave/server": "0.3.0"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^24.19.2",
32
+ "@vitest/coverage-v8": "4.1.12",
33
+ "typescript": "^6.0.3",
34
+ "vite": "^6.4.5",
35
+ "vitest": "^4.1.12"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public",
39
+ "provenance": true
40
+ },
41
+ "author": "ochairo",
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "git+https://github.com/ochairo/databehave.git",
45
+ "directory": "packages/admin"
46
+ },
47
+ "scripts": {
48
+ "build:admin": "vite build --config vite.admin.config.ts && mv assets/ui-shell.html assets/ui.html",
49
+ "build": "pnpm build:admin && tsc -p tsconfig.build.json",
50
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.build.json --noEmit && tsc -p tsconfig.ui.json --noEmit",
51
+ "test": "vitest run --coverage",
52
+ "test:no-coverage": "vitest run",
53
+ "clean": "rm -rf dist assets coverage"
54
+ }
6
55
  }