@usequark/quark-create-app 1.23.11 → 1.23.12
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/LICENSE +21 -0
- package/README.md +26 -26
- package/package.json +55 -55
- package/src/index.js +17 -17
- package/src/mobile-template.test.js +1 -1
- package/src/scaffold-output.test.js +50 -0
- package/src/template-scripts.test.js +1 -1
- package/src/utils.js +1 -1
- package/templates/base-project/.cursor/rules/quark.mdc +17 -17
- package/templates/base-project/.github/copilot-instructions.md +5 -5
- package/templates/base-project/.github/skills/project-context/SKILL.md +6 -6
- package/templates/base-project/CLAUDE.md +12 -12
- package/templates/base-project/README.md +3 -3
- package/templates/base-project/apps/web/next.config.js +5 -5
- package/templates/base-project/apps/web/package.json +5 -5
- package/templates/base-project/apps/web/src/app/_components/HomeThemeToggle.js +1 -1
- package/templates/base-project/apps/web/src/app/api/auth/apple/route.js +2 -2
- package/templates/base-project/apps/web/src/app/api/auth/google/route.js +2 -2
- package/templates/base-project/apps/web/src/app/api/auth/refresh/route.js +1 -1
- package/templates/base-project/apps/web/src/app/api/auth/register/route.js +3 -3
- package/templates/base-project/apps/web/src/app/api/auth/token/route.js +2 -2
- package/templates/base-project/apps/web/src/app/api/csrf/route.js +1 -1
- package/templates/base-project/apps/web/src/app/api/device/register/route.js +2 -2
- package/templates/base-project/apps/web/src/app/api/error-handler.js +1 -1
- package/templates/base-project/apps/web/src/app/api/files/[id]/route.js +2 -2
- package/templates/base-project/apps/web/src/app/api/files/route.js +2 -2
- package/templates/base-project/apps/web/src/app/api/health/route.js +2 -2
- package/templates/base-project/apps/web/src/app/api/users/[id]/route.js +2 -2
- package/templates/base-project/apps/web/src/app/api/users/me/route.js +2 -2
- package/templates/base-project/apps/web/src/app/api/users/route.js +2 -2
- package/templates/base-project/apps/web/src/app/auth/error/page.js +1 -1
- package/templates/base-project/apps/web/src/app/auth/forgot-password/page.js +1 -1
- package/templates/base-project/apps/web/src/app/auth/register/RegisterPageClient.js +1 -1
- package/templates/base-project/apps/web/src/app/auth/signin/SignInPageClient.js +1 -1
- package/templates/base-project/apps/web/src/app/layout.js +1 -1
- package/templates/base-project/apps/web/src/app/manifest.js +1 -1
- package/templates/base-project/apps/web/src/app/page.js +19 -19
- package/templates/base-project/apps/web/src/app/robots.js +1 -1
- package/templates/base-project/apps/web/src/app/sitemap.js +1 -1
- package/templates/base-project/apps/web/src/lib/analytics/umami-replay.js +1 -1
- package/templates/base-project/apps/web/src/lib/auth-middleware.js +1 -1
- package/templates/base-project/apps/web/src/lib/auth-signup.js +1 -1
- package/templates/base-project/apps/web/src/lib/auth.js +2 -2
- package/templates/base-project/apps/web/src/lib/jwt.js +1 -1
- package/templates/base-project/apps/web/src/lib/proxy-auth.js +1 -1
- package/templates/base-project/apps/web/src/lib/seo/site-metadata.js +1 -1
- package/templates/base-project/apps/web/src/preflight.js +3 -3
- package/templates/base-project/apps/web/src/proxy.js +1 -1
- package/templates/base-project/docs/START_HERE.md +2 -2
- package/templates/base-project/packages/db/package.json +2 -2
- package/templates/base-project/packages/db/src/client.js +3 -3
- package/templates/base-project/packages/db/src/umami.js +1 -1
- package/templates/base-project/scripts/check-loading.mjs +1 -1
- package/templates/base-project/scripts/doctor.js +1 -1
- package/templates/base-project/skills/add-endpoint/SKILL.md +1 -1
- package/templates/base-project/skills/ecommerce/SKILL.md +2 -2
- package/templates/base-project/skills/ecommerce-cart/SKILL.md +3 -3
- package/templates/base-project/skills/ecommerce-catalog/SKILL.md +3 -3
- package/templates/base-project/skills/ecommerce-checkout/SKILL.md +2 -2
- package/templates/base-project/skills/i18n/SKILL.md +6 -6
- package/templates/base-project/skills/payment/SKILL.md +8 -8
- package/templates/config/package.json +1 -1
- package/templates/config/src/app-url.js +1 -1
- package/templates/config/src/environment.js +1 -1
- package/templates/config/src/load-config.js +2 -2
- package/templates/config/src/redis.js +1 -1
- package/templates/config/src/validate-env.js +2 -2
- package/templates/jobs/README.md +2 -2
- package/templates/mobile/lib/errors.ts +1 -1
- package/templates/ui/src/theme-constants.js +1 -1
- package/templates/worker/README.md +2 -2
- package/templates/worker/package.json +4 -4
- package/templates/worker/src/handlers/email-job-validation.js +1 -1
- package/templates/worker/src/handlers/email.js +5 -5
- package/templates/worker/src/handlers/files.js +4 -4
- package/templates/worker/src/handlers/index.js +1 -1
- package/templates/worker/src/handlers/push-notification.js +3 -3
- package/templates/worker/src/index.js +6 -6
- package/templates/worker/src/lib/railway.js +2 -2
- package/templates/worker/src/lib/tokens.js +1 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024, Quark Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @
|
|
1
|
+
# @usequark/quark-create-app CLI
|
|
2
2
|
|
|
3
3
|
Scaffold a new Quark project with sensible defaults for full-stack JavaScript development.
|
|
4
4
|
|
|
@@ -6,10 +6,10 @@ Scaffold a new Quark project with sensible defaults for full-stack JavaScript de
|
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
# Interactive — prompts for project name, description, and options
|
|
9
|
-
npx @
|
|
9
|
+
npx @usequark/quark-create-app@latest
|
|
10
10
|
|
|
11
11
|
# Non-interactive — provide project name as argument
|
|
12
|
-
npx @
|
|
12
|
+
npx @usequark/quark-create-app@latest my-awesome-app
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
The CLI scaffolds a complete project structure with:
|
|
@@ -41,26 +41,26 @@ The CLI detects this, prints a warning, and skips git initialisation so a nested
|
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
43
|
# Create a new project (interactive or with name argument)
|
|
44
|
-
npx @
|
|
45
|
-
npx @
|
|
44
|
+
npx @usequark/quark-create-app@latest
|
|
45
|
+
npx @usequark/quark-create-app@latest my-app
|
|
46
46
|
|
|
47
47
|
# Add a package to an existing project
|
|
48
|
-
npx @
|
|
48
|
+
npx @usequark/quark-create-app add jobs
|
|
49
49
|
|
|
50
50
|
# Print an embedded skill for a feature
|
|
51
|
-
npx @
|
|
51
|
+
npx @usequark/quark-create-app skill bookings
|
|
52
52
|
|
|
53
53
|
# Update Quark packages in an existing project
|
|
54
|
-
npx @
|
|
54
|
+
npx @usequark/quark-create-app update
|
|
55
55
|
|
|
56
56
|
# Check for available updates without applying them
|
|
57
|
-
npx @
|
|
57
|
+
npx @usequark/quark-create-app update --check
|
|
58
58
|
|
|
59
59
|
# Report drift in scaffold-managed files without overwriting anything
|
|
60
|
-
npx @
|
|
60
|
+
npx @usequark/quark-create-app update --scaffold-check
|
|
61
61
|
|
|
62
62
|
# Fail CI when scaffold drift is detected
|
|
63
|
-
npx @
|
|
63
|
+
npx @usequark/quark-create-app update --scaffold-check --fail-on-drift
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
Aliases:
|
|
@@ -78,7 +78,7 @@ When run without arguments, the CLI prompts for:
|
|
|
78
78
|
4. **Public signup** — allow self-service user registration
|
|
79
79
|
|
|
80
80
|
```bash
|
|
81
|
-
npx @
|
|
81
|
+
npx @usequark/quark-create-app@latest
|
|
82
82
|
# ? Project name: my-app
|
|
83
83
|
# ? Describe your app: A platform for booking salon appointments
|
|
84
84
|
# ? Include background jobs (emails, webhooks, scheduled tasks)? Yes
|
|
@@ -90,7 +90,7 @@ npx @techstream/quark-create-app@latest
|
|
|
90
90
|
Skip all prompts with flags:
|
|
91
91
|
|
|
92
92
|
```bash
|
|
93
|
-
npx @
|
|
93
|
+
npx @usequark/quark-create-app@latest my-app --no-prompts
|
|
94
94
|
```
|
|
95
95
|
|
|
96
96
|
### Packages
|
|
@@ -99,13 +99,13 @@ Specify which optional packages to include (default: `ui,jobs`; valid: `ui`, `jo
|
|
|
99
99
|
|
|
100
100
|
```bash
|
|
101
101
|
# Only include UI package
|
|
102
|
-
npx @
|
|
102
|
+
npx @usequark/quark-create-app@latest my-app --no-prompts --packages ui
|
|
103
103
|
|
|
104
104
|
# Include both UI and Jobs
|
|
105
|
-
npx @
|
|
105
|
+
npx @usequark/quark-create-app@latest my-app --no-prompts --packages ui,jobs
|
|
106
106
|
|
|
107
107
|
# Minimal setup (no optional packages)
|
|
108
|
-
npx @
|
|
108
|
+
npx @usequark/quark-create-app@latest my-app --no-prompts --packages ""
|
|
109
109
|
```
|
|
110
110
|
|
|
111
111
|
`ui` is always included automatically as a required dependency.
|
|
@@ -115,7 +115,7 @@ npx @techstream/quark-create-app@latest my-app --no-prompts --packages ""
|
|
|
115
115
|
Seed the `MAIN.md` brief from a flag:
|
|
116
116
|
|
|
117
117
|
```bash
|
|
118
|
-
npx @
|
|
118
|
+
npx @usequark/quark-create-app@latest my-app --no-prompts --prompt "A booking platform for salons"
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
### Signup
|
|
@@ -123,7 +123,7 @@ npx @techstream/quark-create-app@latest my-app --no-prompts --prompt "A booking
|
|
|
123
123
|
Control public self-service signup (default: `enabled`):
|
|
124
124
|
|
|
125
125
|
```bash
|
|
126
|
-
npx @
|
|
126
|
+
npx @usequark/quark-create-app@latest my-app --no-prompts --signup disabled
|
|
127
127
|
```
|
|
128
128
|
|
|
129
129
|
### skill command
|
|
@@ -132,12 +132,12 @@ Print an embedded skill for a feature:
|
|
|
132
132
|
|
|
133
133
|
```bash
|
|
134
134
|
# Print the bookings skill
|
|
135
|
-
npx @
|
|
135
|
+
npx @usequark/quark-create-app@latest skill bookings
|
|
136
136
|
|
|
137
137
|
# Print a core skill (model, endpoint, dashboard)
|
|
138
|
-
npx @
|
|
139
|
-
npx @
|
|
140
|
-
npx @
|
|
138
|
+
npx @usequark/quark-create-app@latest skill model
|
|
139
|
+
npx @usequark/quark-create-app@latest skill endpoint
|
|
140
|
+
npx @usequark/quark-create-app@latest skill dashboard
|
|
141
141
|
```
|
|
142
142
|
|
|
143
143
|
Available skills: `model`, `endpoint`, `dashboard`, `bookings`, `crm`, `cms`, `ai`.
|
|
@@ -148,7 +148,7 @@ Create the project structure without running package installation:
|
|
|
148
148
|
|
|
149
149
|
```bash
|
|
150
150
|
# Create project but skip pnpm install
|
|
151
|
-
npx @
|
|
151
|
+
npx @usequark/quark-create-app@latest my-app --no-prompts --skip-install
|
|
152
152
|
|
|
153
153
|
# Useful for CI/CD where you'll install dependencies separately
|
|
154
154
|
```
|
|
@@ -159,14 +159,14 @@ Control whether to remove Docker volumes from previous cleanup:
|
|
|
159
159
|
|
|
160
160
|
```bash
|
|
161
161
|
# Keep Docker working directories (useful in CI/CD)
|
|
162
|
-
npx @
|
|
162
|
+
npx @usequark/quark-create-app@latest my-app --no-prompts --skip-docker
|
|
163
163
|
```
|
|
164
164
|
|
|
165
165
|
### Complete Example: Full Automation
|
|
166
166
|
|
|
167
167
|
```bash
|
|
168
168
|
# Create, install, and setup everything automatically
|
|
169
|
-
npx @
|
|
169
|
+
npx @usequark/quark-create-app@latest my-app \
|
|
170
170
|
--no-prompts \
|
|
171
171
|
--packages ui,jobs \
|
|
172
172
|
&& cd my-app \
|
|
@@ -177,7 +177,7 @@ npx @techstream/quark-create-app@latest my-app \
|
|
|
177
177
|
|
|
178
178
|
## Common Tasks
|
|
179
179
|
|
|
180
|
-
- **Update Quark packages**: `quark-update` or `pnpm update @
|
|
180
|
+
- **Update Quark packages**: `quark-update` or `pnpm update @usequark/quark-*`
|
|
181
181
|
- **Check for updates**: `quark-update --check`
|
|
182
182
|
- **Review scaffold drift**: `quark-update --scaffold-check`
|
|
183
183
|
- **Fail CI on scaffold drift**: `quark-update --scaffold-check --fail-on-drift`
|
package/package.json
CHANGED
|
@@ -1,56 +1,56 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
2
|
+
"name": "@usequark/quark-create-app",
|
|
3
|
+
"version": "1.23.12",
|
|
4
|
+
"description": "CLI to scaffold new Quark projects with Next.js, Prisma, BullMQ, and Railway deployment",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"homepage": "https://github.com/usequark/quark#readme",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/usequark/quark.git",
|
|
10
|
+
"directory": "packages/cli"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/usequark/quark/issues"
|
|
14
|
+
},
|
|
15
|
+
"author": "Quark Contributors",
|
|
16
|
+
"bin": {
|
|
17
|
+
"quark": "src/index.js",
|
|
18
|
+
"quark-create-app": "src/index.js",
|
|
19
|
+
"create-quark-app": "src/index.js",
|
|
20
|
+
"quark-update": "src/index.js"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"src",
|
|
24
|
+
"templates",
|
|
25
|
+
"README.md"
|
|
26
|
+
],
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"chalk": "^6.0.0",
|
|
29
|
+
"commander": "^15.0.0",
|
|
30
|
+
"execa": "^10.0.1",
|
|
31
|
+
"fs-extra": "^11.4.1",
|
|
32
|
+
"prompts": "^2.4.2"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"registry": "https://registry.npmjs.org",
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=22.13.0"
|
|
40
|
+
},
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"scripts": {
|
|
43
|
+
"sync-templates": "node scripts/sync-templates.js",
|
|
44
|
+
"sync-templates:check": "node scripts/sync-templates.js --check",
|
|
45
|
+
"regen-migration": "node scripts/regenerate-template-migration.js",
|
|
46
|
+
"smoke:published": "node scripts/smoke-published.js",
|
|
47
|
+
"test": "node test-cli.js && node --test src/utils.test.js && node --test src/prepare-hooks.test.js && node --test src/scaffold-output.test.js && node --test src/template-scripts.test.js && node --test src/scaffold-guards.test.js && node --test src/worker-dockerfile.test.js && node --test src/dependabot-config.test.js && node --test 'src/deploy/**/*.test.js' && node --test --test-concurrency=1 'src/deploy/**/*.integration.test.js'",
|
|
48
|
+
"test:build": "node test-build.js",
|
|
49
|
+
"test:e2e": "node test-e2e.js",
|
|
50
|
+
"test:e2e:full": "node test-e2e-full.js",
|
|
51
|
+
"test:integration": "node test-integration.js",
|
|
52
|
+
"test:flags": "node --test test-flags.js",
|
|
53
|
+
"test:all": "node test-all.js",
|
|
54
|
+
"check:perf": "node scripts/check-e2e-perf.js"
|
|
55
|
+
}
|
|
56
|
+
}
|
package/src/index.js
CHANGED
|
@@ -352,7 +352,7 @@ function buildFeatureRows(features) {
|
|
|
352
352
|
.map((feature) => rows[feature]);
|
|
353
353
|
|
|
354
354
|
if (selectedRows.length === 0) {
|
|
355
|
-
return "| Optional scaffolded features | None selected yet | Add one later with `npx @
|
|
355
|
+
return "| Optional scaffolded features | None selected yet | Add one later with `npx @usequark/quark-create-app add <feature>` |";
|
|
356
356
|
}
|
|
357
357
|
|
|
358
358
|
return selectedRows.join("\n");
|
|
@@ -411,7 +411,7 @@ function formatFeatureSummary(features) {
|
|
|
411
411
|
}
|
|
412
412
|
|
|
413
413
|
/**
|
|
414
|
-
* Registry pin for @
|
|
414
|
+
* Registry pin for @usequark/quark-core in scaffolded apps.
|
|
415
415
|
* Mirrors sync-templates.js CORE_VERSION_PIN (major.0.0 from baked templates).
|
|
416
416
|
*/
|
|
417
417
|
function getCoreVersionPin() {
|
|
@@ -419,7 +419,7 @@ function getCoreVersionPin() {
|
|
|
419
419
|
const webPkg = fs.readJSONSync(
|
|
420
420
|
path.join(templatesDir, "base-project/apps/web/package.json"),
|
|
421
421
|
);
|
|
422
|
-
const pin = webPkg?.dependencies?.["@
|
|
422
|
+
const pin = webPkg?.dependencies?.["@usequark/quark-core"];
|
|
423
423
|
if (typeof pin === "string" && pin !== "workspace:*") {
|
|
424
424
|
return pin;
|
|
425
425
|
}
|
|
@@ -430,21 +430,21 @@ function getCoreVersionPin() {
|
|
|
430
430
|
}
|
|
431
431
|
|
|
432
432
|
/**
|
|
433
|
-
* Replace @
|
|
433
|
+
* Replace @usequark/quark-* workspace deps with @scope/* for local packages.
|
|
434
434
|
* Also removes deps for packages that were not selected.
|
|
435
|
-
* @
|
|
435
|
+
* @usequark/quark-core is a published registry package — rewrite workspace:*
|
|
436
436
|
* to the registry pin instead of deleting or rescoping it.
|
|
437
437
|
*/
|
|
438
438
|
function replaceDepsScope(deps, scope, selectedPackages) {
|
|
439
439
|
if (!deps) return;
|
|
440
440
|
for (const [key, value] of Object.entries(deps)) {
|
|
441
|
-
if (key.startsWith("@
|
|
441
|
+
if (key.startsWith("@usequark/quark-") && value === "workspace:*") {
|
|
442
442
|
// Published registry package — keep name, pin to registry version.
|
|
443
|
-
if (key === "@
|
|
443
|
+
if (key === "@usequark/quark-core") {
|
|
444
444
|
deps[key] = getCoreVersionPin();
|
|
445
445
|
continue;
|
|
446
446
|
}
|
|
447
|
-
const packageName = key.replace("@
|
|
447
|
+
const packageName = key.replace("@usequark/quark-", "");
|
|
448
448
|
delete deps[key];
|
|
449
449
|
// Only keep the dep if the package was selected (or is always required)
|
|
450
450
|
if (
|
|
@@ -490,9 +490,9 @@ async function patchNextConfig(webDir, scope, selectedPackages) {
|
|
|
490
490
|
}
|
|
491
491
|
|
|
492
492
|
/**
|
|
493
|
-
* Replace @
|
|
493
|
+
* Replace @usequark/quark-* import paths in all .js source files
|
|
494
494
|
* for workspace packages (db, jobs, ui, config) with @scope/* equivalents.
|
|
495
|
-
* Registry packages (@
|
|
495
|
+
* Registry packages (@usequark/quark-core) are left untouched.
|
|
496
496
|
*/
|
|
497
497
|
async function replaceImportsInSourceFiles(dir, scope) {
|
|
498
498
|
const workspacePackages = ["db", "jobs", "ui", "config"];
|
|
@@ -512,7 +512,7 @@ async function replaceImportsInSourceFiles(dir, scope) {
|
|
|
512
512
|
let changed = false;
|
|
513
513
|
|
|
514
514
|
for (const pkg of workspacePackages) {
|
|
515
|
-
const pattern = new RegExp(`@
|
|
515
|
+
const pattern = new RegExp(`@usequark/quark-${pkg}`, "g");
|
|
516
516
|
if (pattern.test(content)) {
|
|
517
517
|
content = content.replace(pattern, `@${scope}/${pkg}`);
|
|
518
518
|
changed = true;
|
|
@@ -1694,7 +1694,7 @@ STORAGE_PROVIDER=local
|
|
|
1694
1694
|
|
|
1695
1695
|
console.log(
|
|
1696
1696
|
chalk.dim(
|
|
1697
|
-
` 📖 github.com/usequark/quark • Updates: npx @
|
|
1697
|
+
` 📖 github.com/usequark/quark • Updates: npx @usequark/quark-create-app update\n`,
|
|
1698
1698
|
),
|
|
1699
1699
|
);
|
|
1700
1700
|
} catch (error) {
|
|
@@ -2635,7 +2635,7 @@ program
|
|
|
2635
2635
|
* Read the installed version of a package from node_modules.
|
|
2636
2636
|
* Returns null if the package is not installed.
|
|
2637
2637
|
* @param {string} cwd - Project root
|
|
2638
|
-
* @param {string} packageName - e.g. "@
|
|
2638
|
+
* @param {string} packageName - e.g. "@usequark/quark-core"
|
|
2639
2639
|
* @returns {Promise<string|null>}
|
|
2640
2640
|
*/
|
|
2641
2641
|
async function getInstalledVersion(cwd, packageName) {
|
|
@@ -2713,8 +2713,8 @@ program
|
|
|
2713
2713
|
|
|
2714
2714
|
// The packages this command manages
|
|
2715
2715
|
const MANAGED_PACKAGES = [
|
|
2716
|
-
"@
|
|
2717
|
-
"@
|
|
2716
|
+
"@usequark/quark-core",
|
|
2717
|
+
"@usequark/quark-create-app",
|
|
2718
2718
|
];
|
|
2719
2719
|
|
|
2720
2720
|
// Snapshot installed versions before any update
|
|
@@ -2726,7 +2726,7 @@ program
|
|
|
2726
2726
|
console.log(chalk.cyan(`Scaffolded: ${quarkLink.scaffoldedDate}`));
|
|
2727
2727
|
console.log(
|
|
2728
2728
|
chalk.cyan(
|
|
2729
|
-
`Installed core: ${before["@
|
|
2729
|
+
`Installed core: ${before["@usequark/quark-core"] ?? quarkLink.quarkVersion ?? "unknown"}\n`,
|
|
2730
2730
|
),
|
|
2731
2731
|
);
|
|
2732
2732
|
|
|
@@ -2818,7 +2818,7 @@ program
|
|
|
2818
2818
|
|
|
2819
2819
|
// Persist the new core version - keep previous on failure, never write garbage
|
|
2820
2820
|
const newCoreVersion =
|
|
2821
|
-
after["@
|
|
2821
|
+
after["@usequark/quark-core"] ?? quarkLink.quarkVersion;
|
|
2822
2822
|
quarkLink.quarkVersion = newCoreVersion;
|
|
2823
2823
|
quarkLink.updatedDate = new Date().toISOString();
|
|
2824
2824
|
await fs.writeFile(quarkLinkPath, JSON.stringify(quarkLink, null, " "));
|
|
@@ -66,7 +66,7 @@ test("mobile package.json has no monorepo workspace refs in devDependencies", ()
|
|
|
66
66
|
if (pkg.devDependencies) {
|
|
67
67
|
for (const dep of Object.keys(pkg.devDependencies)) {
|
|
68
68
|
assert.ok(
|
|
69
|
-
!dep.startsWith("@
|
|
69
|
+
!dep.startsWith("@usequark/quark-"),
|
|
70
70
|
`mobile devDependencies has monorepo ref: ${dep}`,
|
|
71
71
|
);
|
|
72
72
|
}
|
|
@@ -96,6 +96,56 @@ describe("scaffold output placeholders", () => {
|
|
|
96
96
|
);
|
|
97
97
|
});
|
|
98
98
|
|
|
99
|
+
// Guards the scope rewrite itself. replaceDepsScope and
|
|
100
|
+
// replaceImportsInSourceFiles map the framework scope onto the project's own
|
|
101
|
+
// scope for db/jobs/ui/config, and leave the published quark-core registry
|
|
102
|
+
// dependency alone on purpose.
|
|
103
|
+
//
|
|
104
|
+
// db, jobs, ui and config are local-only workspace packages and have never
|
|
105
|
+
// been published to any registry, so a framework-scoped reference surviving
|
|
106
|
+
// into generated output produces a project that cannot install. Nothing else
|
|
107
|
+
// catches that: the placeholder test above only looks for __QUARK_ and
|
|
108
|
+
// @myquark, so a rewrite rule that silently stopped matching - because a
|
|
109
|
+
// template and its rule drifted apart - left every test in this repo green
|
|
110
|
+
// while every scaffolded app was broken.
|
|
111
|
+
//
|
|
112
|
+
// Both scopes are asserted. @techstream is the pre-rename scope and must not
|
|
113
|
+
// appear at all; @usequark is the current one and must not appear for the
|
|
114
|
+
// local-only packages, though @usequark/quark-core is expected and correct.
|
|
115
|
+
//
|
|
116
|
+
// Scoped to files that participate in module resolution. Markdown and .mdc
|
|
117
|
+
// instruction files legitimately name the framework scope in order to tell an
|
|
118
|
+
// agent never to import it - .cursor/rules/quark.mdc ships exactly that
|
|
119
|
+
// prohibition, alongside deliberately-wrong import examples. Prose cannot
|
|
120
|
+
// break an install; an import or a dependency can.
|
|
121
|
+
it("never leaks a framework-scoped reference to a local-only package", () => {
|
|
122
|
+
const RESOLVABLE = /\.(js|jsx|mjs|cjs|ts|tsx)$/;
|
|
123
|
+
const localOnly = /@(techstream|usequark)\/quark-(db|jobs|ui|config)\b/;
|
|
124
|
+
const offenders = [];
|
|
125
|
+
|
|
126
|
+
for (const file of collectFiles(projectDir)) {
|
|
127
|
+
const rel = path.relative(projectDir, file);
|
|
128
|
+
const base = path.basename(file);
|
|
129
|
+
if (base !== "package.json" && !RESOLVABLE.test(base)) continue;
|
|
130
|
+
|
|
131
|
+
let content;
|
|
132
|
+
try {
|
|
133
|
+
content = fs.readFileSync(file, "utf-8");
|
|
134
|
+
} catch {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (localOnly.test(content)) {
|
|
138
|
+
offenders.push(rel);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
assert.deepStrictEqual(
|
|
143
|
+
offenders,
|
|
144
|
+
[],
|
|
145
|
+
`local-only packages must be rewritten to the project scope; leaked in: ${offenders.join(", ")}`,
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
|
|
99
149
|
it("rewrites the DB import in AI prompts to the project scope", () => {
|
|
100
150
|
const page = fs.readFileSync(
|
|
101
151
|
path.join(projectDir, "apps/web/src/app/page.js"),
|
|
@@ -115,7 +115,7 @@ describe("check-loading.mjs", () => {
|
|
|
115
115
|
writeFile(
|
|
116
116
|
dir,
|
|
117
117
|
"apps/web/src/app/metrics/page.js",
|
|
118
|
-
'import { prisma } from "@
|
|
118
|
+
'import { prisma } from "@usequark/quark-db";\n\nexport default function Page() {\n\treturn null;\n}\n',
|
|
119
119
|
);
|
|
120
120
|
|
|
121
121
|
const result = runScript(dir, "scripts/check-loading.mjs");
|
package/src/utils.js
CHANGED
|
@@ -15,10 +15,10 @@ Scaffolded: __QUARK_SCAFFOLD_DATE__
|
|
|
15
15
|
1. **ESM only.** Always `import`/`export`. Never `require()` or `module.exports`.
|
|
16
16
|
2. **No authored TypeScript.** Plain `.js` and `.jsx` files only - no repo-authored `.ts`, `.tsx`, or type annotations. Generated code is the only exception.
|
|
17
17
|
3. **Validate everything at boundaries.** Server Actions and API routes must use Zod. No raw `req.body` access without parsing.
|
|
18
|
-
4. **Use AppError at runtime boundaries.** Throw `AppError` / `ValidationError` / `NotFoundError` from `@
|
|
19
|
-
5. **Log with createLogger in runtime code.** Use `createLogger(name)` from `@
|
|
18
|
+
4. **Use AppError at runtime boundaries.** Throw `AppError` / `ValidationError` / `NotFoundError` from `@usequark/quark-core/errors` in application/runtime code. Native `Error` is reserved for library, bootstrap, CLI, and test code.
|
|
19
|
+
5. **Log with createLogger in runtime code.** Use `createLogger(name)` from `@usequark/quark-core` for application/runtime code. Console output is reserved for bootstrap, CLI, and test code.
|
|
20
20
|
6. **DB models always have timestamps.** Every Prisma model: `createdAt DateTime @default(now())` + `updatedAt DateTime @updatedAt`.
|
|
21
|
-
7. **Workspace import scope.** Use `@__QUARK_SCOPE__/*` for local packages. Never `@
|
|
21
|
+
7. **Workspace import scope.** Use `@__QUARK_SCOPE__/*` for local packages. Never `@usequark/quark-db`, `@usequark/quark-config`, etc.
|
|
22
22
|
8. **Co-located tests.** `feature.test.js` lives next to `feature.js`. Tests use `node --test` - no Jest, no Vitest.
|
|
23
23
|
|
|
24
24
|
---
|
|
@@ -32,16 +32,16 @@ import { loadConfig } from "@__QUARK_SCOPE__/config";
|
|
|
32
32
|
import { Button, Card, Input } from "@__QUARK_SCOPE__/ui";
|
|
33
33
|
import { JOB_TYPES } from "@__QUARK_SCOPE__/jobs";
|
|
34
34
|
|
|
35
|
-
// ✅ Published runtime - @
|
|
36
|
-
import { AppError, ValidationError, NotFoundError } from "@
|
|
37
|
-
import { createLogger, getCurrentSession } from "@
|
|
38
|
-
import { createQueue, addJob } from "@
|
|
39
|
-
import { metrics, cache, storage } from "@
|
|
35
|
+
// ✅ Published runtime - @usequark/quark-core:
|
|
36
|
+
import { AppError, ValidationError, NotFoundError } from "@usequark/quark-core/errors";
|
|
37
|
+
import { createLogger, getCurrentSession } from "@usequark/quark-core";
|
|
38
|
+
import { createQueue, addJob } from "@usequark/quark-core";
|
|
39
|
+
import { metrics, cache, storage } from "@usequark/quark-core";
|
|
40
40
|
|
|
41
41
|
// ❌ Never:
|
|
42
42
|
import { Button } from "@/components/ui/button"; // wrong path convention
|
|
43
|
-
import { prisma } from "@
|
|
44
|
-
import something from "@
|
|
43
|
+
import { prisma } from "@usequark/quark-db"; // wrong scope for workspace pkg
|
|
44
|
+
import something from "@usequark/quark-config"; // wrong scope for workspace pkg
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
---
|
|
@@ -63,8 +63,8 @@ import something from "@techstream/quark-config"; // wrong scope for workspa
|
|
|
63
63
|
```javascript
|
|
64
64
|
"use server";
|
|
65
65
|
import { z } from "zod";
|
|
66
|
-
import { ValidationError, AppError } from "@
|
|
67
|
-
import { getCurrentSession, createLogger } from "@
|
|
66
|
+
import { ValidationError, AppError } from "@usequark/quark-core/errors";
|
|
67
|
+
import { getCurrentSession, createLogger } from "@usequark/quark-core";
|
|
68
68
|
import { prisma } from "@__QUARK_SCOPE__/db";
|
|
69
69
|
|
|
70
70
|
const log = createLogger("action:example");
|
|
@@ -89,8 +89,8 @@ export async function createExample(formData) {
|
|
|
89
89
|
|
|
90
90
|
```javascript
|
|
91
91
|
import { NextResponse } from "next/server";
|
|
92
|
-
import { AppError } from "@
|
|
93
|
-
import { createLogger } from "@
|
|
92
|
+
import { AppError } from "@usequark/quark-core/errors";
|
|
93
|
+
import { createLogger } from "@usequark/quark-core";
|
|
94
94
|
|
|
95
95
|
const log = createLogger("api:example");
|
|
96
96
|
|
|
@@ -119,7 +119,7 @@ export async function GET(request) {
|
|
|
119
119
|
## Auth
|
|
120
120
|
|
|
121
121
|
```javascript
|
|
122
|
-
import { getCurrentSession } from "@
|
|
122
|
+
import { getCurrentSession } from "@usequark/quark-core";
|
|
123
123
|
|
|
124
124
|
const session = await getCurrentSession(); // null if unauthenticated
|
|
125
125
|
if (!session) redirect("/login"); // Server Component
|
|
@@ -133,13 +133,13 @@ if (session.user.role !== "ADMIN") throw new AppError("Forbidden", 403);
|
|
|
133
133
|
|
|
134
134
|
```javascript
|
|
135
135
|
// Dispatch (from Server Action or API route):
|
|
136
|
-
import { createQueue, addJob } from "@
|
|
136
|
+
import { createQueue, addJob } from "@usequark/quark-core";
|
|
137
137
|
import { JOB_TYPES } from "@__QUARK_SCOPE__/jobs";
|
|
138
138
|
const queue = createQueue("default");
|
|
139
139
|
await addJob(queue, JOB_TYPES.MY_JOB, { userId });
|
|
140
140
|
|
|
141
141
|
// Handle (apps/worker/src/handlers/):
|
|
142
|
-
import { createLogger } from "@
|
|
142
|
+
import { createLogger } from "@usequark/quark-core";
|
|
143
143
|
const log = createLogger("job:my-job");
|
|
144
144
|
export async function handleMyJob({ data }) { log.info("processing", data); }
|
|
145
145
|
```
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
- **ESM only** - `import`/`export` everywhere. Never `require()`.
|
|
17
17
|
- **No authored TypeScript** - `.js` and `.jsx` only. Generated code may emit typed artifacts, but project code should not add `.ts` or `.tsx` sources.
|
|
18
18
|
- **Validate at every boundary** - Zod schemas on all Server Actions and API routes.
|
|
19
|
-
- **Errors** - `AppError` / `ValidationError` from `@
|
|
20
|
-
- **Logging** - `createLogger(name)` from `@
|
|
19
|
+
- **Errors** - `AppError` / `ValidationError` from `@usequark/quark-core/errors` in app/runtime code. Native `Error` is acceptable in library, bootstrap, CLI, and test code.
|
|
20
|
+
- **Logging** - `createLogger(name)` from `@usequark/quark-core` in app/runtime code. Console output is acceptable in bootstrap, CLI, and test code.
|
|
21
21
|
- **DB models** - Always add `createdAt` and `updatedAt` to every Prisma model.
|
|
22
|
-
- **Workspace imports** - Use `@__QUARK_SCOPE__/*` for local packages (`db`, `config`, `ui`, `jobs`). Never `@
|
|
22
|
+
- **Workspace imports** - Use `@__QUARK_SCOPE__/*` for local packages (`db`, `config`, `ui`, `jobs`). Never `@usequark/quark-db` etc.
|
|
23
23
|
- **Tests** - Co-located `*.test.js`, run with `node --test`.
|
|
24
24
|
|
|
25
25
|
## Import Patterns
|
|
@@ -32,8 +32,8 @@ import { Button, Card, Input } from "@__QUARK_SCOPE__/ui";
|
|
|
32
32
|
import { JOB_TYPES } from "@__QUARK_SCOPE__/jobs";
|
|
33
33
|
|
|
34
34
|
// Published runtime:
|
|
35
|
-
import { AppError, ValidationError } from "@
|
|
36
|
-
import { createLogger, getCurrentSession, createQueue, addJob } from "@
|
|
35
|
+
import { AppError, ValidationError } from "@usequark/quark-core/errors";
|
|
36
|
+
import { createLogger, getCurrentSession, createQueue, addJob } from "@usequark/quark-core";
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
## UI & Design System
|
|
@@ -12,7 +12,7 @@ This is a Quark-based full-stack JavaScript application.
|
|
|
12
12
|
| Property | Value |
|
|
13
13
|
|---|---|
|
|
14
14
|
| **Scope** | `@__QUARK_SCOPE__` |
|
|
15
|
-
| **Framework** | Quark (scaffolded from `@
|
|
15
|
+
| **Framework** | Quark (scaffolded from `@usequark/quark-create-app`) |
|
|
16
16
|
| **Scaffolded** | __QUARK_SCAFFOLD_DATE__ |
|
|
17
17
|
|
|
18
18
|
## Project Structure
|
|
@@ -50,11 +50,11 @@ __QUARK_OPTIONAL_PACKAGES__├── docker-compose.yml
|
|
|
50
50
|
|
|
51
51
|
- **ESM only** - use `import`/`export`, never `require`.
|
|
52
52
|
- **No authored TypeScript** - plain `.js` and `.jsx` files. Generated code may emit typed artifacts, but project code should not add `.ts` or `.tsx` sources.
|
|
53
|
-
- **Imports:** Use `@
|
|
53
|
+
- **Imports:** Use `@usequark/quark-core` for published utilities. Use `@__QUARK_SCOPE__/*` for local packages (db, config, ui, jobs).
|
|
54
54
|
- **Tests:** Co-located `*.test.js` files, run with `node --test`.
|
|
55
55
|
- **Validation:** Zod schemas for all Server Actions and API routes.
|
|
56
|
-
- **Errors:** Use `AppError` / `ValidationError` from `@
|
|
57
|
-
- **Logging:** Use `createLogger(name)` from `@
|
|
56
|
+
- **Errors:** Use `AppError` / `ValidationError` from `@usequark/quark-core/errors` in app/runtime code. Native `Error` is acceptable in library, bootstrap, CLI, and test code.
|
|
57
|
+
- **Logging:** Use `createLogger(name)` from `@usequark/quark-core` in app/runtime code. Console output is acceptable in bootstrap, CLI, and test code.
|
|
58
58
|
- **Database models:** Always include `createdAt`/`updatedAt`.
|
|
59
59
|
- **Environment:** All env vars validated in `packages/config/src/validate-env.js`.
|
|
60
60
|
- **Analytics:** Optional Umami support lives in `apps/web/src/lib/analytics/*`. The public env contract uses only `NEXT_PUBLIC_UMAMI_URL`, `NEXT_PUBLIC_UMAMI_WEBSITE_ID`, and `NEXT_PUBLIC_UMAMI_REPLAY_ENABLED`; replay uses a local rrweb recorder, and dormant helpers exist for dashboard-generated Umami Links, Pixels, and marketing-email snippets.
|
|
@@ -86,8 +86,8 @@ docker compose up -d # Start infrastructure
|
|
|
86
86
|
## Updating Quark Core
|
|
87
87
|
|
|
88
88
|
```bash
|
|
89
|
-
npx @
|
|
90
|
-
pnpm update @
|
|
89
|
+
npx @usequark/quark-create-app update # Update core infrastructure
|
|
90
|
+
pnpm update @usequark/quark-core # Or update directly
|
|
91
91
|
```
|
|
92
92
|
|
|
93
93
|
---
|