@shipeasy/devtools-core 1.0.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 (55) hide show
  1. package/LICENSE +40 -0
  2. package/README.md +19 -0
  3. package/dist/api.d.mts +143 -0
  4. package/dist/api.d.ts +143 -0
  5. package/dist/api.js +10 -0
  6. package/dist/api.mjs +10 -0
  7. package/dist/auth.d.mts +57 -0
  8. package/dist/auth.d.ts +57 -0
  9. package/dist/auth.js +12 -0
  10. package/dist/auth.mjs +12 -0
  11. package/dist/chunk-2B75JLTX.js +25 -0
  12. package/dist/chunk-5VQLXGNR.mjs +101 -0
  13. package/dist/chunk-6SU5REDK.mjs +2848 -0
  14. package/dist/chunk-7NO55TFC.mjs +25 -0
  15. package/dist/chunk-GUTBZI2O.js +2848 -0
  16. package/dist/chunk-I2KLQ2HA.js +22 -0
  17. package/dist/chunk-KPO3R7ND.js +28 -0
  18. package/dist/chunk-LCRTLHGL.js +101 -0
  19. package/dist/chunk-LZDNBMH6.mjs +1394 -0
  20. package/dist/chunk-MK56AKZR.js +178 -0
  21. package/dist/chunk-RANNOC72.js +72 -0
  22. package/dist/chunk-RH6X24HG.mjs +28 -0
  23. package/dist/chunk-U5DDQYSF.mjs +22 -0
  24. package/dist/chunk-VHYOR3XA.mjs +178 -0
  25. package/dist/chunk-WP2TWHG3.mjs +72 -0
  26. package/dist/chunk-YQHCUZGP.js +1394 -0
  27. package/dist/feedback-state.d.mts +29 -0
  28. package/dist/feedback-state.d.ts +29 -0
  29. package/dist/feedback-state.js +9 -0
  30. package/dist/feedback-state.mjs +9 -0
  31. package/dist/forms.d.mts +95 -0
  32. package/dist/forms.d.ts +95 -0
  33. package/dist/forms.js +21 -0
  34. package/dist/forms.mjs +21 -0
  35. package/dist/gate-flow.d.mts +41 -0
  36. package/dist/gate-flow.d.ts +41 -0
  37. package/dist/gate-flow.js +17 -0
  38. package/dist/gate-flow.mjs +17 -0
  39. package/dist/index.d.mts +10 -0
  40. package/dist/index.d.ts +10 -0
  41. package/dist/index.js +86 -0
  42. package/dist/index.mjs +86 -0
  43. package/dist/public-report.d.mts +56 -0
  44. package/dist/public-report.d.ts +56 -0
  45. package/dist/public-report.js +12 -0
  46. package/dist/public-report.mjs +12 -0
  47. package/dist/self-report.d.mts +25 -0
  48. package/dist/self-report.d.ts +25 -0
  49. package/dist/self-report.js +73 -0
  50. package/dist/self-report.mjs +73 -0
  51. package/dist/types-D0sroUDD.d.mts +278 -0
  52. package/dist/types-D0sroUDD.d.ts +278 -0
  53. package/dist/zod.gen-DTKpgw-T.d.mts +64 -0
  54. package/dist/zod.gen-DTKpgw-T.d.ts +64 -0
  55. package/package.json +58 -0
@@ -0,0 +1,56 @@
1
+ /** The project has not opted into public ticket creation (or the client key
2
+ * lacks the `tickets:public_create` scope). */
3
+ declare class PublicTicketsDisabled extends Error {
4
+ readonly status = 403;
5
+ constructor(message: string);
6
+ }
7
+ interface PublicBugInput {
8
+ /** One-line summary (required, ≤200 chars). */
9
+ title: string;
10
+ /** What happened — the actual result / error text (≤8000 chars). */
11
+ error?: string;
12
+ /** Freeform description / steps (≤8000 chars). */
13
+ description?: string;
14
+ /** Optional contact email for follow-up. */
15
+ reporterEmail?: string;
16
+ /** Where in the app it happened — feeds the server-side dedupe key
17
+ * (same title + step dedupes to the existing open ticket). */
18
+ step?: string;
19
+ /** System/env info (platform, os version, app version, …). */
20
+ context?: Record<string, unknown>;
21
+ }
22
+ interface PublicBugResult {
23
+ /** The filed (or deduped-to) ticket number. */
24
+ number: number;
25
+ /** True when an open ticket with the same title+step already existed. */
26
+ deduped: boolean;
27
+ }
28
+ interface PublicFeatureInput {
29
+ /** One-line summary (required, ≤200 chars). */
30
+ title: string;
31
+ /** What the feature should do (≤8000 chars). */
32
+ description?: string;
33
+ /** The workflow it would unblock (≤8000 chars). */
34
+ useCase?: string;
35
+ /** Optional contact email for follow-up. */
36
+ reporterEmail?: string;
37
+ /** Where in the app the request came from — feeds the server-side dedupe key. */
38
+ step?: string;
39
+ /** System/env info (platform, os version, app version, …). */
40
+ context?: Record<string, unknown>;
41
+ }
42
+ interface SubmitPublicBugOptions {
43
+ /** The app's public client key (`sdk_client_*`) — safe to embed. Must carry
44
+ * the `tickets:public_create` scope. */
45
+ clientKey: string;
46
+ /** Edge worker origin. Defaults to production (`https://api.shipeasy.ai`). */
47
+ edgeBaseUrl?: string;
48
+ /** Injectable fetch for tests. Defaults to global fetch. */
49
+ fetch?: typeof fetch;
50
+ }
51
+ declare function submitPublicBug(input: PublicBugInput, opts: SubmitPublicBugOptions): Promise<PublicBugResult>;
52
+ /** File a feature request through the same public intake (`type: "feature"`).
53
+ * Same key/opt-in gates, same forced `pending_approval` state. */
54
+ declare function submitPublicFeature(input: PublicFeatureInput, opts: SubmitPublicBugOptions): Promise<PublicBugResult>;
55
+
56
+ export { type PublicBugInput, type PublicBugResult, type PublicFeatureInput, PublicTicketsDisabled, type SubmitPublicBugOptions, submitPublicBug, submitPublicFeature };
@@ -0,0 +1,56 @@
1
+ /** The project has not opted into public ticket creation (or the client key
2
+ * lacks the `tickets:public_create` scope). */
3
+ declare class PublicTicketsDisabled extends Error {
4
+ readonly status = 403;
5
+ constructor(message: string);
6
+ }
7
+ interface PublicBugInput {
8
+ /** One-line summary (required, ≤200 chars). */
9
+ title: string;
10
+ /** What happened — the actual result / error text (≤8000 chars). */
11
+ error?: string;
12
+ /** Freeform description / steps (≤8000 chars). */
13
+ description?: string;
14
+ /** Optional contact email for follow-up. */
15
+ reporterEmail?: string;
16
+ /** Where in the app it happened — feeds the server-side dedupe key
17
+ * (same title + step dedupes to the existing open ticket). */
18
+ step?: string;
19
+ /** System/env info (platform, os version, app version, …). */
20
+ context?: Record<string, unknown>;
21
+ }
22
+ interface PublicBugResult {
23
+ /** The filed (or deduped-to) ticket number. */
24
+ number: number;
25
+ /** True when an open ticket with the same title+step already existed. */
26
+ deduped: boolean;
27
+ }
28
+ interface PublicFeatureInput {
29
+ /** One-line summary (required, ≤200 chars). */
30
+ title: string;
31
+ /** What the feature should do (≤8000 chars). */
32
+ description?: string;
33
+ /** The workflow it would unblock (≤8000 chars). */
34
+ useCase?: string;
35
+ /** Optional contact email for follow-up. */
36
+ reporterEmail?: string;
37
+ /** Where in the app the request came from — feeds the server-side dedupe key. */
38
+ step?: string;
39
+ /** System/env info (platform, os version, app version, …). */
40
+ context?: Record<string, unknown>;
41
+ }
42
+ interface SubmitPublicBugOptions {
43
+ /** The app's public client key (`sdk_client_*`) — safe to embed. Must carry
44
+ * the `tickets:public_create` scope. */
45
+ clientKey: string;
46
+ /** Edge worker origin. Defaults to production (`https://api.shipeasy.ai`). */
47
+ edgeBaseUrl?: string;
48
+ /** Injectable fetch for tests. Defaults to global fetch. */
49
+ fetch?: typeof fetch;
50
+ }
51
+ declare function submitPublicBug(input: PublicBugInput, opts: SubmitPublicBugOptions): Promise<PublicBugResult>;
52
+ /** File a feature request through the same public intake (`type: "feature"`).
53
+ * Same key/opt-in gates, same forced `pending_approval` state. */
54
+ declare function submitPublicFeature(input: PublicFeatureInput, opts: SubmitPublicBugOptions): Promise<PublicBugResult>;
55
+
56
+ export { type PublicBugInput, type PublicBugResult, type PublicFeatureInput, PublicTicketsDisabled, type SubmitPublicBugOptions, submitPublicBug, submitPublicFeature };
@@ -0,0 +1,12 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+
5
+ var _chunkRANNOC72js = require('./chunk-RANNOC72.js');
6
+ require('./chunk-KPO3R7ND.js');
7
+ require('./chunk-I2KLQ2HA.js');
8
+
9
+
10
+
11
+
12
+ exports.PublicTicketsDisabled = _chunkRANNOC72js.PublicTicketsDisabled; exports.submitPublicBug = _chunkRANNOC72js.submitPublicBug; exports.submitPublicFeature = _chunkRANNOC72js.submitPublicFeature;
@@ -0,0 +1,12 @@
1
+ import {
2
+ PublicTicketsDisabled,
3
+ submitPublicBug,
4
+ submitPublicFeature
5
+ } from "./chunk-WP2TWHG3.mjs";
6
+ import "./chunk-RH6X24HG.mjs";
7
+ import "./chunk-U5DDQYSF.mjs";
8
+ export {
9
+ PublicTicketsDisabled,
10
+ submitPublicBug,
11
+ submitPublicFeature
12
+ };
@@ -0,0 +1,25 @@
1
+ import { SeeChain, SeeViolationChain } from '@shipeasy/sdk/devtools-contract';
2
+
3
+ /**
4
+ * Point the reporter at an edge origin + tag reports with the running project.
5
+ * Called once from the overlay mount. Safe to call again on session swap.
6
+ */
7
+ declare function configureSelfReport(opts: {
8
+ edgeBaseUrl?: string;
9
+ affectedProjectId?: string;
10
+ }): void;
11
+ /**
12
+ * The overlay's own `see()` — same grammar as `@shipeasy/sdk`'s see():
13
+ *
14
+ * see(err).causes_the("label draft").to("not be saved").extras({ profile_id });
15
+ * see.Violation("no profile").causes_the("label edit").to("have no anchor");
16
+ *
17
+ * Reports into Shipeasy's monitoring project, NOT the customer's. Import it in
18
+ * overlay catch blocks that know the user-visible consequence of the fault.
19
+ */
20
+ declare function see(problem: unknown): SeeChain;
21
+ declare namespace see {
22
+ var Violation: (name: string) => SeeViolationChain;
23
+ }
24
+
25
+ export { configureSelfReport, see };
@@ -0,0 +1,25 @@
1
+ import { SeeChain, SeeViolationChain } from '@shipeasy/sdk/devtools-contract';
2
+
3
+ /**
4
+ * Point the reporter at an edge origin + tag reports with the running project.
5
+ * Called once from the overlay mount. Safe to call again on session swap.
6
+ */
7
+ declare function configureSelfReport(opts: {
8
+ edgeBaseUrl?: string;
9
+ affectedProjectId?: string;
10
+ }): void;
11
+ /**
12
+ * The overlay's own `see()` — same grammar as `@shipeasy/sdk`'s see():
13
+ *
14
+ * see(err).causes_the("label draft").to("not be saved").extras({ profile_id });
15
+ * see.Violation("no profile").causes_the("label edit").to("have no anchor");
16
+ *
17
+ * Reports into Shipeasy's monitoring project, NOT the customer's. Import it in
18
+ * overlay catch blocks that know the user-visible consequence of the fault.
19
+ */
20
+ declare function see(problem: unknown): SeeChain;
21
+ declare namespace see {
22
+ var Violation: (name: string) => SeeViolationChain;
23
+ }
24
+
25
+ export { configureSelfReport, see };
@@ -0,0 +1,73 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
2
+
3
+
4
+ var _chunkKPO3R7NDjs = require('./chunk-KPO3R7ND.js');
5
+ require('./chunk-I2KLQ2HA.js');
6
+
7
+ // src/self-report.ts
8
+
9
+
10
+
11
+
12
+
13
+ var _devtoolscontract = require('@shipeasy/sdk/devtools-contract');
14
+ var PLACEHOLDER_KEY = "sdk_client_REPLACE_WITH_SHIPEASY_DEVTOOLS_MONITOR_KEY";
15
+ var MONITOR_CLIENT_KEY = PLACEHOLDER_KEY;
16
+ var SELF_REPORT_SDK_VERSION = "devtools-overlay";
17
+ var config = { edgeBaseUrl: _chunkKPO3R7NDjs.DEFAULT_EDGE_BASE_URL };
18
+ var limiter = new (0, _devtoolscontract.SeeLimiter)();
19
+ function configureSelfReport(opts) {
20
+ config = {
21
+ edgeBaseUrl: (_nullishCoalesce(opts.edgeBaseUrl, () => ( _chunkKPO3R7NDjs.DEFAULT_EDGE_BASE_URL))).replace(/\/$/, ""),
22
+ affectedProjectId: opts.affectedProjectId
23
+ };
24
+ }
25
+ function armed() {
26
+ return !!MONITOR_CLIENT_KEY && MONITOR_CLIENT_KEY !== PLACEHOLDER_KEY;
27
+ }
28
+ function post(events) {
29
+ const url = `${config.edgeBaseUrl}/collect`;
30
+ if (typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function") {
31
+ try {
32
+ const body = JSON.stringify({ k: MONITOR_CLIENT_KEY, events });
33
+ if (navigator.sendBeacon(url, new Blob([body], { type: "text/plain" }))) return;
34
+ } catch (e) {
35
+ }
36
+ }
37
+ try {
38
+ void fetch(url, {
39
+ method: "POST",
40
+ headers: { "X-SDK-Key": MONITOR_CLIENT_KEY, "Content-Type": "application/json" },
41
+ body: JSON.stringify({ events }),
42
+ keepalive: true
43
+ }).catch(() => {
44
+ });
45
+ } catch (e2) {
46
+ }
47
+ }
48
+ function dispatch(problem, consequence, extras, kind) {
49
+ if (!armed()) return;
50
+ try {
51
+ const enriched = {
52
+ surface: "devtools",
53
+ ...config.affectedProjectId ? { affected_project: config.affectedProjectId } : {},
54
+ ...extras
55
+ };
56
+ const ev = _devtoolscontract.buildSeeEvent.call(void 0, problem, consequence, enriched, {
57
+ side: "client",
58
+ sdkVersion: SELF_REPORT_SDK_VERSION,
59
+ url: typeof window !== "undefined" && window.location ? window.location.href : void 0
60
+ }, kind);
61
+ if (!limiter.shouldSend(ev)) return;
62
+ post([ev]);
63
+ } catch (e3) {
64
+ }
65
+ }
66
+ function see(problem) {
67
+ return _devtoolscontract.startSeeChain.call(void 0, () => problem, dispatch);
68
+ }
69
+ see.Violation = (name) => _devtoolscontract.startSeeViolationChain.call(void 0, name, dispatch);
70
+
71
+
72
+
73
+ exports.configureSelfReport = configureSelfReport; exports.see = see;
@@ -0,0 +1,73 @@
1
+ import {
2
+ DEFAULT_EDGE_BASE_URL,
3
+ types_exports
4
+ } from "./chunk-RH6X24HG.mjs";
5
+ import "./chunk-U5DDQYSF.mjs";
6
+
7
+ // src/self-report.ts
8
+ import {
9
+ buildSeeEvent,
10
+ SeeLimiter,
11
+ startSeeChain,
12
+ startSeeViolationChain
13
+ } from "@shipeasy/sdk/devtools-contract";
14
+ var PLACEHOLDER_KEY = "sdk_client_REPLACE_WITH_SHIPEASY_DEVTOOLS_MONITOR_KEY";
15
+ var MONITOR_CLIENT_KEY = PLACEHOLDER_KEY;
16
+ var SELF_REPORT_SDK_VERSION = "devtools-overlay";
17
+ var config = { edgeBaseUrl: DEFAULT_EDGE_BASE_URL };
18
+ var limiter = new SeeLimiter();
19
+ function configureSelfReport(opts) {
20
+ config = {
21
+ edgeBaseUrl: (opts.edgeBaseUrl ?? DEFAULT_EDGE_BASE_URL).replace(/\/$/, ""),
22
+ affectedProjectId: opts.affectedProjectId
23
+ };
24
+ }
25
+ function armed() {
26
+ return !!MONITOR_CLIENT_KEY && MONITOR_CLIENT_KEY !== PLACEHOLDER_KEY;
27
+ }
28
+ function post(events) {
29
+ const url = `${config.edgeBaseUrl}/collect`;
30
+ if (typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function") {
31
+ try {
32
+ const body = JSON.stringify({ k: MONITOR_CLIENT_KEY, events });
33
+ if (navigator.sendBeacon(url, new Blob([body], { type: "text/plain" }))) return;
34
+ } catch {
35
+ }
36
+ }
37
+ try {
38
+ void fetch(url, {
39
+ method: "POST",
40
+ headers: { "X-SDK-Key": MONITOR_CLIENT_KEY, "Content-Type": "application/json" },
41
+ body: JSON.stringify({ events }),
42
+ keepalive: true
43
+ }).catch(() => {
44
+ });
45
+ } catch {
46
+ }
47
+ }
48
+ function dispatch(problem, consequence, extras, kind) {
49
+ if (!armed()) return;
50
+ try {
51
+ const enriched = {
52
+ surface: "devtools",
53
+ ...config.affectedProjectId ? { affected_project: config.affectedProjectId } : {},
54
+ ...extras
55
+ };
56
+ const ev = buildSeeEvent(problem, consequence, enriched, {
57
+ side: "client",
58
+ sdkVersion: SELF_REPORT_SDK_VERSION,
59
+ url: typeof window !== "undefined" && window.location ? window.location.href : void 0
60
+ }, kind);
61
+ if (!limiter.shouldSend(ev)) return;
62
+ post([ev]);
63
+ } catch {
64
+ }
65
+ }
66
+ function see(problem) {
67
+ return startSeeChain(() => problem, dispatch);
68
+ }
69
+ see.Violation = (name) => startSeeViolationChain(name, dispatch);
70
+ export {
71
+ configureSelfReport,
72
+ see
73
+ };
@@ -0,0 +1,278 @@
1
+ type UniverseParam = {
2
+ /**
3
+ * Param key, referenced by `groups[].params` on every experiment in the universe.
4
+ */
5
+ name: string;
6
+ /**
7
+ * Scalar type of the param's value.
8
+ */
9
+ type: 'bool' | 'string' | 'int' | 'number';
10
+ /**
11
+ * Universe-wide default. Returned when the assigned variant doesn't override this param (resolution: variant override → universe default).
12
+ */
13
+ default: unknown;
14
+ };
15
+ /**
16
+ * The universe's ordered config schema — the single source of truth for its params.
17
+ */
18
+ type UniverseParamSchema = Array<UniverseParam>;
19
+ type ListUniversesResponse = {
20
+ data: Array<{
21
+ /**
22
+ * Stable opaque universe id.
23
+ */
24
+ id: string;
25
+ /**
26
+ * Stable universe key. Single segment or `folder.name`. Lowercase letters, digits, `_` or `-`; max 128 chars. Immutable after create.
27
+ */
28
+ name: string;
29
+ /**
30
+ * Human-readable blurb shown in the universe picker/hovercard.
31
+ */
32
+ description?: string | null;
33
+ /**
34
+ * Unit of randomisation. Snake-case in request (`unit_type`), camelCase in response.
35
+ */
36
+ unitType: string;
37
+ /**
38
+ * Reserved holdout bucket range, or `null` if none.
39
+ */
40
+ holdoutRange: [
41
+ number,
42
+ number
43
+ ] | null;
44
+ /**
45
+ * Basis points of headroom seeded into each new experiment's reserved tail (0 = none).
46
+ */
47
+ recommendedHeadroom?: number;
48
+ /**
49
+ * The universe-owned config schema, or `null` on pre-rework universes not yet seeded.
50
+ */
51
+ paramSchema?: UniverseParamSchema | null;
52
+ /**
53
+ * ISO-8601 timestamp of creation.
54
+ */
55
+ createdAt: string;
56
+ }>;
57
+ next_cursor: string | null;
58
+ };
59
+
60
+ /** Prod defaults; both overridable per client (local dev, staging). */
61
+ declare const DEFAULT_ADMIN_BASE_URL = "https://shipeasy.ai";
62
+ declare const DEFAULT_EDGE_BASE_URL = "https://api.shipeasy.ai";
63
+ /** A completed device-auth login: the minted admin key + the project it binds. */
64
+ interface DevtoolsSession {
65
+ /** Raw admin SDK key (`sdk_admin_*`). Store securely (Keychain/Keystore). */
66
+ token: string;
67
+ projectId: string;
68
+ userEmail: string | null;
69
+ projectName: string | null;
70
+ }
71
+ interface ProjectModules {
72
+ translations: boolean;
73
+ configs: boolean;
74
+ gates: boolean;
75
+ experiments: boolean;
76
+ feedback: boolean;
77
+ user: boolean;
78
+ events: boolean;
79
+ }
80
+ interface ProjectRecord {
81
+ id: string;
82
+ name: string;
83
+ domain: string | null;
84
+ modules: ProjectModules;
85
+ }
86
+ /** One attribute predicate inside a gate condition (e.g. `plan is one of
87
+ * ["business"]`). Mirrors the admin `GateRule`. */
88
+ interface GateRule {
89
+ attr: string;
90
+ op: string;
91
+ value: unknown;
92
+ }
93
+ /** One entry in a gate's ordered gatekeeper stack — evaluated top-to-bottom,
94
+ * first match wins. A subset of the admin `StackedGateEntry` (the fields the
95
+ * overlay renders). */
96
+ interface GateStackEntry {
97
+ id?: string;
98
+ type?: "condition" | "rollout";
99
+ name?: string;
100
+ /** all rules must match ("all", default) vs any ("any"). */
101
+ pass?: "all" | "any";
102
+ rules?: GateRule[];
103
+ /** 0–10000 basis points. */
104
+ rolloutPct?: number;
105
+ bucketBy?: string;
106
+ locked?: boolean;
107
+ /** True when this condition is a whitelist (its rule's value is the list). */
108
+ whitelist?: boolean;
109
+ }
110
+ interface GateRecord {
111
+ id: string;
112
+ name: string;
113
+ enabled: boolean;
114
+ killswitch: boolean;
115
+ rolloutPct: number;
116
+ updatedAt: string;
117
+ /** Legacy flat targeting rules (pre-stack gates). */
118
+ rules?: GateRule[] | null;
119
+ /** The gatekeeper stack (modern gates). Present → drives the flow view. */
120
+ stack?: GateStackEntry[] | null;
121
+ }
122
+ /** Permissive default schema. Used when a config record arrives without one. */
123
+ declare const PERMISSIVE_CONFIG_SCHEMA: Record<string, unknown>;
124
+ interface ConfigRecord {
125
+ id: string;
126
+ name: string;
127
+ valueJson: unknown;
128
+ /** JSON Schema describing the value shape. Always type="object" post-migration. */
129
+ schema: Record<string, unknown>;
130
+ updatedAt: string;
131
+ }
132
+ /** One experiment variant (group): its label, split weight, and the per-variant
133
+ * param overrides delivered when a caller is hashed into it (a subset of the
134
+ * universe's param schema; unset keys inherit the universe default). */
135
+ interface ExperimentVariant {
136
+ name: string;
137
+ /** Allocation weight in basis points (0–10000). */
138
+ weight: number;
139
+ params?: Record<string, unknown> | null;
140
+ }
141
+ interface ExperimentRecord {
142
+ id: string;
143
+ name: string;
144
+ /** Name of the universe this experiment runs in. */
145
+ universe: string;
146
+ status: "draft" | "running" | "stopped" | "archived";
147
+ groups: ExperimentVariant[];
148
+ updatedAt: string;
149
+ description?: string | null;
150
+ hypothesis?: string | null;
151
+ ownerEmail?: string | null;
152
+ audience?: string | null;
153
+ /** Unit of randomisation override, or null to inherit the universe's. */
154
+ bucketBy?: string | null;
155
+ /** Share of the gated audience allocated, in basis points (0–10000). */
156
+ allocationPct?: number;
157
+ /** ISO-8601 timestamp of the last transition to `running`, or null. */
158
+ startedAt?: string | null;
159
+ minSampleSize?: number;
160
+ }
161
+ interface ProfileRecord {
162
+ id: string;
163
+ name: string;
164
+ createdAt: string;
165
+ /** 1 when this is the project's default profile (D1 returns the int flag). */
166
+ isDefault?: number;
167
+ }
168
+ type UniverseRecord = ListUniversesResponse["data"][number];
169
+ interface KeyRecord {
170
+ id: string;
171
+ key: string;
172
+ value: string;
173
+ profileId: string | null;
174
+ createdAt: string;
175
+ }
176
+ interface DraftRecord {
177
+ id: string;
178
+ name: string;
179
+ profileId: string;
180
+ status: string;
181
+ createdAt: string;
182
+ }
183
+ /** Subset of the server's `connector_data` the devtools read. The admin
184
+ * endpoints return the full blob; we only type the fields the overlays render:
185
+ * the linked GitHub issue/PR (with the PR's merged marker), and the agent
186
+ * trace Jarvis records as it works an item. All fields are tolerated absent. */
187
+ interface FeedbackConnectorData {
188
+ github?: {
189
+ issue?: {
190
+ number: number;
191
+ url: string;
192
+ };
193
+ pr?: {
194
+ number: number;
195
+ url: string;
196
+ /** Merged markers — any of these present means the PR landed. */
197
+ merged?: boolean;
198
+ mergedAt?: string | null;
199
+ state?: string;
200
+ };
201
+ };
202
+ /** Agent (Jarvis) trace — present once the AI has acted on the item.
203
+ * `awaitingReply` / `state: "awaiting_reply"` means it posted a question
204
+ * back and is waiting on a human. */
205
+ agent?: {
206
+ state?: string;
207
+ awaitingReply?: boolean;
208
+ };
209
+ }
210
+ type BugStatus = "open" | "pending_approval" | "triaged" | "in_progress" | "ready_for_qa" | "resolved" | "wont_fix";
211
+ /** Lowest tier is `nice_to_have`; shared by bugs + feature requests. */
212
+ type BugPriority = "nice_to_have" | "medium" | "high" | "critical";
213
+ interface BugRecord {
214
+ id: string;
215
+ title: string;
216
+ status: BugStatus;
217
+ priority: BugPriority | null;
218
+ reporterEmail: string | null;
219
+ pageUrl: string | null;
220
+ createdAt: string;
221
+ connectorData?: FeedbackConnectorData | null;
222
+ }
223
+ interface AttachmentRecord {
224
+ id: string;
225
+ kind: "screenshot" | "recording" | "file";
226
+ filename: string;
227
+ mimeType: string;
228
+ sizeBytes: number;
229
+ createdAt: string;
230
+ }
231
+ interface BugDetail extends BugRecord {
232
+ stepsToReproduce: string;
233
+ actualResult: string;
234
+ expectedResult: string;
235
+ attachments: AttachmentRecord[];
236
+ }
237
+ /** The queue-item type. `bug`/`feature_request` are user-fileable; `error` and
238
+ * `alert` are auto-filed system tickets the overlay now also lists. */
239
+ type OpsItemType = "bug" | "feature_request" | "error" | "alert" | "measure_plan";
240
+ /** Generic ops-item detail — the enriched GET response, permissive across all
241
+ * types (bug/feature content fields present only for those types; empty for
242
+ * auto-filed error/alert tickets). */
243
+ interface OpsItemDetail extends BugRecord {
244
+ type?: OpsItemType;
245
+ /** Auto-filed tickets carry the originating record's key (error fingerprint,
246
+ * alert dedupe key), or null for human-filed bugs/features. */
247
+ sourceRef?: string | null;
248
+ stepsToReproduce?: string;
249
+ actualResult?: string;
250
+ expectedResult?: string;
251
+ description?: string;
252
+ useCase?: string;
253
+ attachments: AttachmentRecord[];
254
+ }
255
+ interface FeatureRequestRecord {
256
+ id: string;
257
+ title: string;
258
+ status: BugStatus;
259
+ priority: BugPriority | null;
260
+ reporterEmail: string | null;
261
+ pageUrl: string | null;
262
+ createdAt: string;
263
+ connectorData?: FeedbackConnectorData | null;
264
+ }
265
+ interface FeatureRequestDetail extends FeatureRequestRecord {
266
+ description: string;
267
+ useCase: string;
268
+ attachments: AttachmentRecord[];
269
+ }
270
+ interface AttachmentUploadResult {
271
+ id: string;
272
+ filename: string;
273
+ kind: "screenshot" | "recording" | "file";
274
+ mimeType: string;
275
+ sizeBytes: number;
276
+ }
277
+
278
+ export { type AttachmentRecord as A, type BugDetail as B, type ConfigRecord as C, DEFAULT_ADMIN_BASE_URL as D, type ExperimentRecord as E, type FeatureRequestDetail as F, type GateRecord as G, type KeyRecord as K, type OpsItemDetail as O, PERMISSIVE_CONFIG_SCHEMA as P, type UniverseRecord as U, type AttachmentUploadResult as a, type BugPriority as b, type BugRecord as c, type BugStatus as d, DEFAULT_EDGE_BASE_URL as e, type DevtoolsSession as f, type DraftRecord as g, type FeatureRequestRecord as h, type FeedbackConnectorData as i, type GateRule as j, type GateStackEntry as k, type OpsItemType as l, type ProfileRecord as m, type ProjectModules as n, type ProjectRecord as o };