@softr/sdk 0.0.22 → 0.0.24
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/dist/auth/session.js +7 -21
- package/dist/core/datasource.d.ts +17 -7
- package/dist/core/datasource.js +37 -32
- package/dist/core/integration.js +2 -2
- package/dist/core/utils.js +14 -0
- package/dist/default-error-overlay.d.ts +13 -0
- package/dist/default-error-overlay.js +319 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/types.d.ts +13 -3
- package/dist/vite.d.ts +2 -9
- package/dist/vite.js +3 -68
- package/package.json +1 -6
- package/skills/softr-sdk/SKILL.md +6 -5
- package/skills/softr-sdk/auth/SKILL.md +2 -2
- package/skills/softr-sdk/current-user/SKILL.md +2 -2
- package/skills/softr-sdk/data-mutations/SKILL.md +23 -8
- package/skills/softr-sdk/reading-records/SKILL.md +5 -7
- package/skills/softr-sdk/routes-and-visibility/SKILL.md +7 -7
- package/dist/preview-identity/preview-identity.js +0 -121
- package/dist/routes/discover.d.ts +0 -14
- package/dist/routes/discover.js +0 -305
- package/dist/routes/manifest.d.ts +0 -24
- package/dist/routes/manifest.js +0 -168
- package/dist/routes/mem-fs.js +0 -71
package/dist/auth/session.js
CHANGED
|
@@ -46,8 +46,9 @@ function readSessionData(sessionToken) {
|
|
|
46
46
|
permissions: payload.permissions
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
|
-
function makeSessionTokenCookie(token
|
|
50
|
-
|
|
49
|
+
function makeSessionTokenCookie(token) {
|
|
50
|
+
const { name, secure } = sessionCookie(SESSION_TOKEN);
|
|
51
|
+
return serializeCookie(name, sealEnvelope(token, SESSION_TOKEN), {
|
|
51
52
|
maxAge: sessionConfig().sessionMaxAge,
|
|
52
53
|
secure
|
|
53
54
|
});
|
|
@@ -71,19 +72,6 @@ function makeSessionDataCookie(session, sessionToken) {
|
|
|
71
72
|
function clearSession() {
|
|
72
73
|
clearCookies([SESSION_TOKEN, SESSION_DATA]);
|
|
73
74
|
}
|
|
74
|
-
/** The clearing pair, for the same out-of-context caller as `makeSessionTokenCookie`. */
|
|
75
|
-
function makeSessionClearingCookies(secure) {
|
|
76
|
-
return serializeClearingCookies([SESSION_TOKEN, SESSION_DATA], secure);
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* The name `readSessionToken` would look the token up under on a request of this
|
|
80
|
-
* scheme, for a caller that only needs to know whether one is present and cannot
|
|
81
|
-
* decode it. Same `secure` argument as `makeSessionTokenCookie`, so a caller that
|
|
82
|
-
* writes and a caller that probes cannot disagree about the name.
|
|
83
|
-
*/
|
|
84
|
-
function sessionTokenCookieName(secure) {
|
|
85
|
-
return sessionCookieName(SESSION_TOKEN, secure);
|
|
86
|
-
}
|
|
87
75
|
const sessionDataSchema = z.object({
|
|
88
76
|
user: userSchema.nullable(),
|
|
89
77
|
permissions: permissionsSchema,
|
|
@@ -95,13 +83,11 @@ const sessionDataSchema = z.object({
|
|
|
95
83
|
* schemes, and the one left behind would revive if the scheme changed back.
|
|
96
84
|
*/
|
|
97
85
|
function clearCookies(bases) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
function serializeClearingCookies(bases, secure) {
|
|
101
|
-
return bases.flatMap((base) => secure ? [sessionCookieName(base, secure), base] : [base]).map((name) => serializeCookie(name, "", {
|
|
86
|
+
const secure = requestIsSecure();
|
|
87
|
+
writeCookies(bases.flatMap((base) => secure ? [sessionCookieName(base, secure), base] : [base]).map((name) => serializeCookie(name, "", {
|
|
102
88
|
maxAge: 0,
|
|
103
89
|
secure
|
|
104
|
-
}));
|
|
90
|
+
})));
|
|
105
91
|
}
|
|
106
92
|
/**
|
|
107
93
|
* Over the plaintext token, never the cookie value: that is resealed with a
|
|
@@ -177,4 +163,4 @@ function openEnvelope(raw, purpose) {
|
|
|
177
163
|
}
|
|
178
164
|
|
|
179
165
|
//#endregion
|
|
180
|
-
export { clearSession,
|
|
166
|
+
export { clearSession, makeSessionDataCookie, makeSessionTokenCookie, readSessionData, readSessionToken };
|
|
@@ -1,13 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ChartOptions, ChartResult, CreateOptions, GetOptions, ListOptions, ListResult, MetricOptions, MetricResult, RecordFieldsFor, SoftrRecord, UpdateOptions } from "../types.js";
|
|
2
2
|
|
|
3
3
|
//#region src/core/datasource.d.ts
|
|
4
|
-
declare function listRecords(datasourceId:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
declare function
|
|
4
|
+
declare function listRecords<Id extends string, Sel extends Record<string, string> = Record<never, never>>(datasourceId: Id, options?: Omit<ListOptions, 'select'> & {
|
|
5
|
+
select?: Sel;
|
|
6
|
+
}): Promise<ListResult<SoftrRecord<RecordFieldsFor<Id, Sel>>>>;
|
|
7
|
+
declare function getRecord<Id extends string, Sel extends Record<string, string> = Record<never, never>>(datasourceId: Id, options: Omit<GetOptions, 'select'> & {
|
|
8
|
+
select?: Sel;
|
|
9
|
+
}): Promise<SoftrRecord<RecordFieldsFor<Id, Sel>> | null>;
|
|
10
|
+
declare function createRecord<Id extends string, Sel extends Record<string, string> = Record<never, never>>(datasourceId: Id, options: Omit<CreateOptions, 'select' | 'data'> & {
|
|
11
|
+
select?: Sel;
|
|
12
|
+
data: Partial<RecordFieldsFor<Id, Sel>>;
|
|
13
|
+
}): Promise<SoftrRecord<RecordFieldsFor<Id, Sel>>>;
|
|
14
|
+
declare function updateRecord<Id extends string, Sel extends Record<string, string> = Record<never, never>>(datasourceId: Id, options: Omit<UpdateOptions, 'select' | 'data'> & {
|
|
15
|
+
select?: Sel;
|
|
16
|
+
data: Partial<RecordFieldsFor<Id, Sel>>;
|
|
17
|
+
}): Promise<SoftrRecord<RecordFieldsFor<Id, Sel>>>;
|
|
8
18
|
declare function deleteRecord(datasourceId: string, id: string): Promise<void>;
|
|
9
19
|
declare function getMetric(datasourceId: string, options: MetricOptions): Promise<MetricResult>;
|
|
10
|
-
declare function
|
|
20
|
+
declare function getChart(datasourceId: string, options: ChartOptions): Promise<ChartResult>;
|
|
11
21
|
declare const ds: {
|
|
12
22
|
list: typeof listRecords;
|
|
13
23
|
get: typeof getRecord;
|
|
@@ -15,7 +25,7 @@ declare const ds: {
|
|
|
15
25
|
update: typeof updateRecord;
|
|
16
26
|
delete: typeof deleteRecord;
|
|
17
27
|
metric: typeof getMetric;
|
|
18
|
-
|
|
28
|
+
chart: typeof getChart;
|
|
19
29
|
};
|
|
20
30
|
//#endregion
|
|
21
31
|
export { ds };
|
package/dist/core/datasource.js
CHANGED
|
@@ -3,6 +3,7 @@ import { panic } from "../assertions.js";
|
|
|
3
3
|
import { readUserTimezone } from "../cookies.js";
|
|
4
4
|
import { sessionConfig } from "../auth/config.js";
|
|
5
5
|
import { readSessionToken } from "../auth/session.js";
|
|
6
|
+
import { assertResponseOk } from "./utils.js";
|
|
6
7
|
|
|
7
8
|
//#region src/core/datasource.ts
|
|
8
9
|
const MAX_RECORD_COUNT = 100;
|
|
@@ -36,7 +37,7 @@ async function listRecords(datasourceId, options = {}) {
|
|
|
36
37
|
}
|
|
37
38
|
})
|
|
38
39
|
});
|
|
39
|
-
|
|
40
|
+
await assertResponseOk(res, `Softr datasource list failed for "${datasourceId}"`);
|
|
40
41
|
const payload = await res.json();
|
|
41
42
|
const nextOffset = payload.offset < payload.total ? payload.offset : null;
|
|
42
43
|
return {
|
|
@@ -60,13 +61,18 @@ async function getRecord(datasourceId, options) {
|
|
|
60
61
|
},
|
|
61
62
|
body: JSON.stringify({ options: { userLocale: "en-US" } })
|
|
62
63
|
});
|
|
63
|
-
|
|
64
|
+
await assertResponseOk(res, `Softr datasource get failed for "${datasourceId}"`);
|
|
64
65
|
const contentLength = res.headers.get("Content-Length");
|
|
65
66
|
if (contentLength && parseInt(contentLength, 10) === 0) return null;
|
|
66
|
-
|
|
67
|
+
const record = await res.json();
|
|
68
|
+
return {
|
|
69
|
+
id: record.id,
|
|
70
|
+
fields: options.select ? aliasFields(record.fields, options.select) : record.fields
|
|
71
|
+
};
|
|
67
72
|
}
|
|
68
73
|
return (await listRecords(datasourceId, {
|
|
69
74
|
where: options.where,
|
|
75
|
+
select: options.select,
|
|
70
76
|
limit: 1,
|
|
71
77
|
timeZone: options.timeZone
|
|
72
78
|
})).records[0] ?? null;
|
|
@@ -81,12 +87,12 @@ async function createRecord(datasourceId, options) {
|
|
|
81
87
|
},
|
|
82
88
|
body: JSON.stringify({ fields: rawFields })
|
|
83
89
|
});
|
|
84
|
-
|
|
90
|
+
await assertResponseOk(res, `Softr datasource create failed for "${datasourceId}"`);
|
|
85
91
|
const record = await res.json();
|
|
86
|
-
return
|
|
92
|
+
return {
|
|
87
93
|
id: record.id,
|
|
88
|
-
fields: aliasFields(record.fields, options.select)
|
|
89
|
-
}
|
|
94
|
+
fields: options.select ? aliasFields(record.fields, options.select) : record.fields
|
|
95
|
+
};
|
|
90
96
|
}
|
|
91
97
|
async function updateRecord(datasourceId, options) {
|
|
92
98
|
if (!options.id) throw new Error(`Softr datasource update: id must not be empty`);
|
|
@@ -99,25 +105,25 @@ async function updateRecord(datasourceId, options) {
|
|
|
99
105
|
},
|
|
100
106
|
body: JSON.stringify({ fields: rawFields })
|
|
101
107
|
});
|
|
102
|
-
|
|
108
|
+
await assertResponseOk(res, `Softr datasource update failed for "${datasourceId}"`);
|
|
103
109
|
const record = await res.json();
|
|
104
|
-
return
|
|
110
|
+
return {
|
|
105
111
|
id: record.id,
|
|
106
|
-
fields: aliasFields(record.fields, options.select)
|
|
107
|
-
}
|
|
112
|
+
fields: options.select ? aliasFields(record.fields, options.select) : record.fields
|
|
113
|
+
};
|
|
108
114
|
}
|
|
109
115
|
async function deleteRecord(datasourceId, id) {
|
|
110
|
-
|
|
116
|
+
await assertResponseOk(await fetch(`${dsUrl(datasourceId)}/records/${id}`, {
|
|
111
117
|
method: "DELETE",
|
|
112
118
|
headers: { "Authorization": `Bearer ${readSessionToken()}` }
|
|
113
|
-
});
|
|
114
|
-
if (!res.ok) throw new Error(`Softr datasource delete failed for "${datasourceId}": ${res.status}`);
|
|
119
|
+
}), `Softr datasource delete failed for "${datasourceId}"`);
|
|
115
120
|
}
|
|
116
121
|
async function getMetric(datasourceId, options) {
|
|
117
122
|
const { select, where, aggregation, field } = options;
|
|
123
|
+
if (aggregation !== "COUNT" && !field) throw new Error(`field is required for aggregation "${aggregation}"`);
|
|
118
124
|
const fieldId = field ? select?.[field] ?? field : void 0;
|
|
119
125
|
const filterCriteria = where ? dealiasFilterCriteria(buildFilterCriteria(where), select ?? {}) : {};
|
|
120
|
-
const res = await fetch(`${dsUrl(datasourceId)}/
|
|
126
|
+
const res = await fetch(`${dsUrl(datasourceId)}/chart/data`, {
|
|
121
127
|
method: "POST",
|
|
122
128
|
headers: {
|
|
123
129
|
"Content-Type": "application/json",
|
|
@@ -126,37 +132,36 @@ async function getMetric(datasourceId, options) {
|
|
|
126
132
|
},
|
|
127
133
|
body: JSON.stringify({
|
|
128
134
|
options: { userLocale: "en-US" },
|
|
129
|
-
|
|
135
|
+
groupBy: [],
|
|
136
|
+
metrics: [{
|
|
130
137
|
field: fieldId,
|
|
131
138
|
aggregation
|
|
132
|
-
},
|
|
139
|
+
}],
|
|
133
140
|
filterCriteria
|
|
134
141
|
})
|
|
135
142
|
});
|
|
136
|
-
|
|
143
|
+
await assertResponseOk(res, `Softr datasource metric failed for "${datasourceId}"`);
|
|
137
144
|
const payload = await res.json();
|
|
138
145
|
const executionTimestamp = /* @__PURE__ */ new Date(payload.executionTimestamp * 1e3);
|
|
139
146
|
let value;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (!fieldId) throw new Error(`field is required for aggregation "${aggregation}"`);
|
|
143
|
-
value = payload.data.find((item) => fieldId in item)?.[fieldId] ?? null;
|
|
144
|
-
}
|
|
147
|
+
const responseKey = aggregation === "COUNT" && !fieldId ? COUNT_CNT : fieldId;
|
|
148
|
+
value = payload.data.find((item) => responseKey in item)?.[responseKey] ?? null;
|
|
145
149
|
return {
|
|
146
150
|
value,
|
|
147
151
|
executionTimestamp
|
|
148
152
|
};
|
|
149
153
|
}
|
|
150
|
-
async function
|
|
154
|
+
async function getChart(datasourceId, options) {
|
|
151
155
|
const { select, where, groupBy, metrics, orderBy } = options;
|
|
152
156
|
const filterCriteria = where ? dealiasFilterCriteria(buildFilterCriteria(where), select ?? {}) : {};
|
|
153
|
-
const
|
|
157
|
+
const sortingOptions = orderBy ? dealiasOrderBy(buildOrderBy(orderBy), select ?? {}) : void 0;
|
|
154
158
|
const groupByFields = (Array.isArray(groupBy) ? groupBy : [groupBy]).map((field) => ({ field: select?.[field] ?? field }));
|
|
155
159
|
const yAxisFields = Object.values(metrics).map(({ field, aggregation }) => ({
|
|
156
160
|
field: field ? select?.[field] ?? field : void 0,
|
|
157
161
|
aggregation
|
|
158
162
|
}));
|
|
159
|
-
|
|
163
|
+
if (!yAxisFields.length) throw new Error("chart requires at least one metric");
|
|
164
|
+
const res = await fetch(`${dsUrl(datasourceId)}/chart/data`, {
|
|
160
165
|
method: "POST",
|
|
161
166
|
headers: {
|
|
162
167
|
"Content-Type": "application/json",
|
|
@@ -166,12 +171,12 @@ async function getChartData(datasourceId, options) {
|
|
|
166
171
|
body: JSON.stringify({
|
|
167
172
|
options: { userLocale: "en-US" },
|
|
168
173
|
filterCriteria,
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
yAxisFields
|
|
174
|
+
sortingOptions,
|
|
175
|
+
groupBy: groupByFields,
|
|
176
|
+
metrics: yAxisFields
|
|
172
177
|
})
|
|
173
178
|
});
|
|
174
|
-
|
|
179
|
+
await assertResponseOk(res, `Softr datasource chart failed for "${datasourceId}"`);
|
|
175
180
|
const payload = await res.json();
|
|
176
181
|
const executionTimestamp = /* @__PURE__ */ new Date(payload.executionTimestamp * 1e3);
|
|
177
182
|
const aliases = {};
|
|
@@ -211,11 +216,11 @@ const ds = {
|
|
|
211
216
|
update: updateRecord,
|
|
212
217
|
delete: deleteRecord,
|
|
213
218
|
metric: getMetric,
|
|
214
|
-
|
|
219
|
+
chart: getChart
|
|
215
220
|
};
|
|
216
221
|
function withoutTrailingSlash(url) {
|
|
217
222
|
return url.replace(/\/+$/, "");
|
|
218
223
|
}
|
|
219
224
|
|
|
220
225
|
//#endregion
|
|
221
|
-
export { ds };
|
|
226
|
+
export { ds, dsUrl };
|
package/dist/core/integration.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readSessionToken } from "../auth/session.js";
|
|
2
|
+
import { dsUrl } from "./datasource.js";
|
|
2
3
|
|
|
3
4
|
//#region src/core/integration.ts
|
|
4
|
-
const BASE_URL = () => (import.meta.env.VITE_SOFTR_BASE_URL ?? "").replace(/\/$/, "");
|
|
5
5
|
async function integrationFetch(integrationId, input, init) {
|
|
6
6
|
const req = new Request(input, init);
|
|
7
7
|
if (req.signal.aborted) throw req.signal.reason ?? new DOMException("The operation was aborted.", "AbortError");
|
|
@@ -16,7 +16,7 @@ async function integrationFetch(integrationId, input, init) {
|
|
|
16
16
|
};
|
|
17
17
|
const method = req.method.toUpperCase();
|
|
18
18
|
if (method !== "GET" && method !== "HEAD" && req.body !== null) payload.body = await req.clone().text();
|
|
19
|
-
return fetch(`${
|
|
19
|
+
return fetch(`${dsUrl(integrationId)}/proxy`, {
|
|
20
20
|
method: "POST",
|
|
21
21
|
headers: {
|
|
22
22
|
"Content-Type": "application/json",
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/core/utils.ts
|
|
2
|
+
async function assertResponseOk(res, message) {
|
|
3
|
+
if (!res.ok) {
|
|
4
|
+
let fullMessage = `${message}: ${res.status}`;
|
|
5
|
+
if (process.env.NODE_ENV !== "production") {
|
|
6
|
+
const body = await res.text().catch(() => "");
|
|
7
|
+
if (body) fullMessage += `\n\n${body}`;
|
|
8
|
+
}
|
|
9
|
+
throw new Error(fullMessage);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
//#endregion
|
|
14
|
+
export { assertResponseOk };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as react0 from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/default-error-overlay.d.ts
|
|
4
|
+
type Props = {
|
|
5
|
+
error: Error;
|
|
6
|
+
reset?: () => void;
|
|
7
|
+
};
|
|
8
|
+
declare function DefaultErrorOverlay({
|
|
9
|
+
error,
|
|
10
|
+
reset
|
|
11
|
+
}: Props): react0.JSX.Element;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { DefaultErrorOverlay };
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { useRef, useState } from "react";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/default-error-overlay.tsx
|
|
5
|
+
function DefaultErrorOverlay({ error, reset }) {
|
|
6
|
+
if (process.env.NODE_ENV === "production") return /* @__PURE__ */ jsx("div", {
|
|
7
|
+
style: s.overlay,
|
|
8
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
9
|
+
style: s.card,
|
|
10
|
+
children: [
|
|
11
|
+
/* @__PURE__ */ jsx(AlertIcon, {}),
|
|
12
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h1", {
|
|
13
|
+
style: s.heading,
|
|
14
|
+
children: "Something went wrong"
|
|
15
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
16
|
+
style: s.body,
|
|
17
|
+
children: "This page couldn't be shown. Try again in a moment."
|
|
18
|
+
})] }),
|
|
19
|
+
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(RetryButton, { onClick: reset }) })
|
|
20
|
+
]
|
|
21
|
+
})
|
|
22
|
+
});
|
|
23
|
+
return /* @__PURE__ */ jsx(DevView, {
|
|
24
|
+
error,
|
|
25
|
+
reset
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function DevView({ error, reset }) {
|
|
29
|
+
return /* @__PURE__ */ jsx("div", {
|
|
30
|
+
style: s.overlay,
|
|
31
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
32
|
+
style: s.card,
|
|
33
|
+
children: [
|
|
34
|
+
/* @__PURE__ */ jsx(AlertIcon, {}),
|
|
35
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
36
|
+
/* @__PURE__ */ jsx("h1", {
|
|
37
|
+
style: s.heading,
|
|
38
|
+
children: "Something went wrong"
|
|
39
|
+
}),
|
|
40
|
+
/* @__PURE__ */ jsx("p", {
|
|
41
|
+
style: s.body,
|
|
42
|
+
children: "A render error was caught. Copy the details to the agent to help fix the issue."
|
|
43
|
+
}),
|
|
44
|
+
/* @__PURE__ */ jsx("p", {
|
|
45
|
+
style: s.note,
|
|
46
|
+
children: "Only shown in development mode."
|
|
47
|
+
})
|
|
48
|
+
] }),
|
|
49
|
+
/* @__PURE__ */ jsx("pre", {
|
|
50
|
+
style: s.message,
|
|
51
|
+
children: error.message
|
|
52
|
+
}),
|
|
53
|
+
error.stack && /* @__PURE__ */ jsx(StackTrace, { stack: error.stack }),
|
|
54
|
+
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(RetryButton, { onClick: reset }) })
|
|
55
|
+
]
|
|
56
|
+
})
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function cleanStack(stack) {
|
|
60
|
+
return stack.split("\n").slice(1).filter((line) => line.trim().startsWith("at ") && !line.includes("/node_modules/")).map((line) => line.replace(/https?:\/\/[^/]+\//, "").replace(/\?[^):]+/g, "")).join("\n");
|
|
61
|
+
}
|
|
62
|
+
function StackTrace({ stack }) {
|
|
63
|
+
const cleaned = cleanStack(stack);
|
|
64
|
+
const [open, setOpen] = useState(false);
|
|
65
|
+
const [copied, setCopied] = useState(false);
|
|
66
|
+
const ref = useRef(null);
|
|
67
|
+
if (!cleaned) return null;
|
|
68
|
+
async function copy() {
|
|
69
|
+
try {
|
|
70
|
+
await navigator.clipboard.writeText(cleaned);
|
|
71
|
+
setCopied(true);
|
|
72
|
+
setTimeout(() => setCopied(false), 1500);
|
|
73
|
+
} catch {
|
|
74
|
+
if (ref.current) getSelection()?.selectAllChildren(ref.current);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
78
|
+
style: {
|
|
79
|
+
display: "flex",
|
|
80
|
+
flexDirection: "column",
|
|
81
|
+
gap: "0.5rem"
|
|
82
|
+
},
|
|
83
|
+
children: [/* @__PURE__ */ jsxs("button", {
|
|
84
|
+
type: "button",
|
|
85
|
+
style: s.toggle,
|
|
86
|
+
"aria-expanded": open,
|
|
87
|
+
onClick: () => setOpen((v) => !v),
|
|
88
|
+
children: [/* @__PURE__ */ jsx("svg", {
|
|
89
|
+
style: {
|
|
90
|
+
width: "0.875rem",
|
|
91
|
+
height: "0.875rem",
|
|
92
|
+
flexShrink: 0,
|
|
93
|
+
transition: "transform 150ms",
|
|
94
|
+
transform: open ? "rotate(90deg)" : "none"
|
|
95
|
+
},
|
|
96
|
+
viewBox: "0 0 24 24",
|
|
97
|
+
fill: "none",
|
|
98
|
+
stroke: "currentColor",
|
|
99
|
+
strokeWidth: "2",
|
|
100
|
+
strokeLinecap: "round",
|
|
101
|
+
strokeLinejoin: "round",
|
|
102
|
+
children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" })
|
|
103
|
+
}), "Stack trace"]
|
|
104
|
+
}), open && /* @__PURE__ */ jsxs("div", {
|
|
105
|
+
style: { position: "relative" },
|
|
106
|
+
children: [/* @__PURE__ */ jsx("pre", {
|
|
107
|
+
ref,
|
|
108
|
+
style: s.stack,
|
|
109
|
+
children: cleaned
|
|
110
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
111
|
+
type: "button",
|
|
112
|
+
style: s.copy,
|
|
113
|
+
"aria-label": "Copy stack trace",
|
|
114
|
+
onClick: copy,
|
|
115
|
+
children: copied ? /* @__PURE__ */ jsx("svg", {
|
|
116
|
+
style: icon.sm,
|
|
117
|
+
viewBox: "0 0 24 24",
|
|
118
|
+
fill: "none",
|
|
119
|
+
stroke: "currentColor",
|
|
120
|
+
strokeWidth: "2",
|
|
121
|
+
strokeLinecap: "round",
|
|
122
|
+
strokeLinejoin: "round",
|
|
123
|
+
children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" })
|
|
124
|
+
}) : /* @__PURE__ */ jsxs("svg", {
|
|
125
|
+
style: icon.sm,
|
|
126
|
+
viewBox: "0 0 24 24",
|
|
127
|
+
fill: "none",
|
|
128
|
+
stroke: "currentColor",
|
|
129
|
+
strokeWidth: "2",
|
|
130
|
+
strokeLinecap: "round",
|
|
131
|
+
strokeLinejoin: "round",
|
|
132
|
+
children: [/* @__PURE__ */ jsx("rect", {
|
|
133
|
+
width: "14",
|
|
134
|
+
height: "14",
|
|
135
|
+
x: "8",
|
|
136
|
+
y: "8",
|
|
137
|
+
rx: "2",
|
|
138
|
+
ry: "2"
|
|
139
|
+
}), /* @__PURE__ */ jsx("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })]
|
|
140
|
+
})
|
|
141
|
+
})]
|
|
142
|
+
})]
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
function AlertIcon() {
|
|
146
|
+
return /* @__PURE__ */ jsx("div", {
|
|
147
|
+
style: s.alert,
|
|
148
|
+
children: /* @__PURE__ */ jsxs("svg", {
|
|
149
|
+
style: icon.md,
|
|
150
|
+
viewBox: "0 0 24 24",
|
|
151
|
+
fill: "none",
|
|
152
|
+
stroke: "currentColor",
|
|
153
|
+
strokeWidth: "2",
|
|
154
|
+
strokeLinecap: "round",
|
|
155
|
+
strokeLinejoin: "round",
|
|
156
|
+
children: [
|
|
157
|
+
/* @__PURE__ */ jsx("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" }),
|
|
158
|
+
/* @__PURE__ */ jsx("path", { d: "M12 9v4" }),
|
|
159
|
+
/* @__PURE__ */ jsx("path", { d: "M12 17h.01" })
|
|
160
|
+
]
|
|
161
|
+
})
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
function RetryButton({ onClick }) {
|
|
165
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
166
|
+
type: "button",
|
|
167
|
+
style: s.retry,
|
|
168
|
+
onClick,
|
|
169
|
+
children: [/* @__PURE__ */ jsxs("svg", {
|
|
170
|
+
style: icon.sm,
|
|
171
|
+
viewBox: "0 0 24 24",
|
|
172
|
+
fill: "none",
|
|
173
|
+
stroke: "currentColor",
|
|
174
|
+
strokeWidth: "2",
|
|
175
|
+
strokeLinecap: "round",
|
|
176
|
+
strokeLinejoin: "round",
|
|
177
|
+
children: [
|
|
178
|
+
/* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" }),
|
|
179
|
+
/* @__PURE__ */ jsx("path", { d: "M21 3v5h-5" }),
|
|
180
|
+
/* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" }),
|
|
181
|
+
/* @__PURE__ */ jsx("path", { d: "M8 16H3v5" })
|
|
182
|
+
]
|
|
183
|
+
}), "Try again"]
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
const icon = {
|
|
187
|
+
sm: {
|
|
188
|
+
width: "0.875rem",
|
|
189
|
+
height: "0.875rem"
|
|
190
|
+
},
|
|
191
|
+
md: {
|
|
192
|
+
width: "1.25rem",
|
|
193
|
+
height: "1.25rem"
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
const s = {
|
|
197
|
+
overlay: {
|
|
198
|
+
minHeight: "100vh",
|
|
199
|
+
display: "grid",
|
|
200
|
+
placeItems: "center",
|
|
201
|
+
gridTemplateColumns: "minmax(0, 1fr)",
|
|
202
|
+
padding: "1.5rem"
|
|
203
|
+
},
|
|
204
|
+
card: {
|
|
205
|
+
width: "100%",
|
|
206
|
+
maxWidth: "36rem",
|
|
207
|
+
display: "flex",
|
|
208
|
+
flexDirection: "column",
|
|
209
|
+
gap: "1.25rem",
|
|
210
|
+
padding: "1.5rem",
|
|
211
|
+
borderRadius: "calc(var(--radius, 0.625rem) + 4px)",
|
|
212
|
+
background: "var(--card, oklch(1 0 0))",
|
|
213
|
+
boxShadow: "0 0 0 1px color-mix(in oklch, var(--foreground, oklch(0.145 0 0)) 10%, transparent)"
|
|
214
|
+
},
|
|
215
|
+
alert: {
|
|
216
|
+
display: "flex",
|
|
217
|
+
alignItems: "center",
|
|
218
|
+
justifyContent: "center",
|
|
219
|
+
width: "2.5rem",
|
|
220
|
+
height: "2.5rem",
|
|
221
|
+
borderRadius: "var(--radius, 0.625rem)",
|
|
222
|
+
background: "color-mix(in oklch, var(--destructive, oklch(0.577 0.245 27.325)) 12%, transparent)",
|
|
223
|
+
color: "var(--destructive, oklch(0.577 0.245 27.325))",
|
|
224
|
+
flexShrink: 0
|
|
225
|
+
},
|
|
226
|
+
heading: {
|
|
227
|
+
margin: 0,
|
|
228
|
+
fontSize: "1rem",
|
|
229
|
+
fontWeight: 500,
|
|
230
|
+
lineHeight: 1.375
|
|
231
|
+
},
|
|
232
|
+
body: {
|
|
233
|
+
margin: "0.375rem 0 0",
|
|
234
|
+
fontSize: "0.875rem",
|
|
235
|
+
color: "var(--muted-foreground, oklch(0.556 0 0))"
|
|
236
|
+
},
|
|
237
|
+
note: {
|
|
238
|
+
margin: "0.75rem 0 0",
|
|
239
|
+
fontSize: "0.875rem",
|
|
240
|
+
color: "var(--muted-foreground, oklch(0.556 0 0))",
|
|
241
|
+
opacity: .65
|
|
242
|
+
},
|
|
243
|
+
message: {
|
|
244
|
+
margin: 0,
|
|
245
|
+
padding: "0.75rem",
|
|
246
|
+
borderRadius: "var(--radius, 0.625rem)",
|
|
247
|
+
background: "var(--muted, oklch(0.97 0 0))",
|
|
248
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
249
|
+
fontSize: "0.8125rem",
|
|
250
|
+
lineHeight: 1.6,
|
|
251
|
+
whiteSpace: "pre-wrap",
|
|
252
|
+
overflowWrap: "anywhere",
|
|
253
|
+
maxHeight: "12rem",
|
|
254
|
+
overflow: "auto"
|
|
255
|
+
},
|
|
256
|
+
toggle: {
|
|
257
|
+
display: "inline-flex",
|
|
258
|
+
alignItems: "center",
|
|
259
|
+
gap: "0.375rem",
|
|
260
|
+
height: "2rem",
|
|
261
|
+
padding: "0 0.75rem 0 0.5rem",
|
|
262
|
+
border: "1px solid var(--input, oklch(0.922 0 0))",
|
|
263
|
+
borderRadius: "var(--radius, 0.625rem)",
|
|
264
|
+
background: "var(--input-fill, oklch(1 0 0))",
|
|
265
|
+
color: "var(--primary-foreground, oklch(0.985 0 0))",
|
|
266
|
+
fontFamily: "inherit",
|
|
267
|
+
fontSize: "0.875rem",
|
|
268
|
+
fontWeight: 500,
|
|
269
|
+
cursor: "pointer",
|
|
270
|
+
userSelect: "none"
|
|
271
|
+
},
|
|
272
|
+
stack: {
|
|
273
|
+
margin: 0,
|
|
274
|
+
padding: "0.75rem",
|
|
275
|
+
paddingRight: "2.75rem",
|
|
276
|
+
borderRadius: "var(--radius, 0.625rem)",
|
|
277
|
+
background: "var(--muted, oklch(0.97 0 0))",
|
|
278
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
279
|
+
fontSize: "0.75rem",
|
|
280
|
+
lineHeight: 1.6,
|
|
281
|
+
maxHeight: "16rem",
|
|
282
|
+
overflow: "auto"
|
|
283
|
+
},
|
|
284
|
+
copy: {
|
|
285
|
+
position: "absolute",
|
|
286
|
+
top: "0.375rem",
|
|
287
|
+
right: "0.375rem",
|
|
288
|
+
display: "inline-flex",
|
|
289
|
+
alignItems: "center",
|
|
290
|
+
justifyContent: "center",
|
|
291
|
+
width: "1.75rem",
|
|
292
|
+
height: "1.75rem",
|
|
293
|
+
padding: 0,
|
|
294
|
+
border: "1px solid var(--input, oklch(0.922 0 0))",
|
|
295
|
+
borderRadius: "calc(var(--radius, 0.625rem) - 2px)",
|
|
296
|
+
background: "var(--card, oklch(1 0 0))",
|
|
297
|
+
color: "var(--muted-foreground, oklch(0.556 0 0))",
|
|
298
|
+
cursor: "pointer"
|
|
299
|
+
},
|
|
300
|
+
retry: {
|
|
301
|
+
display: "inline-flex",
|
|
302
|
+
alignItems: "center",
|
|
303
|
+
gap: "0.375rem",
|
|
304
|
+
height: "2rem",
|
|
305
|
+
padding: "0 0.75rem",
|
|
306
|
+
border: "1px solid transparent",
|
|
307
|
+
borderRadius: "var(--radius, 0.625rem)",
|
|
308
|
+
background: "var(--primary, oklch(0.205 0 0))",
|
|
309
|
+
color: "var(--primary-foreground, oklch(0.985 0 0))",
|
|
310
|
+
fontFamily: "inherit",
|
|
311
|
+
fontSize: "0.875rem",
|
|
312
|
+
fontWeight: 500,
|
|
313
|
+
cursor: "pointer",
|
|
314
|
+
userSelect: "none"
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
//#endregion
|
|
319
|
+
export { DefaultErrorOverlay };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { q } from "./core/query.js";
|
|
2
2
|
import { SoftrUserGroupId, SoftrUserGroups, User } from "./auth/user.js";
|
|
3
|
-
import { AggregationFunction,
|
|
3
|
+
import { AggregationFunction, ChartOptions, ChartResult, CreateOptions, DatasourcePermissions, DatasourceTypeMap, GetOptions, JsonValue, ListOptions, ListResult, MetricOptions, MetricResult, RecordFieldsFor, SoftrMe, SoftrPermissions, SoftrRecord, SoftrUser, UpdateOptions } from "./types.js";
|
|
4
4
|
import { Permissions } from "./auth/permissions.js";
|
|
5
5
|
import { SoftrContext } from "./auth/context.js";
|
|
6
6
|
import { AccessBehaviour, AccessCheck, AccessError, AccessReason, RouteVisibility, VisibilityHandle, defineVisibility, isAccessError, isAlreadySignedInError, isForbiddenError, isUnauthenticatedError } from "./routes/visibility.js";
|
|
7
7
|
import { getSoftrContext, initialSoftrContext, softrAuthMiddleware, useCurrentUser, usePermissions } from "./auth/isomorphic.js";
|
|
8
8
|
import { useUserTimezone } from "./timezone.js";
|
|
9
|
-
|
|
9
|
+
import { DefaultErrorOverlay } from "./default-error-overlay.js";
|
|
10
|
+
export { type AccessBehaviour, type AccessCheck, type AccessError, type AccessReason, type AggregationFunction, type ChartOptions, type ChartResult, type CreateOptions, type DatasourcePermissions, type DatasourceTypeMap, DefaultErrorOverlay, type GetOptions, type JsonValue, type ListOptions, type ListResult, type MetricOptions, type MetricResult, type Permissions, type RecordFieldsFor, type RouteVisibility, type SoftrContext, type SoftrMe, type SoftrPermissions, type SoftrRecord, type SoftrUser, type SoftrUserGroupId, type SoftrUserGroups, type UpdateOptions, type User, type VisibilityHandle, defineVisibility, getSoftrContext, initialSoftrContext, isAccessError, isAlreadySignedInError, isForbiddenError, isUnauthenticatedError, q, softrAuthMiddleware, useCurrentUser, usePermissions, useUserTimezone };
|
package/dist/index.js
CHANGED
|
@@ -2,5 +2,6 @@ import { q } from "./core/query.js";
|
|
|
2
2
|
import { defineVisibility, isAccessError, isAlreadySignedInError, isForbiddenError, isUnauthenticatedError } from "./routes/visibility.js";
|
|
3
3
|
import { getSoftrContext, initialSoftrContext, softrAuthMiddleware, useCurrentUser, usePermissions } from "./auth/isomorphic.js";
|
|
4
4
|
import { useUserTimezone } from "./timezone.js";
|
|
5
|
+
import { DefaultErrorOverlay } from "./default-error-overlay.js";
|
|
5
6
|
|
|
6
|
-
export { defineVisibility, getSoftrContext, initialSoftrContext, isAccessError, isAlreadySignedInError, isForbiddenError, isUnauthenticatedError, q, softrAuthMiddleware, useCurrentUser, usePermissions, useUserTimezone };
|
|
7
|
+
export { DefaultErrorOverlay, defineVisibility, getSoftrContext, initialSoftrContext, isAccessError, isAlreadySignedInError, isForbiddenError, isUnauthenticatedError, q, softrAuthMiddleware, useCurrentUser, usePermissions, useUserTimezone };
|