@weft-js/create 0.1.0 → 0.1.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/README.md +60 -10
- package/bin/create-weft.mjs +62 -14
- package/package.json +26 -16
- package/scripts/tarballs.mjs +56 -6
- package/src/data.mjs +90 -18
- package/src/index.mjs +210 -51
- package/src/stack/pages.mjs +151 -0
- package/src/stack/schema.mjs +195 -0
- package/src/stack.mjs +102 -313
- package/src/templates.mjs +174 -0
- package/src/wizard.mjs +65 -16
- package/templates/admin/files/drizzle/.schema-hash +1 -0
- package/templates/admin/files/drizzle/0000_admin.sql +136 -0
- package/templates/admin/files/drizzle/meta/0000_snapshot.json +771 -0
- package/templates/admin/files/drizzle/meta/_journal.json +13 -0
- package/templates/admin/files/public/favicon.svg +1 -0
- package/templates/admin/files/src/auth.server.ts +24 -0
- package/templates/admin/files/src/components/AuthPage.tsx +33 -0
- package/templates/admin/files/src/components/Failed.tsx +19 -0
- package/templates/admin/files/src/components/Logo.tsx +16 -0
- package/templates/admin/files/src/components/OrderDetail.tsx +93 -0
- package/templates/admin/files/src/components/OrdersFilters.tsx +44 -0
- package/templates/admin/files/src/components/OrdersTable.tsx +144 -0
- package/templates/admin/files/src/components/Overview.tsx +113 -0
- package/templates/admin/files/src/components/StatusBadge.tsx +12 -0
- package/templates/admin/files/src/db/schema.ts +68 -0
- package/templates/admin/files/src/lib/orders.ts +60 -0
- package/templates/admin/files/src/routes/404.tsx +20 -0
- package/templates/admin/files/src/routes/_error.tsx +20 -0
- package/templates/admin/files/src/routes/_layout.tsx +6 -0
- package/templates/admin/files/src/routes/admin/_layout.tsx +89 -0
- package/templates/admin/files/src/routes/admin/index.tsx +45 -0
- package/templates/admin/files/src/routes/admin/nested/_layout.tsx +35 -0
- package/templates/admin/files/src/routes/admin/nested/index.tsx +77 -0
- package/templates/admin/files/src/routes/admin/orders/[id].tsx +24 -0
- package/templates/admin/files/src/routes/admin/orders/index.tsx +28 -0
- package/templates/admin/files/src/routes/admin/per-row.tsx +81 -0
- package/templates/admin/files/src/routes/admin/slow.tsx +74 -0
- package/templates/admin/files/src/routes/index.tsx +13 -0
- package/templates/admin/files/src/routes/login.tsx +53 -0
- package/templates/admin/files/src/routes/signup.tsx +60 -0
- package/templates/admin/files/src/server/orders.ts +193 -0
- package/templates/admin/files/src/server/reports.ts +92 -0
- package/templates/admin/files/src/server/session.ts +42 -0
- package/templates/admin/files/src/theme.css +43 -0
- package/templates/admin/files/weft.config.ts +31 -0
- package/templates/admin/template.json +22 -0
- package/templates/catalog/files/drizzle/.schema-hash +1 -0
- package/templates/catalog/files/drizzle/0000_catalog.sql +47 -0
- package/templates/catalog/files/drizzle/meta/0000_snapshot.json +263 -0
- package/templates/catalog/files/drizzle/meta/_journal.json +13 -0
- package/templates/catalog/files/public/favicon.svg +1 -0
- package/templates/catalog/files/seed.sql +13 -0
- package/templates/catalog/files/src/components/AddToCart.tsx +22 -0
- package/templates/catalog/files/src/components/Aisles.tsx +31 -0
- package/templates/catalog/files/src/components/CartLines.tsx +96 -0
- package/templates/catalog/files/src/components/CartLink.tsx +29 -0
- package/templates/catalog/files/src/components/Failed.tsx +19 -0
- package/templates/catalog/files/src/components/Featured.tsx +19 -0
- package/templates/catalog/files/src/components/Filters.tsx +40 -0
- package/templates/catalog/files/src/components/Logo.tsx +16 -0
- package/templates/catalog/files/src/components/ProductArt.tsx +42 -0
- package/templates/catalog/files/src/components/ProductCard.tsx +42 -0
- package/templates/catalog/files/src/components/ProductList.tsx +65 -0
- package/templates/catalog/files/src/components/Related.tsx +19 -0
- package/templates/catalog/files/src/components/SiteFooter.tsx +9 -0
- package/templates/catalog/files/src/components/SiteHeader.tsx +16 -0
- package/templates/catalog/files/src/db/schema.ts +53 -0
- package/templates/catalog/files/src/lib/catalog.ts +35 -0
- package/templates/catalog/files/src/routes/404.tsx +18 -0
- package/templates/catalog/files/src/routes/_error.tsx +18 -0
- package/templates/catalog/files/src/routes/_layout.tsx +14 -0
- package/templates/catalog/files/src/routes/c/[slug].tsx +53 -0
- package/templates/catalog/files/src/routes/cart.tsx +29 -0
- package/templates/catalog/files/src/routes/index.tsx +84 -0
- package/templates/catalog/files/src/routes/p/[slug].tsx +67 -0
- package/templates/catalog/files/src/server/cart.ts +125 -0
- package/templates/catalog/files/src/server/catalog.ts +107 -0
- package/templates/catalog/files/src/theme.css +159 -0
- package/templates/catalog/files/weft.config.ts +30 -0
- package/templates/catalog/template.json +20 -0
- package/templates/landing/files/.weft/plugins.lock.json +42 -0
- package/templates/landing/files/assets/fonts/LICENSE-figtree.txt +93 -0
- package/templates/landing/files/assets/fonts/figtree.woff2 +0 -0
- package/templates/landing/files/assets/hero.webp +0 -0
- package/templates/landing/files/drizzle/.schema-hash +1 -0
- package/templates/landing/files/drizzle/0000_landing.sql +6 -0
- package/templates/landing/files/drizzle/meta/0000_snapshot.json +60 -0
- package/templates/landing/files/drizzle/meta/_journal.json +13 -0
- package/templates/landing/files/public/favicon.svg +1 -0
- package/templates/landing/files/src/components/SiteFooter.tsx +24 -0
- package/templates/landing/files/src/components/SiteHeader.tsx +23 -0
- package/templates/landing/files/src/components/WaitlistForm.tsx +36 -0
- package/templates/landing/files/src/db/schema.ts +7 -0
- package/templates/landing/files/src/routes/404.tsx +24 -0
- package/templates/landing/files/src/routes/_error.tsx +24 -0
- package/templates/landing/files/src/routes/_layout.tsx +14 -0
- package/templates/landing/files/src/routes/index.tsx +130 -0
- package/templates/landing/files/src/routes/joined.tsx +30 -0
- package/templates/landing/files/src/routes/pricing.tsx +131 -0
- package/templates/landing/files/src/routes/privacy.tsx +56 -0
- package/templates/landing/files/src/server/waitlist.ts +13 -0
- package/templates/landing/files/src/theme.css +108 -0
- package/templates/landing/files/weft.config.ts +44 -0
- package/templates/landing/template.json +17 -0
- package/templates/todo/files/drizzle/.schema-hash +1 -0
- package/templates/todo/files/drizzle/0000_todo.sql +82 -0
- package/templates/todo/files/drizzle/meta/0000_snapshot.json +462 -0
- package/templates/todo/files/drizzle/meta/_journal.json +13 -0
- package/templates/todo/files/public/favicon.svg +1 -0
- package/templates/todo/files/src/components/AuthPage.tsx +33 -0
- package/templates/todo/files/src/components/Logo.tsx +14 -0
- package/templates/todo/files/src/components/NewTodo.tsx +27 -0
- package/templates/todo/files/src/components/TodoList.tsx +101 -0
- package/templates/todo/files/src/db/schema.ts +18 -0
- package/templates/todo/files/src/lib/views.ts +13 -0
- package/templates/todo/files/src/routes/404.tsx +20 -0
- package/templates/todo/files/src/routes/_error.tsx +20 -0
- package/templates/todo/files/src/routes/_layout.tsx +6 -0
- package/templates/todo/files/src/routes/index.tsx +13 -0
- package/templates/todo/files/src/routes/login.tsx +53 -0
- package/templates/todo/files/src/routes/signup.tsx +57 -0
- package/templates/todo/files/src/routes/todos.tsx +87 -0
- package/templates/todo/files/src/server/todos.ts +98 -0
- package/templates/todo/files/src/theme.css +71 -0
- package/templates/todo/files/weft.config.ts +30 -0
- package/templates/todo/template.json +18 -0
package/README.md
CHANGED
|
@@ -1,28 +1,78 @@
|
|
|
1
1
|
# @weft-js/create
|
|
2
2
|
|
|
3
|
-
> **Early release (0.1.
|
|
3
|
+
> **Early release (0.1.x).** APIs can change between minor versions.
|
|
4
4
|
|
|
5
|
-
Starts a new weft app
|
|
5
|
+
Starts a new [Weft](https://github.com/Ravonus/weft) app: pages, a server, a database, sign-in and Warp's components,
|
|
6
|
+
wired up and ready for `weft dev`.
|
|
6
7
|
|
|
7
8
|
```bash
|
|
8
9
|
npm create @weft-js my-app
|
|
9
10
|
```
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
```bash
|
|
13
|
+
pnpm create @weft-js my-app
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
bun create @weft-js my-app
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
deno run -A npm:@weft-js/create my-app
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
In a terminal it asks what the flags don't answer, with the default already picked. `--yes` takes every default: Warp,
|
|
25
|
+
SQLite through Drizzle, and Better Auth. Then:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
cd my-app
|
|
29
|
+
npx weft dev
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
With a database, run `npx weft db generate` first. The new app has a home page, an about page, a todo list on server
|
|
33
|
+
functions, a sign-in page, and an `AGENTS.md` written for the installed Weft. `weft check` passes on it as made; its one
|
|
34
|
+
warning asks for `site.url` before you deploy.
|
|
35
|
+
|
|
36
|
+
## Flags
|
|
12
37
|
|
|
13
38
|
| Flag | Values | Default |
|
|
14
39
|
|---|---|---|
|
|
15
|
-
|
|
|
40
|
+
| `[dir]` | A folder that's missing or empty | asked; `my-weft-app` with `--yes` |
|
|
41
|
+
| `--template` | `todo`, `admin`, `catalog`, `landing`: a fuller starting app (below) | none |
|
|
42
|
+
| `--ui` | `warp`, `headless` (Warp's behaviour and tokens, your markup), `tailwind`, `none` | `warp` |
|
|
16
43
|
| `--db` | `sqlite`, `postgres`, `mysql`, `none` | `sqlite` |
|
|
17
|
-
| `--layer` | `drizzle`, `prisma`, `native` | `drizzle` |
|
|
44
|
+
| `--layer` | `drizzle`, `prisma`, `native` (SQL migrations, no ORM) | `drizzle` |
|
|
18
45
|
| `--auth`, `--no-auth` | Sign-in, when there's a database | on |
|
|
19
|
-
| `--auth-provider` | `better-auth`, `custom` | `better-auth` |
|
|
20
|
-
| `--runtime` | `node`, `bun`, `deno` | the one running it |
|
|
21
|
-
| `--config` | `ts`, `json`, `yaml`: the format of the
|
|
46
|
+
| `--auth-provider` | `better-auth`, `custom` (a stub for your own) | `better-auth` |
|
|
47
|
+
| `--runtime` | `node`, `bun`, `deno`: what `weft build` targets | the one running it |
|
|
48
|
+
| `--config` | `ts`, `json`, `yaml`: the format of the Weft config | `ts` |
|
|
22
49
|
| `--pm` | `npm`, `pnpm`, `bun`, `deno`, `yarn` | the one you ran it with |
|
|
23
|
-
| `--git`, `--no-git
|
|
50
|
+
| `--git`, `--no-git` | Start a git repository | on |
|
|
51
|
+
| `--install`, `--no-install` | Install the dependencies | on, or off with no terminal and no `--yes` |
|
|
24
52
|
| `--name` | The package name | the folder's name |
|
|
53
|
+
| `--yes`, `-y` | Take the defaults for anything not given | |
|
|
25
54
|
|
|
26
55
|
With npm, flags go after `--`: `npm create @weft-js my-app -- --ui tailwind --db none`.
|
|
27
56
|
|
|
28
|
-
|
|
57
|
+
## Templates
|
|
58
|
+
|
|
59
|
+
A template is a fuller app on Postgres. It sets `--db postgres` and the sign-in it needs, and keeps the other flags.
|
|
60
|
+
|
|
61
|
+
| Template | Pages |
|
|
62
|
+
|---|---|
|
|
63
|
+
| `todo` | Sign-in and sign-up, and a todo list |
|
|
64
|
+
| `admin` | An admin area with an orders table, order pages and nested layouts, behind sign-in |
|
|
65
|
+
| `catalog` | A shop: categories, product pages and a cart |
|
|
66
|
+
| `landing` | A landing page with pricing, a privacy page and a sign-up list |
|
|
67
|
+
|
|
68
|
+
## Docs
|
|
69
|
+
|
|
70
|
+
[Installation](https://github.com/Ravonus/weft/blob/main/site/content/learn/installation.md) walks through every file in
|
|
71
|
+
a new app, and how to run, check, build and deploy it.
|
|
72
|
+
|
|
73
|
+
## Links
|
|
74
|
+
|
|
75
|
+
- [Source](https://github.com/Ravonus/weft/tree/main/packages/create)
|
|
76
|
+
- [Weft on GitHub](https://github.com/Ravonus/weft): the framework, the docs and every package
|
|
77
|
+
- [Changelog](https://github.com/Ravonus/weft/blob/main/CHANGELOG.md)
|
|
78
|
+
- [Issues](https://github.com/Ravonus/weft/issues)
|
package/bin/create-weft.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// create-weft [dir] [--ui warp|headless|tailwind|none] [--db sqlite|postgres|mysql|none] [--layer drizzle|prisma|native] [--[no-]auth] [--auth-provider better-auth|custom] [--runtime node|bun|deno]
|
|
2
|
+
// create-weft [dir] [--template landing|todo|admin|catalog] [--ui warp|headless|tailwind|none] [--db sqlite|postgres|mysql|none] [--layer drizzle|prisma|native] [--[no-]auth] [--auth-provider better-auth|custom] [--runtime node|bun|deno]
|
|
3
3
|
// [--config ts|json|yaml] [--pm npm|pnpm|bun|deno|yarn] [--[no-]git] [--[no-]install] [--name <name>] [--tarballs <dir>] [--yes]
|
|
4
4
|
// In a terminal it asks what the flags don't answer; --yes, or no terminal, takes the defaults.
|
|
5
5
|
import { execFileSync } from 'node:child_process'
|
|
@@ -7,16 +7,42 @@ import { readFileSync, writeFileSync } from 'node:fs'
|
|
|
7
7
|
import { join, resolve } from 'node:path'
|
|
8
8
|
import { createInterface } from 'node:readline/promises'
|
|
9
9
|
import { parseArgs } from 'node:util'
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
CONFIGS,
|
|
12
|
+
DB,
|
|
13
|
+
LAYERS,
|
|
14
|
+
RUNTIMES,
|
|
15
|
+
scaffold,
|
|
16
|
+
TEMPLATES,
|
|
17
|
+
UI,
|
|
18
|
+
withTemplate,
|
|
19
|
+
} from '../src/index.mjs'
|
|
11
20
|
import { resolveChoices } from '../src/wizard.mjs'
|
|
12
|
-
import { pin } from '../scripts/tarballs.mjs'
|
|
21
|
+
import { pin, pinWorkspace } from '../scripts/tarballs.mjs'
|
|
13
22
|
|
|
14
|
-
const usage = `Usage: npm create @weft-js -- [dir] [--ui ${UI.join('|')}] [--db ${DB.join('|')}] [--layer ${LAYERS.join('|')}] [--[no-]auth] [--auth-provider better-auth|custom] [--runtime ${RUNTIMES.join('|')}] [--config ${CONFIGS.join('|')}] [--pm <manager>] [--[no-]git] [--[no-]install] [--name <name>] [--tarballs <dir>] [--yes]`
|
|
15
|
-
const string = { type: 'string' },
|
|
23
|
+
const usage = `Usage: npm create @weft-js -- [dir] [--template ${TEMPLATES.join('|')}] [--ui ${UI.join('|')}] [--db ${DB.join('|')}] [--layer ${LAYERS.join('|')}] [--[no-]auth] [--auth-provider better-auth|custom] [--runtime ${RUNTIMES.join('|')}] [--config ${CONFIGS.join('|')}] [--pm <manager>] [--[no-]git] [--[no-]install] [--name <name>] [--tarballs <dir>] [--yes]`
|
|
24
|
+
const string = { type: 'string' },
|
|
25
|
+
boolean = { type: 'boolean' }
|
|
16
26
|
const { values, positionals } = parseArgs({
|
|
17
27
|
allowPositionals: true,
|
|
18
28
|
allowNegative: true,
|
|
19
|
-
options: {
|
|
29
|
+
options: {
|
|
30
|
+
template: string,
|
|
31
|
+
ui: string,
|
|
32
|
+
db: string,
|
|
33
|
+
layer: string,
|
|
34
|
+
auth: boolean,
|
|
35
|
+
'auth-provider': string,
|
|
36
|
+
runtime: string,
|
|
37
|
+
config: string,
|
|
38
|
+
pm: string,
|
|
39
|
+
git: boolean,
|
|
40
|
+
install: boolean,
|
|
41
|
+
name: string,
|
|
42
|
+
tarballs: string,
|
|
43
|
+
yes: { ...boolean, short: 'y' },
|
|
44
|
+
help: { ...boolean, short: 'h' },
|
|
45
|
+
},
|
|
20
46
|
})
|
|
21
47
|
const interactive = process.stdin.isTTY && process.stdout.isTTY
|
|
22
48
|
if (values.help || positionals.length > 1 || (!positionals.length && !interactive)) {
|
|
@@ -33,40 +59,62 @@ async function directory() {
|
|
|
33
59
|
return answer.trim() || 'my-weft-app'
|
|
34
60
|
}
|
|
35
61
|
|
|
36
|
-
/**
|
|
62
|
+
/** The app is already written, so a failure here leaves a step for later; a failed install still fails the command. */
|
|
37
63
|
function step(what, command, args, cwd) {
|
|
38
64
|
try {
|
|
39
|
-
execFileSync(command, args, {
|
|
65
|
+
execFileSync(command, args, {
|
|
66
|
+
cwd,
|
|
67
|
+
stdio: ['ignore', 'ignore', 'inherit'],
|
|
68
|
+
shell: process.platform === 'win32',
|
|
69
|
+
}) // npm is npm.cmd there
|
|
40
70
|
return true
|
|
41
71
|
} catch {
|
|
42
|
-
console.error(
|
|
72
|
+
console.error(
|
|
73
|
+
`create-weft: ${what} didn't finish; run \`${[command, ...args].join(' ')}\` yourself.`,
|
|
74
|
+
)
|
|
43
75
|
return false
|
|
44
76
|
}
|
|
45
77
|
}
|
|
46
78
|
|
|
47
79
|
try {
|
|
48
80
|
const { yes, help: _help, name, tarballs, 'auth-provider': authProvider, ...flags } = values
|
|
49
|
-
if (authProvider && !['better-auth', 'custom'].includes(authProvider))
|
|
81
|
+
if (authProvider && !['better-auth', 'custom'].includes(authProvider))
|
|
82
|
+
throw new Error('--auth-provider must be better-auth or custom')
|
|
50
83
|
if (authProvider) flags.auth = authProvider === 'custom' ? 'custom' : true
|
|
51
84
|
const where = await directory()
|
|
52
85
|
const dir = resolve(where)
|
|
53
|
-
const choices = await resolveChoices(flags, {
|
|
86
|
+
const choices = await resolveChoices(withTemplate(flags), {
|
|
87
|
+
interactive,
|
|
88
|
+
yes,
|
|
89
|
+
io: { input: process.stdin, output: process.stdout },
|
|
90
|
+
})
|
|
54
91
|
const { files } = scaffold(dir, { ...choices, ...(name && { name }) })
|
|
55
92
|
// Before the install: a checkout's packages aren't on npm, so `local.mjs new` needs them wired in from the start.
|
|
56
93
|
if (tarballs) {
|
|
57
94
|
const file = join(dir, 'package.json')
|
|
58
|
-
|
|
95
|
+
const map = JSON.parse(readFileSync(join(tarballs, 'tarballs.json'), 'utf8'))
|
|
96
|
+
writeFileSync(file, JSON.stringify(pin(JSON.parse(readFileSync(file, 'utf8')), map), null, 2))
|
|
97
|
+
pinWorkspace(dir, map)
|
|
59
98
|
}
|
|
60
99
|
console.log(`\nCreated ${files.length} files in ${dir}`)
|
|
61
100
|
if (choices.git) step('git init', 'git', ['init', '--quiet'], dir)
|
|
62
101
|
const installed = choices.install && step('The install', choices.pm, ['install'], dir)
|
|
63
|
-
const weft = {
|
|
102
|
+
const weft = {
|
|
103
|
+
npm: 'npx weft',
|
|
104
|
+
pnpm: 'pnpm exec weft',
|
|
105
|
+
bun: 'bunx --bun weft',
|
|
106
|
+
deno: 'deno run -A npm:@weft-js/cli',
|
|
107
|
+
yarn: 'yarn weft',
|
|
108
|
+
}[choices.pm]
|
|
64
109
|
// AGENTS.md comes from the weft just installed, so it always matches the compiler the app runs.
|
|
65
110
|
if (installed) {
|
|
66
111
|
const [command, ...args] = weft.split(' ')
|
|
67
112
|
step('AGENTS.md', command, [...args, 'agents-md'], dir)
|
|
68
113
|
}
|
|
69
|
-
console.log(
|
|
114
|
+
console.log(
|
|
115
|
+
`\n cd ${where}${installed ? '' : `\n ${choices.pm} install\n ${weft} agents-md`}${choices.db === 'none' || choices.template ? '' : `\n ${weft} db generate`}\n ${weft} dev\n`,
|
|
116
|
+
)
|
|
117
|
+
if (choices.install && !installed) process.exitCode = 1
|
|
70
118
|
} catch (e) {
|
|
71
119
|
console.error(`create-weft: ${e.message}`)
|
|
72
120
|
process.exit(1)
|
package/package.json
CHANGED
|
@@ -1,30 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weft-js/create",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Scaffold a weft app: npm create @weft-js",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"weft"
|
|
7
|
+
],
|
|
5
8
|
"license": "MIT",
|
|
6
|
-
"
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/Ravonus/weft.git",
|
|
12
|
+
"directory": "packages/create"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/Ravonus/weft/tree/main/packages/create#readme",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/Ravonus/weft/issues"
|
|
17
|
+
},
|
|
7
18
|
"bin": {
|
|
8
19
|
"create-weft": "./bin/create-weft.mjs"
|
|
9
20
|
},
|
|
21
|
+
"files": [
|
|
22
|
+
"bin",
|
|
23
|
+
"src",
|
|
24
|
+
"templates",
|
|
25
|
+
"scripts/tarballs.mjs",
|
|
26
|
+
"README.md",
|
|
27
|
+
"LICENSE"
|
|
28
|
+
],
|
|
29
|
+
"type": "module",
|
|
10
30
|
"exports": {
|
|
11
31
|
".": "./src/index.mjs",
|
|
12
32
|
"./stack": "./src/stack.mjs"
|
|
13
33
|
},
|
|
14
|
-
"engines": {
|
|
15
|
-
"node": ">=26"
|
|
16
|
-
},
|
|
17
34
|
"publishConfig": {
|
|
18
35
|
"access": "public"
|
|
19
36
|
},
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"bin",
|
|
25
|
-
"src",
|
|
26
|
-
"scripts/tarballs.mjs",
|
|
27
|
-
"README.md",
|
|
28
|
-
"LICENSE"
|
|
29
|
-
]
|
|
30
|
-
}
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=26"
|
|
39
|
+
}
|
|
40
|
+
}
|
package/scripts/tarballs.mjs
CHANGED
|
@@ -1,11 +1,44 @@
|
|
|
1
1
|
// Every package as a tarball, and an app's package.json pointed at them: what the packed gates and `local.mjs` share.
|
|
2
2
|
import { execFileSync } from 'node:child_process'
|
|
3
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync } from 'node:fs'
|
|
4
|
-
import { join } from 'node:path'
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'
|
|
4
|
+
import { join, resolve } from 'node:path'
|
|
5
5
|
import { fileURLToPath } from 'node:url'
|
|
6
6
|
|
|
7
7
|
export const pkgs = fileURLToPath(new URL('../../', import.meta.url))
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Write the install policy and tarball overrides for a fresh pnpm workspace. weft's own dependency patches stay
|
|
11
|
+
* behind: their files live in this repo, not in the app.
|
|
12
|
+
*/
|
|
13
|
+
export function writePackedPolicy(dir, tarballs = {}, packages = []) {
|
|
14
|
+
const policy = readFileSync(new URL('../../../pnpm-workspace.yaml', import.meta.url), 'utf8')
|
|
15
|
+
.replace(/^packages:\n(?:[ \t].*\n)*/m, '')
|
|
16
|
+
.replace(/^(?:#.*\n)*patchedDependencies:\n(?:[ \t].*\n)*/m, '')
|
|
17
|
+
const overrides = Object.entries(tarballs)
|
|
18
|
+
.map(([name, spec]) => ` ${JSON.stringify(name)}: ${JSON.stringify(spec)}\n`)
|
|
19
|
+
.join('')
|
|
20
|
+
const merged = /^overrides:\n/m.test(policy)
|
|
21
|
+
? policy.replace(/^overrides:\n/m, `overrides:\n${overrides}`)
|
|
22
|
+
: `${policy}${overrides ? `\noverrides:\n${overrides}` : ''}`
|
|
23
|
+
writeFileSync(
|
|
24
|
+
join(dir, 'pnpm-workspace.yaml'),
|
|
25
|
+
`${packages.length ? `packages:\n${packages.map((name) => ` - ${JSON.stringify(name)}\n`).join('')}` : ''}${merged}\n`,
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Pack one package to a known path, independent of lifecycle output. */
|
|
30
|
+
export function pack(dir, dest) {
|
|
31
|
+
const { name, version } = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8'))
|
|
32
|
+
const file = join(resolve(dest), `${name.replace(/^@/, '').replaceAll('/', '-')}-${version}.tgz`)
|
|
33
|
+
execFileSync('pnpm', ['pack', '--out', file], {
|
|
34
|
+
cwd: dir,
|
|
35
|
+
stdio: ['ignore', 'pipe', 'inherit'],
|
|
36
|
+
shell: process.platform === 'win32',
|
|
37
|
+
})
|
|
38
|
+
if (!existsSync(file)) throw new Error(`pnpm pack did not create ${file}`)
|
|
39
|
+
return `file:${file}`
|
|
40
|
+
}
|
|
41
|
+
|
|
9
42
|
/** Pack each package into `dest`. Returns `{ name: 'file:…tgz' }`. */
|
|
10
43
|
export function packAll(dest) {
|
|
11
44
|
mkdirSync(dest, { recursive: true })
|
|
@@ -14,14 +47,31 @@ export function packAll(dest) {
|
|
|
14
47
|
const file = join(pkgs, dir, 'package.json')
|
|
15
48
|
if (!existsSync(file)) continue
|
|
16
49
|
const { name } = JSON.parse(readFileSync(file, 'utf8'))
|
|
17
|
-
|
|
18
|
-
tarballs[name] = `file:${join(dest, packed.trim().split('\n').pop())}`
|
|
50
|
+
tarballs[name] = pack(join(pkgs, dir), dest)
|
|
19
51
|
}
|
|
20
52
|
return tarballs
|
|
21
53
|
}
|
|
22
54
|
|
|
23
55
|
/** `pkg` with its weft dependencies on the tarballs. The overrides reach the ones packages declare for each other. */
|
|
56
|
+
/**
|
|
57
|
+
* The same overrides in the app's own pnpm-workspace.yaml, when create wrote one: that file makes the app its own
|
|
58
|
+
* workspace root, and pnpm reads overrides only from there (not from package.json, nor from a workspace above it).
|
|
59
|
+
*/
|
|
60
|
+
export function pinWorkspace(dir, tarballs) {
|
|
61
|
+
const file = join(dir, 'pnpm-workspace.yaml')
|
|
62
|
+
if (!existsSync(file) || !Object.keys(tarballs).length) return
|
|
63
|
+
const lines = Object.entries(tarballs)
|
|
64
|
+
.map(([name, spec]) => ` ${JSON.stringify(name)}: ${JSON.stringify(spec)}\n`)
|
|
65
|
+
.join('')
|
|
66
|
+
writeFileSync(file, `${readFileSync(file, 'utf8')}overrides:\n${lines}`)
|
|
67
|
+
}
|
|
68
|
+
|
|
24
69
|
export function pin(pkg, tarballs) {
|
|
25
|
-
for (const deps of [pkg.dependencies, pkg.devDependencies])
|
|
26
|
-
|
|
70
|
+
for (const deps of [pkg.dependencies, pkg.devDependencies])
|
|
71
|
+
for (const name in deps) if (tarballs[name]) deps[name] = tarballs[name]
|
|
72
|
+
return {
|
|
73
|
+
...pkg,
|
|
74
|
+
overrides: { ...pkg.overrides, ...tarballs },
|
|
75
|
+
pnpm: { ...pkg.pnpm, overrides: { ...pkg.pnpm?.overrides, ...tarballs } },
|
|
76
|
+
}
|
|
27
77
|
}
|
package/src/data.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// The Native and Prisma data layers of a scaffold
|
|
1
|
+
// The Native and Prisma data layers of a scaffold, beside Drizzle's in stack.mjs. Each writes the same
|
|
2
2
|
// todo app, so the same e2e holds for every layer. `weft add db` writes these files too.
|
|
3
3
|
|
|
4
4
|
const engineSql = {
|
|
@@ -9,23 +9,71 @@ const engineSql = {
|
|
|
9
9
|
|
|
10
10
|
// Better Auth's tables under its default names, which are camelCase, so they're quoted. MySQL can't key a TEXT column.
|
|
11
11
|
export function nativeAuthSql(db) {
|
|
12
|
-
const q = name => (db === 'mysql' ? `\`${name}\`` : `"${name}"`)
|
|
12
|
+
const q = (name) => (db === 'mysql' ? `\`${name}\`` : `"${name}"`)
|
|
13
13
|
const key = 'varchar(255)'
|
|
14
14
|
const text = 'text'
|
|
15
15
|
const when = { sqlite: 'date', postgres: 'timestamptz', mysql: 'datetime(3)' }[db]
|
|
16
16
|
const bool = { sqlite: 'integer', postgres: 'boolean', mysql: 'boolean' }[db]
|
|
17
|
-
const table = (name, columns) =>
|
|
18
|
-
|
|
19
|
-
const
|
|
17
|
+
const table = (name, columns) =>
|
|
18
|
+
`create table ${q(name)} (\n${columns.map(([c, type]) => ` ${q(c)} ${type}`).join(',\n')}\n);\n`
|
|
19
|
+
const ref = (to) => `references ${q(to)} (${q('id')}) on delete cascade`
|
|
20
|
+
const stamps = [
|
|
21
|
+
['createdAt', `${when} not null`],
|
|
22
|
+
['updatedAt', `${when} not null`],
|
|
23
|
+
]
|
|
20
24
|
return [
|
|
21
|
-
table('user', [
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
table('user', [
|
|
26
|
+
['id', `${key} primary key`],
|
|
27
|
+
['name', `${text} not null`],
|
|
28
|
+
['email', `${key} not null unique`],
|
|
29
|
+
['emailVerified', `${bool} not null`],
|
|
30
|
+
['image', text],
|
|
31
|
+
...stamps,
|
|
32
|
+
]),
|
|
33
|
+
table('session', [
|
|
34
|
+
['id', `${key} primary key`],
|
|
35
|
+
['expiresAt', `${when} not null`],
|
|
36
|
+
['token', `${key} not null unique`],
|
|
37
|
+
...stamps,
|
|
38
|
+
['ipAddress', text],
|
|
39
|
+
['userAgent', text],
|
|
40
|
+
['userId', `${key} not null ${ref('user')}`],
|
|
41
|
+
]),
|
|
42
|
+
table('account', [
|
|
43
|
+
['id', `${key} primary key`],
|
|
44
|
+
['accountId', `${text} not null`],
|
|
45
|
+
['providerId', `${text} not null`],
|
|
46
|
+
['userId', `${key} not null ${ref('user')}`],
|
|
47
|
+
['accessToken', text],
|
|
48
|
+
['refreshToken', text],
|
|
49
|
+
['idToken', text],
|
|
50
|
+
['accessTokenExpiresAt', when],
|
|
51
|
+
['refreshTokenExpiresAt', when],
|
|
52
|
+
['scope', text],
|
|
53
|
+
['password', text],
|
|
54
|
+
...stamps,
|
|
55
|
+
]),
|
|
56
|
+
table('verification', [
|
|
57
|
+
['id', `${key} primary key`],
|
|
58
|
+
['identifier', `${text} not null`],
|
|
59
|
+
['value', `${text} not null`],
|
|
60
|
+
['expiresAt', `${when} not null`],
|
|
61
|
+
['createdAt', when],
|
|
62
|
+
['updatedAt', when],
|
|
63
|
+
]),
|
|
64
|
+
table('jwks', [
|
|
65
|
+
['id', `${key} primary key`],
|
|
66
|
+
['publicKey', `${text} not null`],
|
|
67
|
+
['privateKey', `${text} not null`],
|
|
68
|
+
['createdAt', `${when} not null`],
|
|
69
|
+
['expiresAt', when],
|
|
70
|
+
['alg', text],
|
|
71
|
+
['crv', text],
|
|
72
|
+
]),
|
|
25
73
|
].join('\n')
|
|
26
74
|
}
|
|
27
75
|
|
|
28
|
-
const nativeTodos = auth => {
|
|
76
|
+
const nativeTodos = (auth) => {
|
|
29
77
|
const use = auth ? `\n auth: 'user',` : ''
|
|
30
78
|
const mine = auth ? ` and user_id = \${ctx.user.id}` : ''
|
|
31
79
|
return `import { mutation, query } from '@weft-js/start'
|
|
@@ -103,13 +151,21 @@ export default createAuth({ db, secret: env.BETTER_AUTH_SECRET, options: { datab
|
|
|
103
151
|
|
|
104
152
|
const PROVIDER = { sqlite: 'sqlite', postgres: 'postgresql', mysql: 'mysql' }
|
|
105
153
|
const ADAPTER = {
|
|
106
|
-
sqlite: {
|
|
107
|
-
|
|
154
|
+
sqlite: {
|
|
155
|
+
pkg: '@prisma/adapter-libsql',
|
|
156
|
+
name: 'PrismaLibSql',
|
|
157
|
+
make: '{ url: env.DATABASE_URL }',
|
|
158
|
+
},
|
|
159
|
+
postgres: {
|
|
160
|
+
pkg: '@prisma/adapter-pg',
|
|
161
|
+
name: 'PrismaPg',
|
|
162
|
+
make: '{ connectionString: env.DATABASE_URL }',
|
|
163
|
+
},
|
|
108
164
|
mysql: { pkg: '@prisma/adapter-mariadb', name: 'PrismaMariaDb', make: 'env.DATABASE_URL' },
|
|
109
165
|
}
|
|
110
|
-
export const prismaAdapterPackage = db => ADAPTER[db].pkg
|
|
166
|
+
export const prismaAdapterPackage = (db) => ADAPTER[db].pkg
|
|
111
167
|
|
|
112
|
-
const authModels = db => {
|
|
168
|
+
const authModels = (db) => {
|
|
113
169
|
const long = db === 'mysql' ? ' @db.Text' : ''
|
|
114
170
|
return `
|
|
115
171
|
// Better Auth's tables: it reads and writes them through Prisma, with these names.
|
|
@@ -171,12 +227,24 @@ model Verification {
|
|
|
171
227
|
|
|
172
228
|
@@map("verification")
|
|
173
229
|
}
|
|
230
|
+
|
|
231
|
+
model Jwks {
|
|
232
|
+
id String @id
|
|
233
|
+
publicKey String${long} @map("public_key")
|
|
234
|
+
privateKey String${long} @map("private_key")
|
|
235
|
+
createdAt DateTime @map("created_at")
|
|
236
|
+
expiresAt DateTime? @map("expires_at")
|
|
237
|
+
alg String?
|
|
238
|
+
crv String?
|
|
239
|
+
|
|
240
|
+
@@map("jwks")
|
|
241
|
+
}
|
|
174
242
|
`
|
|
175
243
|
}
|
|
176
244
|
|
|
177
|
-
export const prismaAuthModels = db => authModels(db).replace(' todos Todo[]\n', '')
|
|
245
|
+
export const prismaAuthModels = (db) => authModels(db).replace(' todos Todo[]\n', '')
|
|
178
246
|
|
|
179
|
-
const prismaTodos = auth => {
|
|
247
|
+
const prismaTodos = (auth) => {
|
|
180
248
|
const use = auth ? `\n auth: 'user',` : ''
|
|
181
249
|
const mine = auth ? `, userId: ctx.user.id` : ''
|
|
182
250
|
return `import { mutation, query } from '@weft-js/start'
|
|
@@ -238,9 +306,13 @@ model Todo {
|
|
|
238
306
|
id String @id
|
|
239
307
|
title String
|
|
240
308
|
done Boolean @default(false)
|
|
241
|
-
createdAt DateTime @default(now()) @map("created_at")${
|
|
309
|
+
createdAt DateTime @default(now()) @map("created_at")${
|
|
310
|
+
auth
|
|
311
|
+
? `
|
|
242
312
|
userId String @map("user_id")
|
|
243
|
-
user User @relation(fields: [userId], references: [id], onDelete: Cascade)`
|
|
313
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)`
|
|
314
|
+
: ''
|
|
315
|
+
}
|
|
244
316
|
|
|
245
317
|
@@map("todos")
|
|
246
318
|
}
|