@svgrid/create-studio 0.1.4 → 0.2.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/index.mjs CHANGED
@@ -163,7 +163,13 @@ async function applyTheme(destDir, choice) {
163
163
 
164
164
  /**
165
165
  * Generate the app from a studio.config.json (the visual designer's export):
166
- * parse it, emit each screen's composed blocks, and replace the seeded example.
166
+ * the COMPLETE runnable bundle - same code path as the designer's own "Download
167
+ * .zip" - so the deploy target picked in the designer (Vercel / Netlify /
168
+ * Cloudflare / Node) gets its real adapter + config, and every driver dependency
169
+ * the generated code needs (pg / mysql2 / mssql / better-sqlite3 / libsql /
170
+ * pglite / supabase-js) is detected and added, instead of layering a partial
171
+ * set of routes on top of the static template's fixed adapter-auto/package.json.
172
+ * No static template involved for this path - the bundle is self-sufficient.
167
173
  */
168
174
  async function applyProject(destDir, projectPath) {
169
175
  const abs = resolve(process.cwd(), projectPath)
@@ -178,43 +184,13 @@ async function applyProject(destDir, projectPath) {
178
184
  }
179
185
 
180
186
  const project = studio.parseProject(json)
181
- const files = studio.emitStudioProject(project)
182
-
183
- for (const ex of ['customers', 'orders']) {
184
- await rm(join(destDir, 'src', 'routes', ex), { recursive: true, force: true })
185
- }
187
+ const files = studio.emitStudioAppBundle(project)
186
188
  for (const f of files) {
187
189
  const full = join(destDir, f.path)
188
190
  await mkdir(dirname(full), { recursive: true })
189
191
  await writeFile(full, f.contents)
190
192
  }
191
- // Add the runtime deps the generated code imports (Supabase client / SQL
192
- // drivers) so the app installs + runs turnkey.
193
- const allSource = files.map((f) => f.contents).join('\n')
194
- const DEPS = [
195
- ["from '@supabase/supabase-js'", '@supabase/supabase-js', '^2.45.0'],
196
- ["import pg from 'pg'", 'pg', '^8.11.0'],
197
- ["from 'mysql2/promise'", 'mysql2', '^3.9.0'],
198
- ["import mssql from 'mssql'", 'mssql', '^10.0.0'],
199
- ["import Database from 'better-sqlite3'", 'better-sqlite3', '^11.0.0'],
200
- ]
201
- for (const [needle, dep, version] of DEPS) {
202
- if (allSource.includes(needle)) await addDependency(destDir, dep, version)
203
- }
204
- return project.screens.map((s) => s.title)
205
- }
206
-
207
- /** Add a runtime dependency to the generated app's package.json (idempotent). */
208
- async function addDependency(destDir, name, version) {
209
- const pkgPath = join(destDir, 'package.json')
210
- if (!existsSync(pkgPath)) return
211
- try {
212
- const pkg = JSON.parse(await readFile(pkgPath, 'utf8'))
213
- pkg.dependencies = { ...pkg.dependencies, [name]: version }
214
- await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n')
215
- } catch {
216
- // leave deps as-is if package.json isn't valid JSON
217
- }
193
+ return { titles: project.screens.map((s) => s.title), deployLabel: studio.studioDeployInfo(project).label }
218
194
  }
219
195
 
220
196
  /**
@@ -349,18 +325,27 @@ async function main() {
349
325
  const themeChoice = args.project ? null : await promptTheme(args, ask, interactive)
350
326
  if (rl) rl.close()
351
327
 
352
- // 3. Scaffold.
328
+ // 3. Scaffold. --project ships a complete, self-sufficient bundle (its own
329
+ // package.json/adapter config/theme) - skip the static template for that path
330
+ // so its deploy-target choice isn't immediately overwritten by the template's
331
+ // fixed adapter-auto. --from and the default (seeded example) path still
332
+ // build on the template.
353
333
  await mkdir(destDir, { recursive: true })
354
- await copyTemplate(TEMPLATE_DIR, destDir)
355
- await setProjectName(destDir, projectName)
356
- await applyTheme(destDir, themeChoice)
334
+ if (!args.project) {
335
+ await copyTemplate(TEMPLATE_DIR, destDir)
336
+ await setProjectName(destDir, projectName)
337
+ await applyTheme(destDir, themeChoice)
338
+ }
357
339
 
358
340
  // 3b. Generate from a designer project (--project) or a schema file (--from).
359
341
  let entities = null
360
342
  let source = null
343
+ let deployLabel = null
361
344
  try {
362
345
  if (args.project) {
363
- entities = await applyProject(destDir, args.project)
346
+ const result = await applyProject(destDir, args.project)
347
+ entities = result.titles
348
+ deployLabel = result.deployLabel
364
349
  source = args.project
365
350
  } else if (args.from) {
366
351
  entities = await applyFromSchema(destDir, args.from)
@@ -374,6 +359,9 @@ async function main() {
374
359
  // 4. Next steps.
375
360
  const rel = isAbsolute(target) || target.startsWith('.') ? target : `./${target}`
376
361
  stdout.write(`\n${color('green', '✔')} Scaffolded ${color('bold', projectName)} into ${rel}\n`)
362
+ if (deployLabel) {
363
+ stdout.write(` ${color('dim', 'deploy')} ${deployLabel}\n`)
364
+ }
377
365
  if (themeChoice) {
378
366
  stdout.write(` ${color('dim', 'theme')} ${themeChoice.name}${themeChoice.dark ? ' (dark)' : ''}\n`)
379
367
  }
package/package.json CHANGED
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "name": "@svgrid/create-studio",
3
- "version": "0.1.4",
3
+ "funding": {
4
+ "type": "commercial",
5
+ "url": "https://svgrid.com/pricing"
6
+ },
7
+ "version": "0.2.0",
4
8
  "description": "Scaffold a runnable SvGrid Studio data app in one command: npm create @svgrid/studio@latest",
5
9
  "type": "module",
6
10
  "license": "MIT",
@@ -37,6 +41,6 @@
37
41
  "node": ">=18"
38
42
  },
39
43
  "dependencies": {
40
- "@svgrid/enterprise": "^2.0.4"
44
+ "@svgrid/enterprise": "^2.2.0"
41
45
  }
42
46
  }
@@ -0,0 +1,8 @@
1
+ <script lang="ts">
2
+ import EntityScreen from '$lib/EntityScreen.svelte'
3
+ import { productSchema } from '$lib/schemas'
4
+ import { productsSource, nextId } from '$lib/data'
5
+ </script>
6
+
7
+ <h1 class="st__title">Products</h1>
8
+ <EntityScreen schema={productSchema} source={productsSource} newId={() => nextId('p')} />