@svgrid/enterprise 2.3.1 → 2.3.2
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/cdn/{pdfmake-C6pyKjX0.js → pdfmake-DVbZqKeD.js} +2297 -2327
- package/dist/cdn/rolldown-runtime-DtPi1Y-2.js +13 -0
- package/dist/cdn/{smart.export-CfW2zpyq.js → smart.export-D9FF4wAB.js} +54 -51
- package/dist/cdn/svgrid-enterprise.svelte-external.js +7540 -7511
- package/dist/cdn/{vfs_fonts-BktEULEs.js → vfs_fonts-iHMTEkpG.js} +1 -1
- package/dist/designer/assets/GridMenus-CW-rnHS9.js +7 -0
- package/dist/designer/assets/SvDateTimePicker-Cygij-dr.css +1 -0
- package/dist/designer/assets/SvDateTimePicker-DOBYyLeN.js +1 -0
- package/dist/designer/assets/SvGridChart-BEDNTdc5.js +2 -0
- package/dist/designer/assets/SvGridChart-Vu4Nvjiv.css +1 -0
- package/dist/designer/assets/SvGridChartPanel-x3lzSxuf.js +10 -0
- package/dist/designer/assets/SvGridChartView-CAKhPELi.js +1 -0
- package/dist/designer/assets/SvGridDropdown-CAYG7Y-O.js +1 -0
- package/dist/designer/assets/SvGridDropdown-Crwb2P3Q.css +1 -0
- package/dist/designer/assets/SvListBox-BMSfFJJT.css +1 -0
- package/dist/designer/assets/SvListBox-BVzVfCG3.js +1 -0
- package/dist/designer/assets/chart-DHEgt4lN.js +1 -0
- package/dist/designer/assets/disclose-version-CIm4S9xS.js +2 -0
- package/dist/designer/assets/dismissable-2EZKoens.js +1 -0
- package/dist/designer/assets/dismissable-BF-9TJSd.css +1 -0
- package/dist/designer/assets/easing-zaypKrr0.js +3 -0
- package/dist/designer/assets/export-format-DwjuTfrQ.js +6 -0
- package/dist/designer/assets/{index-DsDgp9Xq.js → index-DVrv9dH6.js} +141 -3102
- package/dist/designer/assets/index-DjPp1mn7.css +1 -0
- package/dist/designer/assets/js-scroller.svelte-tHanKJx0.js +110 -0
- package/dist/designer/assets/jszip.min-CX2fPs3O.js +2 -0
- package/dist/designer/assets/pdfmake-BpIYFHoG.js +242 -0
- package/dist/designer/assets/popover-CUkLsvRX.js +1 -0
- package/dist/designer/assets/rolldown-runtime-Dd_uD5pT.js +1 -0
- package/dist/designer/assets/smart.export-CDCwbFH4.js +37 -0
- package/dist/designer/assets/src-BRKu53tV.js +2842 -0
- package/dist/designer/assets/src-DseB1VRN.css +1 -0
- package/dist/designer/assets/vfs_fonts-BV-Ul9v2.js +1 -0
- package/dist/designer/index.html +21 -2
- package/dist/node/studio.js +220 -27
- package/package.json +5 -5
- package/src/sources/introspect-supabase.ts +2 -2
- package/src/studio/emit-project.ts +1 -1
- package/src/studio/init-flow.test.ts +364 -239
- package/src/studio/init-flow.ts +409 -358
- package/dist/designer/assets/GridMenus-BtWVk9Ab.js +0 -7
- package/dist/designer/assets/SvGridChartPanel-DWlBO2SD.js +0 -10
- package/dist/designer/assets/SvGridChartView-8c8Mb4j8.js +0 -1
- package/dist/designer/assets/index-tTY_Dx4P.css +0 -1
- package/dist/designer/assets/jszip.min-fkJdmAmj.js +0 -2
- package/dist/designer/assets/pdfmake-DeCsnyl9.js +0 -242
- package/dist/designer/assets/smart.export-BZlSCE8T.js +0 -35
- package/dist/designer/assets/vfs_fonts-eX2NpmfX.js +0 -1
package/dist/designer/index.html
CHANGED
|
@@ -4,8 +4,27 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>SvGrid Studio - Designer</title>
|
|
7
|
-
<script type="module" crossorigin src="./assets/index-
|
|
8
|
-
<link rel="
|
|
7
|
+
<script type="module" crossorigin src="./assets/index-DVrv9dH6.js"></script>
|
|
8
|
+
<link rel="modulepreload" crossorigin href="./assets/rolldown-runtime-Dd_uD5pT.js">
|
|
9
|
+
<link rel="modulepreload" crossorigin href="./assets/disclose-version-CIm4S9xS.js">
|
|
10
|
+
<link rel="modulepreload" crossorigin href="./assets/export-format-DwjuTfrQ.js">
|
|
11
|
+
<link rel="modulepreload" crossorigin href="./assets/js-scroller.svelte-tHanKJx0.js">
|
|
12
|
+
<link rel="modulepreload" crossorigin href="./assets/dismissable-2EZKoens.js">
|
|
13
|
+
<link rel="modulepreload" crossorigin href="./assets/popover-CUkLsvRX.js">
|
|
14
|
+
<link rel="modulepreload" crossorigin href="./assets/SvGridDropdown-CAYG7Y-O.js">
|
|
15
|
+
<link rel="modulepreload" crossorigin href="./assets/SvDateTimePicker-DOBYyLeN.js">
|
|
16
|
+
<link rel="modulepreload" crossorigin href="./assets/easing-zaypKrr0.js">
|
|
17
|
+
<link rel="modulepreload" crossorigin href="./assets/chart-DHEgt4lN.js">
|
|
18
|
+
<link rel="modulepreload" crossorigin href="./assets/SvGridChart-BEDNTdc5.js">
|
|
19
|
+
<link rel="modulepreload" crossorigin href="./assets/src-BRKu53tV.js">
|
|
20
|
+
<link rel="modulepreload" crossorigin href="./assets/SvListBox-BVzVfCG3.js">
|
|
21
|
+
<link rel="stylesheet" crossorigin href="./assets/dismissable-BF-9TJSd.css">
|
|
22
|
+
<link rel="stylesheet" crossorigin href="./assets/SvGridDropdown-Crwb2P3Q.css">
|
|
23
|
+
<link rel="stylesheet" crossorigin href="./assets/SvDateTimePicker-Cygij-dr.css">
|
|
24
|
+
<link rel="stylesheet" crossorigin href="./assets/SvGridChart-Vu4Nvjiv.css">
|
|
25
|
+
<link rel="stylesheet" crossorigin href="./assets/src-DseB1VRN.css">
|
|
26
|
+
<link rel="stylesheet" crossorigin href="./assets/SvListBox-BMSfFJJT.css">
|
|
27
|
+
<link rel="stylesheet" crossorigin href="./assets/index-DjPp1mn7.css">
|
|
9
28
|
</head>
|
|
10
29
|
<body>
|
|
11
30
|
<div id="app"></div>
|
package/dist/node/studio.js
CHANGED
|
@@ -575,12 +575,14 @@ function parseCsv(text, delimiter) {
|
|
|
575
575
|
const s = text.charCodeAt(0) === 65279 ? text.slice(1) : text;
|
|
576
576
|
for (let i = 0; i < s.length; i++) {
|
|
577
577
|
const c = s[i];
|
|
578
|
-
if (inQuotes)
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
578
|
+
if (inQuotes) {
|
|
579
|
+
if (c === "\"") {
|
|
580
|
+
if (s[i + 1] === "\"") {
|
|
581
|
+
field += "\"";
|
|
582
|
+
i++;
|
|
583
|
+
} else inQuotes = false;
|
|
584
|
+
} else field += c;
|
|
585
|
+
} else if (c === "\"") inQuotes = true;
|
|
584
586
|
else if (c === delim) {
|
|
585
587
|
row.push(field);
|
|
586
588
|
field = "";
|
|
@@ -597,13 +599,13 @@ function parseCsv(text, delimiter) {
|
|
|
597
599
|
}
|
|
598
600
|
return rows.filter((r) => !(r.length === 1 && r[0] === ""));
|
|
599
601
|
}
|
|
600
|
-
var TRUE_SET = new Set([
|
|
602
|
+
var TRUE_SET = /* @__PURE__ */ new Set([
|
|
601
603
|
"true",
|
|
602
604
|
"yes",
|
|
603
605
|
"y",
|
|
604
606
|
"1"
|
|
605
607
|
]);
|
|
606
|
-
var FALSE_SET = new Set([
|
|
608
|
+
var FALSE_SET = /* @__PURE__ */ new Set([
|
|
607
609
|
"false",
|
|
608
610
|
"no",
|
|
609
611
|
"n",
|
|
@@ -1097,7 +1099,7 @@ function introspectOpenApi(specText) {
|
|
|
1097
1099
|
idField,
|
|
1098
1100
|
fields
|
|
1099
1101
|
});
|
|
1100
|
-
|
|
1102
|
+
const source = {
|
|
1101
1103
|
kind: "rest",
|
|
1102
1104
|
baseUrl,
|
|
1103
1105
|
path: r.collection.replace(/^\/+/, ""),
|
|
@@ -1106,6 +1108,7 @@ function introspectOpenApi(specText) {
|
|
|
1106
1108
|
idField,
|
|
1107
1109
|
...rowsPathFor(doc, r.ops.list) ? { rowsPath: rowsPathFor(doc, r.ops.list) } : {}
|
|
1108
1110
|
};
|
|
1111
|
+
sources[name] = source;
|
|
1109
1112
|
}
|
|
1110
1113
|
if (!entities.length) throw new Error("No REST resources with a readable schema were found in the document.");
|
|
1111
1114
|
return {
|
|
@@ -10806,7 +10809,7 @@ var GROUP_ORDER = {
|
|
|
10806
10809
|
function mergeSpec(spec) {
|
|
10807
10810
|
const generated = GENERATED_UI_SURFACE[spec.importName];
|
|
10808
10811
|
if (!generated) return spec;
|
|
10809
|
-
const skip = new Set([
|
|
10812
|
+
const skip = /* @__PURE__ */ new Set([
|
|
10810
10813
|
...spec.hiddenProps ?? [],
|
|
10811
10814
|
...(spec.fixed ?? []).map((f) => f.key),
|
|
10812
10815
|
"_content"
|
|
@@ -10838,7 +10841,7 @@ var UI_COMPONENT_REGISTRY = BASE_REGISTRY.map(mergeSpec);
|
|
|
10838
10841
|
function uiComponentSpec(key) {
|
|
10839
10842
|
return UI_COMPONENT_REGISTRY.find((s) => s.key === key);
|
|
10840
10843
|
}
|
|
10841
|
-
var GRID_CURATED_PROPS = new Set([
|
|
10844
|
+
var GRID_CURATED_PROPS = /* @__PURE__ */ new Set([
|
|
10842
10845
|
"data",
|
|
10843
10846
|
"columns",
|
|
10844
10847
|
"board",
|
|
@@ -10893,7 +10896,7 @@ function gridPropSurface() {
|
|
|
10893
10896
|
};
|
|
10894
10897
|
return g.props.filter((p) => !GRID_CURATED_PROPS.has(p.key)).map((p) => ({ ...p })).sort((a, b) => order[a.group ?? "common"] - order[b.group ?? "common"] || a.label.localeCompare(b.label));
|
|
10895
10898
|
}
|
|
10896
|
-
var GRID_API_UNSETTABLE = new Set([
|
|
10899
|
+
var GRID_API_UNSETTABLE = /* @__PURE__ */ new Set([
|
|
10897
10900
|
"data",
|
|
10898
10901
|
"columns",
|
|
10899
10902
|
"features",
|
|
@@ -11384,7 +11387,7 @@ function screenRenderMode(_project, screen) {
|
|
|
11384
11387
|
/** Block kinds a read-only SSR screen can host: pure renders over server-loaded
|
|
11385
11388
|
* rows. Board/calendar/scheduler (client interaction runtimes), components
|
|
11386
11389
|
* (client bindings), grids-with-extras, and containers stay SPA. */
|
|
11387
|
-
var SSR_READ_KINDS = new Set([
|
|
11390
|
+
var SSR_READ_KINDS = /* @__PURE__ */ new Set([
|
|
11388
11391
|
"chart",
|
|
11389
11392
|
"pivot",
|
|
11390
11393
|
"dashboard",
|
|
@@ -12509,7 +12512,7 @@ function syncDockPanes(screen) {
|
|
|
12509
12512
|
if (missing.length === 0 && extra.length === 0) return screen;
|
|
12510
12513
|
let dock = screen.dock;
|
|
12511
12514
|
for (const id of extra) dock = stripDockPane(dock, id);
|
|
12512
|
-
const taken = new Set([...blockIds, ...collectDockNodeIds(dock)]);
|
|
12515
|
+
const taken = /* @__PURE__ */ new Set([...blockIds, ...collectDockNodeIds(dock)]);
|
|
12513
12516
|
const genId = () => {
|
|
12514
12517
|
const id = uid("dt-", taken);
|
|
12515
12518
|
taken.add(id);
|
|
@@ -14906,12 +14909,15 @@ var isDarkTheme = (theme) => theme?.mode === "dark";
|
|
|
14906
14909
|
/** Resolve the effective `--sg-*` tokens for a project theme: the chosen preset
|
|
14907
14910
|
* (default if none) in the chosen mode, with the accent override applied. */
|
|
14908
14911
|
function resolveThemeTokens(theme) {
|
|
14909
|
-
|
|
14912
|
+
const preset = getStudioTheme(theme?.preset) ?? defaultStudioTheme;
|
|
14913
|
+
const mode = theme?.mode === "dark" ? "dark" : "light";
|
|
14914
|
+
return resolveThemeTokens$1(preset, mode, theme?.accent);
|
|
14910
14915
|
}
|
|
14911
14916
|
/** Resolve the `--sg-*` tokens for a project theme in an EXPLICIT mode (for the
|
|
14912
14917
|
* generated app's light/dark switcher, which ships both token sets). */
|
|
14913
14918
|
function resolveThemeTokensFor(theme, mode) {
|
|
14914
|
-
|
|
14919
|
+
const preset = getStudioTheme(theme?.preset) ?? defaultStudioTheme;
|
|
14920
|
+
return resolveThemeTokens$1(preset, mode, theme?.accent);
|
|
14915
14921
|
}
|
|
14916
14922
|
/** An inline `style` string (`--sg-x: y; ...; color-scheme; font-family`) for previews. */
|
|
14917
14923
|
function themeStyleString(theme) {
|
|
@@ -15800,7 +15806,7 @@ function firstGridBlockId(screen) {
|
|
|
15800
15806
|
/** Data-bound block kinds that read the screen dataset and get a DataHandle. Kept
|
|
15801
15807
|
* to the pure `allRows`-driven viz blocks; board/calendar/detail have their own
|
|
15802
15808
|
* interaction model and stay declarative. */
|
|
15803
|
-
var DATA_HANDLE_KINDS = new Set([
|
|
15809
|
+
var DATA_HANDLE_KINDS = /* @__PURE__ */ new Set([
|
|
15804
15810
|
"chart",
|
|
15805
15811
|
"kpi",
|
|
15806
15812
|
"gauge",
|
|
@@ -16417,7 +16423,7 @@ function freestandingScreenPage(screen, accessEnabled, i18nEnabled) {
|
|
|
16417
16423
|
const grid = screen.renderGrid === true;
|
|
16418
16424
|
const handleNames = handleNameMap(screen);
|
|
16419
16425
|
const wiring = hasCode ? codeWiring(screen, "RowData", grid ? "rows" : void 0) : null;
|
|
16420
|
-
const gridNames = [
|
|
16426
|
+
const gridNames = [.../* @__PURE__ */ new Set([...componentImports, ...grid ? [
|
|
16421
16427
|
"SvGrid",
|
|
16422
16428
|
"tableFeatures",
|
|
16423
16429
|
"rowSortingFeature",
|
|
@@ -16570,9 +16576,9 @@ function screenPage(schema, rawSchema, screen, resolve, rawResolve, accessEnable
|
|
|
16570
16576
|
const childSchemaVars = childList.map((c) => namesFor(c).schemaVar);
|
|
16571
16577
|
const childTypes = childList.map((c) => namesFor(c).type);
|
|
16572
16578
|
const childSourceVars = childList.map((c) => namesFor(c).sourceVar);
|
|
16573
|
-
const schemaVarImports = [
|
|
16574
|
-
const typeImports = [
|
|
16575
|
-
const dataImports = ssrData ? [] : [
|
|
16579
|
+
const schemaVarImports = [.../* @__PURE__ */ new Set([n.schemaVar, ...childSchemaVars])];
|
|
16580
|
+
const typeImports = [.../* @__PURE__ */ new Set([n.type, ...childTypes])];
|
|
16581
|
+
const dataImports = ssrData ? [] : [.../* @__PURE__ */ new Set([
|
|
16576
16582
|
n.sourceVar,
|
|
16577
16583
|
...childSourceVars,
|
|
16578
16584
|
...wantsForm ? [...lookupVars, "nextId"] : []
|
|
@@ -16831,7 +16837,7 @@ function ssrReadServerFile(schema, screen, sourceKind, accessEnabled, screenIds,
|
|
|
16831
16837
|
const children = screenChildEntities(screen.blocks, resolve);
|
|
16832
16838
|
const rbac = accessEnabled && !isSql;
|
|
16833
16839
|
const srcExpr = (s) => isSql ? `createKitDataSource<Record<string, unknown>>({ endpoint: ${jsStr("/api/" + namesFor(s).route)}, fetch })` : namesFor(s).sourceVar;
|
|
16834
|
-
const memImports = isSql ? [] : [
|
|
16840
|
+
const memImports = isSql ? [] : [.../* @__PURE__ */ new Set([n.sourceVar, ...children.map((c) => namesFor(c).sourceVar)])];
|
|
16835
16841
|
const childLoads = children.map((c) => ` const ${mdChildVar(c.name)} = (await ${srcExpr(c)}.getRows(PAGE)).rows`).join("\n");
|
|
16836
16842
|
return {
|
|
16837
16843
|
path: `src/routes/${screen.route}/+page.server.ts`,
|
|
@@ -16919,7 +16925,7 @@ function emitSsrGridScreen(schema, screen, sourceKind, accessEnabled, screenIds,
|
|
|
16919
16925
|
const src = isSql ? "source(fetch)" : n.sourceVar;
|
|
16920
16926
|
const fetchArg = isSql ? ", fetch" : "";
|
|
16921
16927
|
const enterpriseImports = isSql ? "validateAll, createKitDataSource" : "validateAll";
|
|
16922
|
-
const sourceImport = isSql ? "" : `import { ${[
|
|
16928
|
+
const sourceImport = isSql ? "" : `import { ${[.../* @__PURE__ */ new Set([n.sourceVar, ...relSourceVars]), "nextId"].join(", ")} } from '$lib/data'\n`;
|
|
16923
16929
|
const schemaImport = `import { ${n.schemaVar}${isSql ? `, type ${n.type}` : ""} } from '$lib/schemas'`;
|
|
16924
16930
|
const idConst = isSql ? "" : `\nconst ID_FIELD = ${jsStr(idField)}`;
|
|
16925
16931
|
const srcHelper = isSql ? `\n// Same-origin client over the connected /api/${n.route} route (that route runs\n// validation, RBAC, triggers + audit via createKitHandlers).\nconst source = (fetch: typeof globalThis.fetch) => createKitDataSource<${n.type}>({ endpoint: ${jsStr("/api/" + n.route)}, fetch })\n` : "";
|
|
@@ -18980,7 +18986,7 @@ function dataLayerFiles(project, sqlEntities, sources, includeUsers = false, use
|
|
|
18980
18986
|
const dialect = dzDialect(firstSql?.kind === "sql" ? firstSql.dialect : void 0);
|
|
18981
18987
|
if (!dialect) return [];
|
|
18982
18988
|
const cfg = DZ[dialect];
|
|
18983
|
-
const colImports = new Set([cfg.table]);
|
|
18989
|
+
const colImports = /* @__PURE__ */ new Set([cfg.table]);
|
|
18984
18990
|
const tableBlocks = [];
|
|
18985
18991
|
const meta = [];
|
|
18986
18992
|
for (const e of sqlEntities) {
|
|
@@ -19298,7 +19304,7 @@ function deployPlan(project) {
|
|
|
19298
19304
|
switch (project.deploy ?? "auto") {
|
|
19299
19305
|
case "vercel": return {
|
|
19300
19306
|
adapterModule: "@sveltejs/adapter-vercel",
|
|
19301
|
-
adapterDep: ["@sveltejs/adapter-vercel", "^
|
|
19307
|
+
adapterDep: ["@sveltejs/adapter-vercel", "^6.3.2"],
|
|
19302
19308
|
files: [],
|
|
19303
19309
|
cli: "npx vercel --prod",
|
|
19304
19310
|
deployScript: "vercel deploy --prod",
|
|
@@ -39238,6 +39244,134 @@ function getStarterDataset(id) {
|
|
|
39238
39244
|
return starterDatasets.find((d) => d.id === id);
|
|
39239
39245
|
}
|
|
39240
39246
|
//#endregion
|
|
39247
|
+
//#region src/sources/introspect-supabase.ts
|
|
39248
|
+
var mapOpenApiType = (prop) => {
|
|
39249
|
+
if (Array.isArray(prop.enum)) return "enum";
|
|
39250
|
+
if (prop.type === "integer" || prop.type === "number") return "number";
|
|
39251
|
+
if (prop.type === "boolean") return "boolean";
|
|
39252
|
+
return "text";
|
|
39253
|
+
};
|
|
39254
|
+
async function viaOpenApi(o, base) {
|
|
39255
|
+
let res;
|
|
39256
|
+
try {
|
|
39257
|
+
res = await o.fetch(`${base}/rest/v1/`, { headers: {
|
|
39258
|
+
apikey: o.key,
|
|
39259
|
+
Authorization: `Bearer ${o.key}`,
|
|
39260
|
+
Accept: "application/json"
|
|
39261
|
+
} });
|
|
39262
|
+
} catch {
|
|
39263
|
+
return null;
|
|
39264
|
+
}
|
|
39265
|
+
if (!res.ok) return null;
|
|
39266
|
+
let spec;
|
|
39267
|
+
try {
|
|
39268
|
+
spec = await res.json();
|
|
39269
|
+
} catch {
|
|
39270
|
+
return null;
|
|
39271
|
+
}
|
|
39272
|
+
const defs = spec?.definitions ?? spec?.components?.schemas ?? {};
|
|
39273
|
+
let def = defs[o.table];
|
|
39274
|
+
if (!def) {
|
|
39275
|
+
const key = Object.keys(defs).find((k) => k.toLowerCase() === o.table.toLowerCase());
|
|
39276
|
+
if (key) def = defs[key];
|
|
39277
|
+
}
|
|
39278
|
+
const props = def?.properties;
|
|
39279
|
+
if (!props || !Object.keys(props).length) return null;
|
|
39280
|
+
const required = Array.isArray(def.required) ? def.required : [];
|
|
39281
|
+
return Object.entries(props).map(([name, prop]) => {
|
|
39282
|
+
const desc = prop?.description ?? "";
|
|
39283
|
+
const fk = /<fk\s+table=['"]([^'"]+)['"]\s+column=['"]([^'"]+)['"]/i.exec(desc);
|
|
39284
|
+
return {
|
|
39285
|
+
name,
|
|
39286
|
+
type: mapOpenApiType(prop),
|
|
39287
|
+
primaryKey: /primary key|<pk\/>/i.test(desc),
|
|
39288
|
+
required: required.includes(name),
|
|
39289
|
+
enumValues: Array.isArray(prop?.enum) ? prop.enum : void 0,
|
|
39290
|
+
references: fk ? {
|
|
39291
|
+
table: fk[1],
|
|
39292
|
+
column: fk[2]
|
|
39293
|
+
} : void 0
|
|
39294
|
+
};
|
|
39295
|
+
});
|
|
39296
|
+
}
|
|
39297
|
+
async function viaCsv(o, base) {
|
|
39298
|
+
let res;
|
|
39299
|
+
try {
|
|
39300
|
+
res = await o.fetch(`${base}/rest/v1/${encodeURIComponent(o.table)}?select=*&limit=1`, { headers: {
|
|
39301
|
+
apikey: o.key,
|
|
39302
|
+
Authorization: `Bearer ${o.key}`,
|
|
39303
|
+
Accept: "text/csv"
|
|
39304
|
+
} });
|
|
39305
|
+
} catch {
|
|
39306
|
+
return null;
|
|
39307
|
+
}
|
|
39308
|
+
if (!res.ok) return null;
|
|
39309
|
+
const names = ((await res.text()).trim().split(/\r?\n/)[0] ?? "").split(",").map((h) => h.trim().replace(/^"|"$/g, "")).filter(Boolean);
|
|
39310
|
+
return names.length ? names.map((name) => ({ name })) : null;
|
|
39311
|
+
}
|
|
39312
|
+
async function viaSample(o, base) {
|
|
39313
|
+
let res;
|
|
39314
|
+
try {
|
|
39315
|
+
res = await o.fetch(`${base}/rest/v1/${encodeURIComponent(o.table)}?select=*&limit=1`, { headers: {
|
|
39316
|
+
apikey: o.key,
|
|
39317
|
+
Authorization: `Bearer ${o.key}`,
|
|
39318
|
+
Accept: "application/json"
|
|
39319
|
+
} });
|
|
39320
|
+
} catch {
|
|
39321
|
+
return null;
|
|
39322
|
+
}
|
|
39323
|
+
if (!res.ok) return null;
|
|
39324
|
+
let rows;
|
|
39325
|
+
try {
|
|
39326
|
+
rows = await res.json();
|
|
39327
|
+
} catch {
|
|
39328
|
+
return null;
|
|
39329
|
+
}
|
|
39330
|
+
const sample = Array.isArray(rows) ? rows[0] : void 0;
|
|
39331
|
+
if (!sample) return null;
|
|
39332
|
+
return Object.entries(sample).map(([name, v]) => ({
|
|
39333
|
+
name,
|
|
39334
|
+
type: typeof v === "number" ? "number" : typeof v === "boolean" ? "boolean" : "text"
|
|
39335
|
+
}));
|
|
39336
|
+
}
|
|
39337
|
+
/** List a Supabase project's tables from its PostgREST OpenAPI doc (URL + anon key).
|
|
39338
|
+
* Returns the exposed table names (sorted), or `[]` when the doc can't be read
|
|
39339
|
+
* (CORS-blocked, bad key). Lets the Studio wizard offer a table picker instead of
|
|
39340
|
+
* making the user hand-type the table name. */
|
|
39341
|
+
async function listSupabaseTables(url, key, fetchFn = globalThis.fetch) {
|
|
39342
|
+
const base = url.replace(/\/+$/, "");
|
|
39343
|
+
let res;
|
|
39344
|
+
try {
|
|
39345
|
+
res = await fetchFn(`${base}/rest/v1/`, { headers: {
|
|
39346
|
+
apikey: key,
|
|
39347
|
+
Authorization: `Bearer ${key}`,
|
|
39348
|
+
Accept: "application/json"
|
|
39349
|
+
} });
|
|
39350
|
+
} catch {
|
|
39351
|
+
return [];
|
|
39352
|
+
}
|
|
39353
|
+
if (!res.ok) return [];
|
|
39354
|
+
let spec;
|
|
39355
|
+
try {
|
|
39356
|
+
spec = await res.json();
|
|
39357
|
+
} catch {
|
|
39358
|
+
return [];
|
|
39359
|
+
}
|
|
39360
|
+
const defs = spec?.definitions ?? spec?.components?.schemas ?? {};
|
|
39361
|
+
return Object.keys(defs).sort((a, b) => a.localeCompare(b));
|
|
39362
|
+
}
|
|
39363
|
+
/** Introspect a Supabase/PostgREST table into an EntitySchema, or null. */
|
|
39364
|
+
async function introspectSupabaseTable(options) {
|
|
39365
|
+
const o = {
|
|
39366
|
+
fetch: globalThis.fetch,
|
|
39367
|
+
...options
|
|
39368
|
+
};
|
|
39369
|
+
const base = o.url.replace(/\/+$/, "");
|
|
39370
|
+
const columns = await viaOpenApi(o, base) ?? await viaSample(o, base) ?? await viaCsv(o, base);
|
|
39371
|
+
if (!columns || !columns.length) return null;
|
|
39372
|
+
return buildEntitySchema(o.table, columns);
|
|
39373
|
+
}
|
|
39374
|
+
//#endregion
|
|
39241
39375
|
//#region src/studio/init-flow.ts
|
|
39242
39376
|
var SOURCES = [
|
|
39243
39377
|
{
|
|
@@ -39250,6 +39384,11 @@ var SOURCES = [
|
|
|
39250
39384
|
label: "An existing database",
|
|
39251
39385
|
hint: "Postgres, MySQL, SQL Server or SQLite - reads your tables"
|
|
39252
39386
|
},
|
|
39387
|
+
{
|
|
39388
|
+
key: "supabase",
|
|
39389
|
+
label: "Supabase",
|
|
39390
|
+
hint: "project URL + anon key, read over the REST API - no driver needed"
|
|
39391
|
+
},
|
|
39253
39392
|
{
|
|
39254
39393
|
key: "pglite",
|
|
39255
39394
|
label: "Local Postgres in the browser (PGlite)",
|
|
@@ -39322,9 +39461,11 @@ function unwrapRows(body) {
|
|
|
39322
39461
|
async function gatherData(flags, prompts, db, fetchText) {
|
|
39323
39462
|
let source = "sample";
|
|
39324
39463
|
if (flags.db) source = "db";
|
|
39464
|
+
else if (flags.supabaseUrl) source = "supabase";
|
|
39325
39465
|
else if (flags.dataset) source = "sample";
|
|
39326
39466
|
else if (!flags.yes) source = SOURCES[await pick(prompts, "Where should the app get its data?", [...SOURCES])].key;
|
|
39327
39467
|
if (source === "db") return gatherFromDatabase(flags, prompts, db);
|
|
39468
|
+
if (source === "supabase") return gatherFromSupabase(flags, prompts);
|
|
39328
39469
|
if (source === "rest") return gatherFromRest(prompts, fetchText);
|
|
39329
39470
|
let datasetId = flags.dataset ?? starterDatasets[0].id;
|
|
39330
39471
|
if (!flags.dataset && !flags.yes) datasetId = starterDatasets[await pick(prompts, "Pick a starter dataset:", starterDatasets.map((d) => ({
|
|
@@ -39354,8 +39495,10 @@ async function gatherFromDatabase(flags, prompts, db) {
|
|
|
39354
39495
|
let dialect = flags.db;
|
|
39355
39496
|
if (!dialect) dialect = DIALECTS[await pick(prompts, "Which database?", DIALECTS.map((d) => ({ label: d })))];
|
|
39356
39497
|
let url = flags.url ?? "";
|
|
39357
|
-
if (!url)
|
|
39358
|
-
|
|
39498
|
+
if (!url) {
|
|
39499
|
+
if (isFileDialect(dialect)) url = (await prompts.ask("Database file:", "./data.db")).trim();
|
|
39500
|
+
else url = (await prompts.ask("Connection string (blank to enter host/port instead):", "")).trim() || buildConnectionString(dialect, await askConnectionParts(prompts));
|
|
39501
|
+
}
|
|
39359
39502
|
if (!url) throw new Error("A connection string is required.");
|
|
39360
39503
|
const driver = await db.ensureDriver(dialect);
|
|
39361
39504
|
if (!driver.ok) throw new Error(driver.message ?? `Could not install the ${dialect} driver.`);
|
|
@@ -39395,6 +39538,56 @@ async function gatherFromDatabase(flags, prompts, db) {
|
|
|
39395
39538
|
kind: "sql"
|
|
39396
39539
|
};
|
|
39397
39540
|
}
|
|
39541
|
+
/**
|
|
39542
|
+
* Supabase reads over its own REST API, so this needs no driver and no
|
|
39543
|
+
* DbGateway - just the project URL and the anon key.
|
|
39544
|
+
*/
|
|
39545
|
+
async function gatherFromSupabase(flags, prompts) {
|
|
39546
|
+
const url = (flags.supabaseUrl ?? await prompts.ask("Project URL:", "")).trim();
|
|
39547
|
+
const key = (flags.supabaseKey ?? await prompts.ask("Anon key:", "")).trim();
|
|
39548
|
+
if (!url || !key) throw new Error("Both the project URL and the anon key are required.");
|
|
39549
|
+
prompts.say(" Reading the API...");
|
|
39550
|
+
const tables = await listSupabaseTables(url, key);
|
|
39551
|
+
let picked;
|
|
39552
|
+
if (tables.length) {
|
|
39553
|
+
prompts.say("");
|
|
39554
|
+
prompts.say(`Found ${tables.length} ${tables.length === 1 ? "table" : "tables"}:`);
|
|
39555
|
+
tables.forEach((t, i) => prompts.say(` ${i + 1}. ${t}`));
|
|
39556
|
+
picked = parseSelection(flags.yes ? "all" : await prompts.ask("Which tables? (all, or a comma list of names/numbers)", "all"), tables);
|
|
39557
|
+
} else {
|
|
39558
|
+
prompts.say(" Couldn't list the tables (the API doc may be restricted for this key).");
|
|
39559
|
+
picked = (await prompts.ask("Table names (comma separated):", "")).split(",").map((t) => t.trim()).filter(Boolean);
|
|
39560
|
+
}
|
|
39561
|
+
if (picked.length === 0) throw new Error("No tables picked - nothing to build.");
|
|
39562
|
+
const schemas = [];
|
|
39563
|
+
const sources = {};
|
|
39564
|
+
for (const table of picked) {
|
|
39565
|
+
const schema = await introspectSupabaseTable({
|
|
39566
|
+
url,
|
|
39567
|
+
key,
|
|
39568
|
+
table
|
|
39569
|
+
});
|
|
39570
|
+
if (!schema?.fields.length) {
|
|
39571
|
+
prompts.say(` ! Skipped ${table}: no columns could be read.`);
|
|
39572
|
+
continue;
|
|
39573
|
+
}
|
|
39574
|
+
schemas.push(schema);
|
|
39575
|
+
sources[schema.name] = {
|
|
39576
|
+
kind: "supabase",
|
|
39577
|
+
table,
|
|
39578
|
+
url,
|
|
39579
|
+
key
|
|
39580
|
+
};
|
|
39581
|
+
}
|
|
39582
|
+
if (schemas.length === 0) throw new Error("None of the picked tables could be read.");
|
|
39583
|
+
prompts.say(` Read ${schemas.length} ${schemas.length === 1 ? "table" : "tables"}.`);
|
|
39584
|
+
return {
|
|
39585
|
+
schemas,
|
|
39586
|
+
sources,
|
|
39587
|
+
seed: {},
|
|
39588
|
+
kind: "supabase"
|
|
39589
|
+
};
|
|
39590
|
+
}
|
|
39398
39591
|
async function askConnectionParts(prompts) {
|
|
39399
39592
|
return {
|
|
39400
39593
|
host: (await prompts.ask("Host:", "localhost")).trim(),
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"type": "commercial",
|
|
5
5
|
"url": "https://svgrid.com/pricing"
|
|
6
6
|
},
|
|
7
|
-
"version": "2.3.
|
|
7
|
+
"version": "2.3.2",
|
|
8
8
|
"description": "Enterprise feature pack for SvGrid: Excel (xlsx), PDF, CSV, TSV and HTML export, Excel/CSV/JSON import, pivot tables with a drag-and-drop designer, paginated print, Kanban board and scheduler views. Requires a paid license key.",
|
|
9
9
|
"license": "SEE LICENSE IN LICENSE",
|
|
10
10
|
"author": "jQWidgets <sales@jqwidgets.com>",
|
|
@@ -62,10 +62,10 @@
|
|
|
62
62
|
"access": "public"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
|
-
"svelte": "^5.0.0",
|
|
66
65
|
"jszip": "^3.10.0",
|
|
67
66
|
"pdfmake": "^0.2.0",
|
|
68
|
-
"
|
|
67
|
+
"svelte": "^5.0.0",
|
|
68
|
+
"@svgrid/grid": "^2.2.33"
|
|
69
69
|
},
|
|
70
70
|
"peerDependenciesMeta": {
|
|
71
71
|
"jszip": {
|
|
@@ -81,8 +81,8 @@
|
|
|
81
81
|
"pdfmake": "^0.2.10",
|
|
82
82
|
"svelte": "^5.55.5",
|
|
83
83
|
"typescript": "6.0.3",
|
|
84
|
-
"vite": "^8.
|
|
85
|
-
"@svgrid/grid": "^2.2.
|
|
84
|
+
"vite": "^8.2.1",
|
|
85
|
+
"@svgrid/grid": "^2.2.33"
|
|
86
86
|
},
|
|
87
87
|
"repository": {
|
|
88
88
|
"type": "git",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
* whose OpenAPI is blocked) - the caller can then ask the user to list columns.
|
|
12
12
|
*/
|
|
13
13
|
import type { RowData } from '@svgrid/grid'
|
|
14
|
-
import type { EntityFieldType, EntitySchema } from '../schema'
|
|
15
|
-
import { buildEntitySchema, type IntrospectedColumn } from './schema-from-columns'
|
|
14
|
+
import type { EntityFieldType, EntitySchema } from '../schema.js'
|
|
15
|
+
import { buildEntitySchema, type IntrospectedColumn } from './schema-from-columns.js'
|
|
16
16
|
|
|
17
17
|
export type IntrospectSupabaseOptions = {
|
|
18
18
|
/** Project URL, e.g. `https://xxxx.supabase.co`. */
|
|
@@ -4671,7 +4671,7 @@ function deployPlan(project: StudioProject): DeployPlan {
|
|
|
4671
4671
|
case 'vercel':
|
|
4672
4672
|
return {
|
|
4673
4673
|
adapterModule: '@sveltejs/adapter-vercel',
|
|
4674
|
-
adapterDep: ['@sveltejs/adapter-vercel', '^
|
|
4674
|
+
adapterDep: ['@sveltejs/adapter-vercel', '^6.3.2'],
|
|
4675
4675
|
files: [],
|
|
4676
4676
|
cli: 'npx vercel --prod',
|
|
4677
4677
|
deployScript: 'vercel deploy --prod',
|