@svgrid/enterprise 2.3.1 → 2.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.
Files changed (48) hide show
  1. package/dist/cdn/{pdfmake-C6pyKjX0.js → pdfmake-DVbZqKeD.js} +2297 -2327
  2. package/dist/cdn/rolldown-runtime-DtPi1Y-2.js +13 -0
  3. package/dist/cdn/{smart.export-CfW2zpyq.js → smart.export-D9FF4wAB.js} +54 -51
  4. package/dist/cdn/svgrid-enterprise.svelte-external.js +7540 -7511
  5. package/dist/cdn/{vfs_fonts-BktEULEs.js → vfs_fonts-iHMTEkpG.js} +1 -1
  6. package/dist/designer/assets/GridMenus-CW-rnHS9.js +7 -0
  7. package/dist/designer/assets/SvDateTimePicker-Cygij-dr.css +1 -0
  8. package/dist/designer/assets/SvDateTimePicker-DOBYyLeN.js +1 -0
  9. package/dist/designer/assets/SvGridChart-BEDNTdc5.js +2 -0
  10. package/dist/designer/assets/SvGridChart-Vu4Nvjiv.css +1 -0
  11. package/dist/designer/assets/SvGridChartPanel-x3lzSxuf.js +10 -0
  12. package/dist/designer/assets/SvGridChartView-CAKhPELi.js +1 -0
  13. package/dist/designer/assets/SvGridDropdown-CAYG7Y-O.js +1 -0
  14. package/dist/designer/assets/SvGridDropdown-Crwb2P3Q.css +1 -0
  15. package/dist/designer/assets/SvListBox-BMSfFJJT.css +1 -0
  16. package/dist/designer/assets/SvListBox-BVzVfCG3.js +1 -0
  17. package/dist/designer/assets/chart-DHEgt4lN.js +1 -0
  18. package/dist/designer/assets/disclose-version-CIm4S9xS.js +2 -0
  19. package/dist/designer/assets/dismissable-2EZKoens.js +1 -0
  20. package/dist/designer/assets/dismissable-BF-9TJSd.css +1 -0
  21. package/dist/designer/assets/easing-zaypKrr0.js +3 -0
  22. package/dist/designer/assets/export-format-DwjuTfrQ.js +6 -0
  23. package/dist/designer/assets/index-oYok52zd.css +1 -0
  24. package/dist/designer/assets/{index-DsDgp9Xq.js → index-okIcRP9P.js} +141 -3102
  25. package/dist/designer/assets/js-scroller.svelte-tHanKJx0.js +110 -0
  26. package/dist/designer/assets/jszip.min-CX2fPs3O.js +2 -0
  27. package/dist/designer/assets/pdfmake-BpIYFHoG.js +242 -0
  28. package/dist/designer/assets/popover-CUkLsvRX.js +1 -0
  29. package/dist/designer/assets/rolldown-runtime-Dd_uD5pT.js +1 -0
  30. package/dist/designer/assets/smart.export-CDCwbFH4.js +37 -0
  31. package/dist/designer/assets/src-BvsJ00AO.css +1 -0
  32. package/dist/designer/assets/src-CIla2aVG.js +2842 -0
  33. package/dist/designer/assets/vfs_fonts-BV-Ul9v2.js +1 -0
  34. package/dist/designer/index.html +21 -2
  35. package/dist/node/studio.js +220 -27
  36. package/package.json +5 -5
  37. package/src/sources/introspect-supabase.ts +2 -2
  38. package/src/studio/emit-project.ts +1 -1
  39. package/src/studio/init-flow.test.ts +364 -239
  40. package/src/studio/init-flow.ts +409 -358
  41. package/dist/designer/assets/GridMenus-BtWVk9Ab.js +0 -7
  42. package/dist/designer/assets/SvGridChartPanel-DWlBO2SD.js +0 -10
  43. package/dist/designer/assets/SvGridChartView-8c8Mb4j8.js +0 -1
  44. package/dist/designer/assets/index-tTY_Dx4P.css +0 -1
  45. package/dist/designer/assets/jszip.min-fkJdmAmj.js +0 -2
  46. package/dist/designer/assets/pdfmake-DeCsnyl9.js +0 -242
  47. package/dist/designer/assets/smart.export-BZlSCE8T.js +0 -35
  48. package/dist/designer/assets/vfs_fonts-eX2NpmfX.js +0 -1
@@ -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-DsDgp9Xq.js"></script>
8
- <link rel="stylesheet" crossorigin href="./assets/index-tTY_Dx4P.css">
7
+ <script type="module" crossorigin src="./assets/index-okIcRP9P.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/SvDateTimePicker-DOBYyLeN.js">
15
+ <link rel="modulepreload" crossorigin href="./assets/SvGridDropdown-CAYG7Y-O.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-CIla2aVG.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/SvDateTimePicker-Cygij-dr.css">
23
+ <link rel="stylesheet" crossorigin href="./assets/SvGridDropdown-Crwb2P3Q.css">
24
+ <link rel="stylesheet" crossorigin href="./assets/SvGridChart-Vu4Nvjiv.css">
25
+ <link rel="stylesheet" crossorigin href="./assets/src-BvsJ00AO.css">
26
+ <link rel="stylesheet" crossorigin href="./assets/SvListBox-BMSfFJJT.css">
27
+ <link rel="stylesheet" crossorigin href="./assets/index-oYok52zd.css">
9
28
  </head>
10
29
  <body>
11
30
  <div id="app"></div>
@@ -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) if (c === "\"") if (s[i + 1] === "\"") {
579
- field += "\"";
580
- i++;
581
- } else inQuotes = false;
582
- else field += c;
583
- else if (c === "\"") inQuotes = true;
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
- sources[name] = {
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
- return resolveThemeTokens$1(getStudioTheme(theme?.preset) ?? defaultStudioTheme, theme?.mode === "dark" ? "dark" : "light", theme?.accent);
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
- return resolveThemeTokens$1(getStudioTheme(theme?.preset) ?? defaultStudioTheme, mode, theme?.accent);
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 = [...new Set([...componentImports, ...grid ? [
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 = [...new Set([n.schemaVar, ...childSchemaVars])];
16574
- const typeImports = [...new Set([n.type, ...childTypes])];
16575
- const dataImports = ssrData ? [] : [...new Set([
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 ? [] : [...new Set([n.sourceVar, ...children.map((c) => namesFor(c).sourceVar)])];
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 { ${[...new Set([n.sourceVar, ...relSourceVars]), "nextId"].join(", ")} } from '$lib/data'\n`;
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", "^5.5.0"],
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) if (isFileDialect(dialect)) url = (await prompts.ask("Database file:", "./data.db")).trim();
39358
- else url = (await prompts.ask("Connection string (blank to enter host/port instead):", "")).trim() || buildConnectionString(dialect, await askConnectionParts(prompts));
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.1",
7
+ "version": "2.4.0",
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
- "@svgrid/grid": "^2.2.31"
67
+ "svelte": "^5.0.0",
68
+ "@svgrid/grid": "^2.4.0"
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.0.10",
85
- "@svgrid/grid": "^2.2.31"
84
+ "vite": "^8.2.1",
85
+ "@svgrid/grid": "^2.4.0"
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', '^5.5.0'],
4674
+ adapterDep: ['@sveltejs/adapter-vercel', '^6.3.2'],
4675
4675
  files: [],
4676
4676
  cli: 'npx vercel --prod',
4677
4677
  deployScript: 'vercel deploy --prod',