uidex 0.2.4 → 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/README.md +253 -353
- package/dist/cli/cli.cjs +3324 -0
- package/dist/cli/cli.cjs.map +1 -0
- package/dist/cloud/index.cjs +169 -0
- package/dist/cloud/index.cjs.map +1 -0
- package/dist/cloud/index.js +140 -0
- package/dist/cloud/index.js.map +1 -0
- package/dist/headless/index.cjs +4143 -0
- package/dist/headless/index.cjs.map +1 -0
- package/dist/headless/index.d.cts +220 -0
- package/dist/headless/index.d.ts +220 -0
- package/dist/headless/index.js +4130 -0
- package/dist/headless/index.js.map +1 -0
- package/dist/index.cjs +8704 -9883
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +968 -146
- package/dist/index.d.ts +968 -146
- package/dist/index.js +8327 -9492
- package/dist/index.js.map +1 -1
- package/dist/playwright/index.cjs +164 -24
- package/dist/playwright/index.cjs.map +1 -1
- package/dist/playwright/index.d.cts +30 -53
- package/dist/playwright/index.d.ts +30 -53
- package/dist/playwright/index.js +148 -21
- package/dist/playwright/index.js.map +1 -1
- package/dist/playwright/reporter.cjs +62 -28
- package/dist/playwright/reporter.cjs.map +1 -1
- package/dist/playwright/reporter.d.cts +24 -12
- package/dist/playwright/reporter.d.ts +24 -12
- package/dist/playwright/reporter.js +62 -28
- package/dist/playwright/reporter.js.map +1 -1
- package/dist/react/index.cjs +8706 -9883
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +720 -146
- package/dist/react/index.d.ts +720 -146
- package/dist/react/index.js +8518 -9629
- package/dist/react/index.js.map +1 -1
- package/dist/scan/index.cjs +3360 -0
- package/dist/scan/index.cjs.map +1 -0
- package/dist/scan/index.d.cts +378 -0
- package/dist/scan/index.d.ts +378 -0
- package/dist/scan/index.js +3303 -0
- package/dist/scan/index.js.map +1 -0
- package/package.json +67 -60
- package/templates/claude/audit.md +43 -0
- package/templates/claude/rules.md +227 -0
- package/claude/audit-command.md +0 -46
- package/claude/rules.md +0 -167
- package/dist/api/index.cjs +0 -254
- package/dist/api/index.cjs.map +0 -1
- package/dist/api/index.d.cts +0 -236
- package/dist/api/index.d.ts +0 -236
- package/dist/api/index.js +0 -226
- package/dist/api/index.js.map +0 -1
- package/dist/core/index.cjs +0 -11045
- package/dist/core/index.cjs.map +0 -1
- package/dist/core/index.d.cts +0 -424
- package/dist/core/index.d.ts +0 -424
- package/dist/core/index.global.js +0 -66516
- package/dist/core/index.global.js.map +0 -1
- package/dist/core/index.js +0 -10995
- package/dist/core/index.js.map +0 -1
- package/dist/core/style.css +0 -1529
- package/dist/scripts/cli.cjs +0 -3904
- package/uidex.schema.json +0 -93
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/cloud/index.ts
|
|
21
|
+
var cloud_exports = {};
|
|
22
|
+
__export(cloud_exports, {
|
|
23
|
+
CloudError: () => CloudError,
|
|
24
|
+
DEFAULT_CLOUD_ENDPOINT: () => DEFAULT_CLOUD_ENDPOINT,
|
|
25
|
+
cloud: () => cloud
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(cloud_exports);
|
|
28
|
+
|
|
29
|
+
// src/cloud/types.ts
|
|
30
|
+
var DEFAULT_CLOUD_ENDPOINT = "https://app.uidex.dev";
|
|
31
|
+
var CloudError = class extends Error {
|
|
32
|
+
status;
|
|
33
|
+
retryAfter;
|
|
34
|
+
details;
|
|
35
|
+
constructor(message, options) {
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = "CloudError";
|
|
38
|
+
this.status = options.status;
|
|
39
|
+
this.retryAfter = options.retryAfter;
|
|
40
|
+
this.details = options.details;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// src/cloud/client.ts
|
|
45
|
+
function resolveFetch(override) {
|
|
46
|
+
if (override) return override;
|
|
47
|
+
if (typeof globalThis !== "undefined" && typeof globalThis.fetch === "function") {
|
|
48
|
+
return globalThis.fetch.bind(globalThis);
|
|
49
|
+
}
|
|
50
|
+
throw new Error(
|
|
51
|
+
"uidex/cloud: global fetch is not available; pass a `fetch` override"
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
function trimEndpoint(endpoint) {
|
|
55
|
+
return endpoint.endsWith("/") ? endpoint.slice(0, -1) : endpoint;
|
|
56
|
+
}
|
|
57
|
+
function parseRetryAfter(header) {
|
|
58
|
+
if (!header) return void 0;
|
|
59
|
+
const seconds = Number(header);
|
|
60
|
+
if (Number.isFinite(seconds) && seconds >= 0) return seconds;
|
|
61
|
+
const date = Date.parse(header);
|
|
62
|
+
if (Number.isFinite(date)) {
|
|
63
|
+
const delta = Math.ceil((date - Date.now()) / 1e3);
|
|
64
|
+
return delta > 0 ? delta : 0;
|
|
65
|
+
}
|
|
66
|
+
return void 0;
|
|
67
|
+
}
|
|
68
|
+
async function readBody(response) {
|
|
69
|
+
const text = await response.text();
|
|
70
|
+
if (!text) return void 0;
|
|
71
|
+
try {
|
|
72
|
+
return JSON.parse(text);
|
|
73
|
+
} catch {
|
|
74
|
+
return text;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function errorMessage(body, fallback) {
|
|
78
|
+
if (body && typeof body === "object" && "error" in body && typeof body.error === "string") {
|
|
79
|
+
return body.error;
|
|
80
|
+
}
|
|
81
|
+
return fallback;
|
|
82
|
+
}
|
|
83
|
+
function cloud(options) {
|
|
84
|
+
let cachedConfig = null;
|
|
85
|
+
let resolvedConfig = null;
|
|
86
|
+
const projectKey = options.projectKey;
|
|
87
|
+
if (!projectKey) {
|
|
88
|
+
throw new Error("uidex/cloud: `projectKey` is required");
|
|
89
|
+
}
|
|
90
|
+
const endpoint = trimEndpoint(options.endpoint ?? DEFAULT_CLOUD_ENDPOINT);
|
|
91
|
+
const fetchImpl = resolveFetch(options.fetch);
|
|
92
|
+
const authHeader = `Bearer ${projectKey}`;
|
|
93
|
+
async function submit(payload) {
|
|
94
|
+
const response = await fetchImpl(`${endpoint}/api/ingest`, {
|
|
95
|
+
method: "POST",
|
|
96
|
+
headers: {
|
|
97
|
+
"Content-Type": "application/json",
|
|
98
|
+
Authorization: authHeader
|
|
99
|
+
},
|
|
100
|
+
body: JSON.stringify(payload)
|
|
101
|
+
});
|
|
102
|
+
const body = await readBody(response);
|
|
103
|
+
if (!response.ok) {
|
|
104
|
+
const retryAfter = response.status === 429 ? parseRetryAfter(response.headers.get("Retry-After")) : void 0;
|
|
105
|
+
throw new CloudError(
|
|
106
|
+
errorMessage(body, `Feedback submission failed (${response.status})`),
|
|
107
|
+
{ status: response.status, retryAfter, details: body }
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
if (!body || typeof body !== "object") {
|
|
111
|
+
throw new CloudError("Feedback submission returned an empty response", {
|
|
112
|
+
status: response.status
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return body;
|
|
116
|
+
}
|
|
117
|
+
async function fetchConfig() {
|
|
118
|
+
const response = await fetchImpl(`${endpoint}/api/ingest/config`, {
|
|
119
|
+
method: "GET",
|
|
120
|
+
headers: {
|
|
121
|
+
Accept: "application/json",
|
|
122
|
+
Authorization: authHeader
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
const body = await readBody(response);
|
|
126
|
+
if (!response.ok) {
|
|
127
|
+
const retryAfter = response.status === 429 ? parseRetryAfter(response.headers.get("Retry-After")) : void 0;
|
|
128
|
+
throw new CloudError(
|
|
129
|
+
errorMessage(body, `Ingest config request failed (${response.status})`),
|
|
130
|
+
{ status: response.status, retryAfter, details: body }
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
if (!body || typeof body !== "object") {
|
|
134
|
+
throw new CloudError("Ingest config returned an empty response", {
|
|
135
|
+
status: response.status
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return body;
|
|
139
|
+
}
|
|
140
|
+
function startFetch() {
|
|
141
|
+
const promise = fetchConfig();
|
|
142
|
+
promise.then(
|
|
143
|
+
(config) => {
|
|
144
|
+
resolvedConfig = config;
|
|
145
|
+
},
|
|
146
|
+
() => {
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
return promise;
|
|
150
|
+
}
|
|
151
|
+
cachedConfig = startFetch();
|
|
152
|
+
function getConfig() {
|
|
153
|
+
return cachedConfig ?? (cachedConfig = startFetch());
|
|
154
|
+
}
|
|
155
|
+
function getCachedConfig() {
|
|
156
|
+
return resolvedConfig;
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
feedback: { submit },
|
|
160
|
+
integrations: { getConfig, getCachedConfig }
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
164
|
+
0 && (module.exports = {
|
|
165
|
+
CloudError,
|
|
166
|
+
DEFAULT_CLOUD_ENDPOINT,
|
|
167
|
+
cloud
|
|
168
|
+
});
|
|
169
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cloud/index.ts","../../src/cloud/types.ts","../../src/cloud/client.ts"],"sourcesContent":["export { cloud } from \"./client\"\nexport {\n CloudError,\n DEFAULT_CLOUD_ENDPOINT,\n type CloudAdapter,\n type CloudOptions,\n type FeedbackExternalLink,\n type FeedbackPayload,\n type FeedbackResult,\n type FeedbackSuggestedTarget,\n type IngestConfig,\n type IngestConfigIssue,\n type SourceRef,\n} from \"./types\"\n","export type {\n CloudAdapter,\n FeedbackExternalLink,\n FeedbackPayload,\n FeedbackResult,\n FeedbackSuggestedTarget,\n IngestConfig,\n IngestConfigIssue,\n SourceRef,\n} from \"../ingest/feedback-contract\"\n\nexport const DEFAULT_CLOUD_ENDPOINT = \"https://app.uidex.dev\"\n\nexport interface CloudOptions {\n projectKey: string\n endpoint?: string\n fetch?: typeof fetch\n}\n\nexport class CloudError extends Error {\n readonly status: number\n readonly retryAfter?: number\n readonly details?: unknown\n\n constructor(\n message: string,\n options: { status: number; retryAfter?: number; details?: unknown }\n ) {\n super(message)\n this.name = \"CloudError\"\n this.status = options.status\n this.retryAfter = options.retryAfter\n this.details = options.details\n }\n}\n","import {\n CloudError,\n DEFAULT_CLOUD_ENDPOINT,\n type CloudAdapter,\n type CloudOptions,\n type FeedbackPayload,\n type FeedbackResult,\n type IngestConfig,\n} from \"./types\"\n\nfunction resolveFetch(override?: typeof fetch): typeof fetch {\n if (override) return override\n if (\n typeof globalThis !== \"undefined\" &&\n typeof globalThis.fetch === \"function\"\n ) {\n return globalThis.fetch.bind(globalThis)\n }\n throw new Error(\n \"uidex/cloud: global fetch is not available; pass a `fetch` override\"\n )\n}\n\nfunction trimEndpoint(endpoint: string): string {\n return endpoint.endsWith(\"/\") ? endpoint.slice(0, -1) : endpoint\n}\n\nfunction parseRetryAfter(header: string | null): number | undefined {\n if (!header) return undefined\n const seconds = Number(header)\n if (Number.isFinite(seconds) && seconds >= 0) return seconds\n const date = Date.parse(header)\n if (Number.isFinite(date)) {\n const delta = Math.ceil((date - Date.now()) / 1000)\n return delta > 0 ? delta : 0\n }\n return undefined\n}\n\nasync function readBody(response: Response): Promise<unknown> {\n const text = await response.text()\n if (!text) return undefined\n try {\n return JSON.parse(text)\n } catch {\n return text\n }\n}\n\nfunction errorMessage(body: unknown, fallback: string): string {\n if (\n body &&\n typeof body === \"object\" &&\n \"error\" in body &&\n typeof (body as { error: unknown }).error === \"string\"\n ) {\n return (body as { error: string }).error\n }\n return fallback\n}\n\nexport function cloud(options: CloudOptions): CloudAdapter {\n let cachedConfig: Promise<IngestConfig> | null = null\n let resolvedConfig: IngestConfig | null = null\n\n const projectKey = options.projectKey\n if (!projectKey) {\n throw new Error(\"uidex/cloud: `projectKey` is required\")\n }\n const endpoint = trimEndpoint(options.endpoint ?? DEFAULT_CLOUD_ENDPOINT)\n const fetchImpl = resolveFetch(options.fetch)\n const authHeader = `Bearer ${projectKey}`\n\n async function submit(payload: FeedbackPayload): Promise<FeedbackResult> {\n const response = await fetchImpl(`${endpoint}/api/ingest`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: authHeader,\n },\n body: JSON.stringify(payload),\n })\n\n const body = await readBody(response)\n\n if (!response.ok) {\n const retryAfter =\n response.status === 429\n ? parseRetryAfter(response.headers.get(\"Retry-After\"))\n : undefined\n throw new CloudError(\n errorMessage(body, `Feedback submission failed (${response.status})`),\n { status: response.status, retryAfter, details: body }\n )\n }\n\n if (!body || typeof body !== \"object\") {\n throw new CloudError(\"Feedback submission returned an empty response\", {\n status: response.status,\n })\n }\n return body as FeedbackResult\n }\n\n async function fetchConfig(): Promise<IngestConfig> {\n const response = await fetchImpl(`${endpoint}/api/ingest/config`, {\n method: \"GET\",\n headers: {\n Accept: \"application/json\",\n Authorization: authHeader,\n },\n })\n\n const body = await readBody(response)\n\n if (!response.ok) {\n const retryAfter =\n response.status === 429\n ? parseRetryAfter(response.headers.get(\"Retry-After\"))\n : undefined\n throw new CloudError(\n errorMessage(body, `Ingest config request failed (${response.status})`),\n { status: response.status, retryAfter, details: body }\n )\n }\n\n if (!body || typeof body !== \"object\") {\n throw new CloudError(\"Ingest config returned an empty response\", {\n status: response.status,\n })\n }\n return body as IngestConfig\n }\n\n function startFetch(): Promise<IngestConfig> {\n const promise = fetchConfig()\n promise.then(\n (config) => {\n resolvedConfig = config\n },\n () => {}\n )\n return promise\n }\n\n cachedConfig = startFetch()\n\n function getConfig(): Promise<IngestConfig> {\n return cachedConfig ?? (cachedConfig = startFetch())\n }\n\n function getCachedConfig(): IngestConfig | null {\n return resolvedConfig\n }\n\n return {\n feedback: { submit },\n integrations: { getConfig, getCachedConfig },\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// src/cloud/types.ts
|
|
2
|
+
var DEFAULT_CLOUD_ENDPOINT = "https://app.uidex.dev";
|
|
3
|
+
var CloudError = class extends Error {
|
|
4
|
+
status;
|
|
5
|
+
retryAfter;
|
|
6
|
+
details;
|
|
7
|
+
constructor(message, options) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "CloudError";
|
|
10
|
+
this.status = options.status;
|
|
11
|
+
this.retryAfter = options.retryAfter;
|
|
12
|
+
this.details = options.details;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// src/cloud/client.ts
|
|
17
|
+
function resolveFetch(override) {
|
|
18
|
+
if (override) return override;
|
|
19
|
+
if (typeof globalThis !== "undefined" && typeof globalThis.fetch === "function") {
|
|
20
|
+
return globalThis.fetch.bind(globalThis);
|
|
21
|
+
}
|
|
22
|
+
throw new Error(
|
|
23
|
+
"uidex/cloud: global fetch is not available; pass a `fetch` override"
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
function trimEndpoint(endpoint) {
|
|
27
|
+
return endpoint.endsWith("/") ? endpoint.slice(0, -1) : endpoint;
|
|
28
|
+
}
|
|
29
|
+
function parseRetryAfter(header) {
|
|
30
|
+
if (!header) return void 0;
|
|
31
|
+
const seconds = Number(header);
|
|
32
|
+
if (Number.isFinite(seconds) && seconds >= 0) return seconds;
|
|
33
|
+
const date = Date.parse(header);
|
|
34
|
+
if (Number.isFinite(date)) {
|
|
35
|
+
const delta = Math.ceil((date - Date.now()) / 1e3);
|
|
36
|
+
return delta > 0 ? delta : 0;
|
|
37
|
+
}
|
|
38
|
+
return void 0;
|
|
39
|
+
}
|
|
40
|
+
async function readBody(response) {
|
|
41
|
+
const text = await response.text();
|
|
42
|
+
if (!text) return void 0;
|
|
43
|
+
try {
|
|
44
|
+
return JSON.parse(text);
|
|
45
|
+
} catch {
|
|
46
|
+
return text;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function errorMessage(body, fallback) {
|
|
50
|
+
if (body && typeof body === "object" && "error" in body && typeof body.error === "string") {
|
|
51
|
+
return body.error;
|
|
52
|
+
}
|
|
53
|
+
return fallback;
|
|
54
|
+
}
|
|
55
|
+
function cloud(options) {
|
|
56
|
+
let cachedConfig = null;
|
|
57
|
+
let resolvedConfig = null;
|
|
58
|
+
const projectKey = options.projectKey;
|
|
59
|
+
if (!projectKey) {
|
|
60
|
+
throw new Error("uidex/cloud: `projectKey` is required");
|
|
61
|
+
}
|
|
62
|
+
const endpoint = trimEndpoint(options.endpoint ?? DEFAULT_CLOUD_ENDPOINT);
|
|
63
|
+
const fetchImpl = resolveFetch(options.fetch);
|
|
64
|
+
const authHeader = `Bearer ${projectKey}`;
|
|
65
|
+
async function submit(payload) {
|
|
66
|
+
const response = await fetchImpl(`${endpoint}/api/ingest`, {
|
|
67
|
+
method: "POST",
|
|
68
|
+
headers: {
|
|
69
|
+
"Content-Type": "application/json",
|
|
70
|
+
Authorization: authHeader
|
|
71
|
+
},
|
|
72
|
+
body: JSON.stringify(payload)
|
|
73
|
+
});
|
|
74
|
+
const body = await readBody(response);
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
const retryAfter = response.status === 429 ? parseRetryAfter(response.headers.get("Retry-After")) : void 0;
|
|
77
|
+
throw new CloudError(
|
|
78
|
+
errorMessage(body, `Feedback submission failed (${response.status})`),
|
|
79
|
+
{ status: response.status, retryAfter, details: body }
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
if (!body || typeof body !== "object") {
|
|
83
|
+
throw new CloudError("Feedback submission returned an empty response", {
|
|
84
|
+
status: response.status
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return body;
|
|
88
|
+
}
|
|
89
|
+
async function fetchConfig() {
|
|
90
|
+
const response = await fetchImpl(`${endpoint}/api/ingest/config`, {
|
|
91
|
+
method: "GET",
|
|
92
|
+
headers: {
|
|
93
|
+
Accept: "application/json",
|
|
94
|
+
Authorization: authHeader
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
const body = await readBody(response);
|
|
98
|
+
if (!response.ok) {
|
|
99
|
+
const retryAfter = response.status === 429 ? parseRetryAfter(response.headers.get("Retry-After")) : void 0;
|
|
100
|
+
throw new CloudError(
|
|
101
|
+
errorMessage(body, `Ingest config request failed (${response.status})`),
|
|
102
|
+
{ status: response.status, retryAfter, details: body }
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
if (!body || typeof body !== "object") {
|
|
106
|
+
throw new CloudError("Ingest config returned an empty response", {
|
|
107
|
+
status: response.status
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return body;
|
|
111
|
+
}
|
|
112
|
+
function startFetch() {
|
|
113
|
+
const promise = fetchConfig();
|
|
114
|
+
promise.then(
|
|
115
|
+
(config) => {
|
|
116
|
+
resolvedConfig = config;
|
|
117
|
+
},
|
|
118
|
+
() => {
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
return promise;
|
|
122
|
+
}
|
|
123
|
+
cachedConfig = startFetch();
|
|
124
|
+
function getConfig() {
|
|
125
|
+
return cachedConfig ?? (cachedConfig = startFetch());
|
|
126
|
+
}
|
|
127
|
+
function getCachedConfig() {
|
|
128
|
+
return resolvedConfig;
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
feedback: { submit },
|
|
132
|
+
integrations: { getConfig, getCachedConfig }
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
export {
|
|
136
|
+
CloudError,
|
|
137
|
+
DEFAULT_CLOUD_ENDPOINT,
|
|
138
|
+
cloud
|
|
139
|
+
};
|
|
140
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cloud/types.ts","../../src/cloud/client.ts"],"sourcesContent":["export type {\n CloudAdapter,\n FeedbackExternalLink,\n FeedbackPayload,\n FeedbackResult,\n FeedbackSuggestedTarget,\n IngestConfig,\n IngestConfigIssue,\n SourceRef,\n} from \"../ingest/feedback-contract\"\n\nexport const DEFAULT_CLOUD_ENDPOINT = \"https://app.uidex.dev\"\n\nexport interface CloudOptions {\n projectKey: string\n endpoint?: string\n fetch?: typeof fetch\n}\n\nexport class CloudError extends Error {\n readonly status: number\n readonly retryAfter?: number\n readonly details?: unknown\n\n constructor(\n message: string,\n options: { status: number; retryAfter?: number; details?: unknown }\n ) {\n super(message)\n this.name = \"CloudError\"\n this.status = options.status\n this.retryAfter = options.retryAfter\n this.details = options.details\n }\n}\n","import {\n CloudError,\n DEFAULT_CLOUD_ENDPOINT,\n type CloudAdapter,\n type CloudOptions,\n type FeedbackPayload,\n type FeedbackResult,\n type IngestConfig,\n} from \"./types\"\n\nfunction resolveFetch(override?: typeof fetch): typeof fetch {\n if (override) return override\n if (\n typeof globalThis !== \"undefined\" &&\n typeof globalThis.fetch === \"function\"\n ) {\n return globalThis.fetch.bind(globalThis)\n }\n throw new Error(\n \"uidex/cloud: global fetch is not available; pass a `fetch` override\"\n )\n}\n\nfunction trimEndpoint(endpoint: string): string {\n return endpoint.endsWith(\"/\") ? endpoint.slice(0, -1) : endpoint\n}\n\nfunction parseRetryAfter(header: string | null): number | undefined {\n if (!header) return undefined\n const seconds = Number(header)\n if (Number.isFinite(seconds) && seconds >= 0) return seconds\n const date = Date.parse(header)\n if (Number.isFinite(date)) {\n const delta = Math.ceil((date - Date.now()) / 1000)\n return delta > 0 ? delta : 0\n }\n return undefined\n}\n\nasync function readBody(response: Response): Promise<unknown> {\n const text = await response.text()\n if (!text) return undefined\n try {\n return JSON.parse(text)\n } catch {\n return text\n }\n}\n\nfunction errorMessage(body: unknown, fallback: string): string {\n if (\n body &&\n typeof body === \"object\" &&\n \"error\" in body &&\n typeof (body as { error: unknown }).error === \"string\"\n ) {\n return (body as { error: string }).error\n }\n return fallback\n}\n\nexport function cloud(options: CloudOptions): CloudAdapter {\n let cachedConfig: Promise<IngestConfig> | null = null\n let resolvedConfig: IngestConfig | null = null\n\n const projectKey = options.projectKey\n if (!projectKey) {\n throw new Error(\"uidex/cloud: `projectKey` is required\")\n }\n const endpoint = trimEndpoint(options.endpoint ?? DEFAULT_CLOUD_ENDPOINT)\n const fetchImpl = resolveFetch(options.fetch)\n const authHeader = `Bearer ${projectKey}`\n\n async function submit(payload: FeedbackPayload): Promise<FeedbackResult> {\n const response = await fetchImpl(`${endpoint}/api/ingest`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: authHeader,\n },\n body: JSON.stringify(payload),\n })\n\n const body = await readBody(response)\n\n if (!response.ok) {\n const retryAfter =\n response.status === 429\n ? parseRetryAfter(response.headers.get(\"Retry-After\"))\n : undefined\n throw new CloudError(\n errorMessage(body, `Feedback submission failed (${response.status})`),\n { status: response.status, retryAfter, details: body }\n )\n }\n\n if (!body || typeof body !== \"object\") {\n throw new CloudError(\"Feedback submission returned an empty response\", {\n status: response.status,\n })\n }\n return body as FeedbackResult\n }\n\n async function fetchConfig(): Promise<IngestConfig> {\n const response = await fetchImpl(`${endpoint}/api/ingest/config`, {\n method: \"GET\",\n headers: {\n Accept: \"application/json\",\n Authorization: authHeader,\n },\n })\n\n const body = await readBody(response)\n\n if (!response.ok) {\n const retryAfter =\n response.status === 429\n ? parseRetryAfter(response.headers.get(\"Retry-After\"))\n : undefined\n throw new CloudError(\n errorMessage(body, `Ingest config request failed (${response.status})`),\n { status: response.status, retryAfter, details: body }\n )\n }\n\n if (!body || typeof body !== \"object\") {\n throw new CloudError(\"Ingest config returned an empty response\", {\n status: response.status,\n })\n }\n return body as IngestConfig\n }\n\n function startFetch(): Promise<IngestConfig> {\n const promise = fetchConfig()\n promise.then(\n (config) => {\n resolvedConfig = config\n },\n () => {}\n )\n return promise\n }\n\n cachedConfig = startFetch()\n\n function getConfig(): Promise<IngestConfig> {\n return cachedConfig ?? (cachedConfig = startFetch())\n }\n\n function getCachedConfig(): IngestConfig | null {\n return resolvedConfig\n }\n\n return {\n feedback: { submit },\n integrations: { getConfig, getCachedConfig },\n }\n}\n"],"mappings":"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","names":[]}
|