@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
|
@@ -24,14 +24,14 @@
|
|
|
24
24
|
"packageManager": "pnpm@10.12.1",
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@faker-js/faker": "^10.6.0",
|
|
27
|
-
"@
|
|
27
|
+
"@usequark/quark-config": "workspace:*",
|
|
28
28
|
"bcryptjs": "^3.0.3",
|
|
29
29
|
"prisma": "^7.10.0"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@prisma/adapter-pg": "^7.10.0",
|
|
33
33
|
"@prisma/client": "^7.10.0",
|
|
34
|
-
"@
|
|
34
|
+
"@usequark/quark-core": "^2.0.0",
|
|
35
35
|
"pg": "^8.23.0",
|
|
36
36
|
"zod": "^4.6.5"
|
|
37
37
|
}
|
|
@@ -38,12 +38,12 @@ function getPrismaClient() {
|
|
|
38
38
|
// Assign base client immediately so the proxy never blocks.
|
|
39
39
|
globalForPrisma.__prisma = baseClient;
|
|
40
40
|
|
|
41
|
-
// Apply optional query instrumentation extension from @
|
|
41
|
+
// Apply optional query instrumentation extension from @usequark/quark-core.
|
|
42
42
|
// Loaded asynchronously — the base client is used in the meantime, then
|
|
43
43
|
// upgraded in-place once the extension module arrives.
|
|
44
44
|
// The extension handles slow-query logging, argument masking, and Prometheus
|
|
45
45
|
// metrics. It is schema-agnostic and respects the DB_INSTRUMENTATION env var.
|
|
46
|
-
import("@
|
|
46
|
+
import("@usequark/quark-core")
|
|
47
47
|
.then(({ createDbInstrumentation }) => {
|
|
48
48
|
const ext = createDbInstrumentation();
|
|
49
49
|
if (ext) {
|
|
@@ -51,7 +51,7 @@ function getPrismaClient() {
|
|
|
51
51
|
}
|
|
52
52
|
})
|
|
53
53
|
.catch(() => {
|
|
54
|
-
// @
|
|
54
|
+
// @usequark/quark-core not available or old version — base client remains.
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
return globalForPrisma.__prisma;
|
|
@@ -17,7 +17,7 @@ let failed = false;
|
|
|
17
17
|
function isDbBacked(pagePath) {
|
|
18
18
|
const content = readFileSync(pagePath, "utf-8");
|
|
19
19
|
// Matches scoped db packages in scaffolds (@scope/db) and the monorepo
|
|
20
|
-
// package name (@
|
|
20
|
+
// package name (@usequark/quark-db).
|
|
21
21
|
return /@[^/"'\s]+\/(?:quark-)?db["']/.test(content);
|
|
22
22
|
}
|
|
23
23
|
|
|
@@ -186,7 +186,7 @@ if (forgotPwContent && forgotPwContent.includes("quark-auth-layout")) {
|
|
|
186
186
|
"imports",
|
|
187
187
|
`Source files import "${importPattern}" but "${pkg}" is not installed`,
|
|
188
188
|
badFiles.map((f) => ` ${path.relative(ROOT, f)}`).join("\n"),
|
|
189
|
-
`Remove these imports or run: npx @
|
|
189
|
+
`Remove these imports or run: npx @usequark/quark-create-app add ${pkg}`,
|
|
190
190
|
);
|
|
191
191
|
}
|
|
192
192
|
}
|
|
@@ -11,7 +11,7 @@ Add a REST CRUD endpoint for an existing model: list/create on the collection ro
|
|
|
11
11
|
|
|
12
12
|
- **API routes** live in `apps/web/src/app/api/<resource>/`.
|
|
13
13
|
- **Data access** goes through query helpers in `packages/db/src/queries.js` — never call `prisma.*` directly.
|
|
14
|
-
- **Auth** via `requireRole` from `@/lib/auth-middleware`; **validation** via Zod `validateBody`; **CSRF** via `withCsrfProtection` from `@
|
|
14
|
+
- **Auth** via `requireRole` from `@/lib/auth-middleware`; **validation** via Zod `validateBody`; **CSRF** via `withCsrfProtection` from `@usequark/quark-core`.
|
|
15
15
|
|
|
16
16
|
## Workflow
|
|
17
17
|
|
|
@@ -22,9 +22,9 @@ An ecommerce system manages a product catalog, shopping cart, checkout flow, ord
|
|
|
22
22
|
|
|
23
23
|
- **Models** live in `packages/db/prisma/schema.prisma`. Every model needs `id`, `createdAt DateTime @default(now())`, `updatedAt DateTime @updatedAt`. After changes: `pnpm db:generate && pnpm db:migrate`.
|
|
24
24
|
- **Data access** goes through query helpers in `packages/db/src/queries.js` — never call `prisma.*` directly in pages/actions.
|
|
25
|
-
- **Server Actions** (preferred for mutations) use `"use server"`, Zod validation, and `AppError`/`ValidationError` from `@
|
|
25
|
+
- **Server Actions** (preferred for mutations) use `"use server"`, Zod validation, and `AppError`/`ValidationError` from `@usequark/quark-core/errors`.
|
|
26
26
|
- **Admin views** live under `apps/web/src/app/admin/` (see the admin-dashboard skill for product/order management).
|
|
27
|
-
- **Auth** via `getCurrentSession` from `@
|
|
27
|
+
- **Auth** via `getCurrentSession` from `@usequark/quark-core`.
|
|
28
28
|
- **Payment** integration follows the payment skill for Stripe Checkout or similar processors.
|
|
29
29
|
|
|
30
30
|
## Workflow
|
|
@@ -19,8 +19,8 @@ The cart is a temporary collection of items a user intends to purchase. Key conc
|
|
|
19
19
|
|
|
20
20
|
- **Models** live in `packages/db/prisma/schema.prisma`. Every model needs `id`, `createdAt DateTime @default(now())`, `updatedAt DateTime @updatedAt`. After changes: `pnpm db:generate && pnpm db:migrate`.
|
|
21
21
|
- **Data access** goes through query helpers in `packages/db/src/queries.js` — never call `prisma.*` directly in pages/actions.
|
|
22
|
-
- **Server Actions** use `"use server"`, Zod validation, and `AppError`/`ValidationError` from `@
|
|
23
|
-
- **Auth** via `getCurrentSession` from `@
|
|
22
|
+
- **Server Actions** use `"use server"`, Zod validation, and `AppError`/`ValidationError` from `@usequark/quark-core/errors`.
|
|
23
|
+
- **Auth** via `getCurrentSession` from `@usequark/quark-core`.
|
|
24
24
|
|
|
25
25
|
## Models
|
|
26
26
|
|
|
@@ -88,7 +88,7 @@ Use a Prisma transaction to prevent race conditions. Check stock availability be
|
|
|
88
88
|
|
|
89
89
|
```js
|
|
90
90
|
import { prisma } from "@__QUARK_SCOPE__/db";
|
|
91
|
-
import { AppError } from "@
|
|
91
|
+
import { AppError } from "@usequark/quark-core/errors";
|
|
92
92
|
|
|
93
93
|
export async function addToCart(cartId, variantId, quantity = 1) {
|
|
94
94
|
return prisma.$transaction(async (tx) => {
|
|
@@ -20,7 +20,7 @@ The catalog is the foundation of an ecommerce system. It defines what you sell,
|
|
|
20
20
|
- **Models** live in `packages/db/prisma/schema.prisma`. Every model needs `id`, `createdAt DateTime @default(now())`, `updatedAt DateTime @updatedAt`. After changes: `pnpm db:generate && pnpm db:migrate`.
|
|
21
21
|
- **Data access** goes through query helpers in `packages/db/src/queries.js` — never call `prisma.*` directly in pages/actions.
|
|
22
22
|
- **API routes** live in `apps/web/src/app/api/<resource>/`. Guard with `requireRole`, validate with Zod via `validateBody`, wrap mutations in `withCsrfProtection`. Follow `apps/web/src/app/api/users/route.js` as the reference shape.
|
|
23
|
-
- **Server Actions** use `"use server"`, Zod validation, and `AppError`/`ValidationError` from `@
|
|
23
|
+
- **Server Actions** use `"use server"`, Zod validation, and `AppError`/`ValidationError` from `@usequark/quark-core/errors`.
|
|
24
24
|
- **Admin views** live under `apps/web/src/app/admin/products/` and `apps/web/src/app/admin/categories/`.
|
|
25
25
|
|
|
26
26
|
## Models
|
|
@@ -127,8 +127,8 @@ export async function getCategoryTree() {
|
|
|
127
127
|
"use server";
|
|
128
128
|
import { z } from "zod";
|
|
129
129
|
import { prisma } from "@__QUARK_SCOPE__/db";
|
|
130
|
-
import { ValidationError, AppError } from "@
|
|
131
|
-
import { createLogger } from "@
|
|
130
|
+
import { ValidationError, AppError } from "@usequark/quark-core/errors";
|
|
131
|
+
import { createLogger } from "@usequark/quark-core";
|
|
132
132
|
|
|
133
133
|
const log = createLogger("action:product");
|
|
134
134
|
|
|
@@ -68,8 +68,8 @@ model OrderItem {
|
|
|
68
68
|
"use server";
|
|
69
69
|
import { z } from "zod";
|
|
70
70
|
import { prisma } from "@__QUARK_SCOPE__/db";
|
|
71
|
-
import { AppError, ValidationError } from "@
|
|
72
|
-
import { createLogger } from "@
|
|
71
|
+
import { AppError, ValidationError } from "@usequark/quark-core/errors";
|
|
72
|
+
import { createLogger } from "@usequark/quark-core";
|
|
73
73
|
|
|
74
74
|
const log = createLogger("action:checkout");
|
|
75
75
|
|
|
@@ -34,8 +34,8 @@ A localized app must handle locale detection, routing, content translation, and
|
|
|
34
34
|
- **Request config:** `getRequestConfig` from `next-intl/server` resolves the locale per request and loads message files.
|
|
35
35
|
- **Models:** CMS models get a `locale String` field. Queries filter by locale with fallback chain.
|
|
36
36
|
- **Validation** — Zod for all Server Actions and API routes. Use a locale enum for localized content submissions.
|
|
37
|
-
- **Auth** via `getCurrentSession` from `@
|
|
38
|
-
- **Locale utilities** from `@
|
|
37
|
+
- **Auth** via `getCurrentSession` from `@usequark/quark-core`.
|
|
38
|
+
- **Locale utilities** from `@usequark/quark-core/locale`: `getDefaultLocale()`, `getSupportedLocales()`, `isLocaleSupported()`.
|
|
39
39
|
|
|
40
40
|
## Workflow
|
|
41
41
|
|
|
@@ -52,7 +52,7 @@ A localized app must handle locale detection, routing, content translation, and
|
|
|
52
52
|
```js
|
|
53
53
|
// src/i18n/routing.js
|
|
54
54
|
import { defineRouting } from "next-intl/routing";
|
|
55
|
-
import { getDefaultLocale, getSupportedLocales } from "@
|
|
55
|
+
import { getDefaultLocale, getSupportedLocales } from "@usequark/quark-core/locale";
|
|
56
56
|
|
|
57
57
|
const supportedLocales = getSupportedLocales();
|
|
58
58
|
|
|
@@ -104,7 +104,7 @@ export const config = {
|
|
|
104
104
|
"use client";
|
|
105
105
|
import { useLocale, useTranslations } from "next-intl";
|
|
106
106
|
import { useRouter, usePathname } from "next/navigation";
|
|
107
|
-
import { getSupportedLocales } from "@
|
|
107
|
+
import { getSupportedLocales } from "@usequark/quark-core/locale";
|
|
108
108
|
|
|
109
109
|
export function LocaleSwitcher() {
|
|
110
110
|
const locale = useLocale();
|
|
@@ -152,7 +152,7 @@ model Page {
|
|
|
152
152
|
## Example: locale-aware query
|
|
153
153
|
|
|
154
154
|
```js
|
|
155
|
-
import { getDefaultLocale, isLocaleSupported } from "@
|
|
155
|
+
import { getDefaultLocale, isLocaleSupported } from "@usequark/quark-core/locale";
|
|
156
156
|
|
|
157
157
|
export async function getPageBySlug(slug, locale) {
|
|
158
158
|
const validLocale = isLocaleSupported(locale) ? locale : getDefaultLocale();
|
|
@@ -185,7 +185,7 @@ export async function generateMetadata({ params }) {
|
|
|
185
185
|
|
|
186
186
|
```js
|
|
187
187
|
import { z } from "zod";
|
|
188
|
-
import { isLocaleSupported } from "@
|
|
188
|
+
import { isLocaleSupported } from "@usequark/quark-core/locale";
|
|
189
189
|
|
|
190
190
|
export const localizedPageSchema = z.object({
|
|
191
191
|
title: z.string().min(1).max(255),
|
|
@@ -24,11 +24,11 @@ Key concepts:
|
|
|
24
24
|
|
|
25
25
|
## Framework context
|
|
26
26
|
|
|
27
|
-
- **Stripe client** — `createStripeClient()` from `@
|
|
28
|
-
- **Webhook route** — `apps/web/src/app/api/stripe/webhook/route.js`. Use `getStripeWebhookEvent()` from `@
|
|
27
|
+
- **Stripe client** — `createStripeClient()` from `@usequark/quark-core/stripe`. Reads `STRIPE_SECRET_KEY` from env.
|
|
28
|
+
- **Webhook route** — `apps/web/src/app/api/stripe/webhook/route.js`. Use `getStripeWebhookEvent()` from `@usequark/quark-core/stripe` to verify signatures.
|
|
29
29
|
- **Validation** — Zod for all incoming data. Webhook event data is already validated by Stripe's SDK.
|
|
30
|
-
- **Errors** — `AppError` / `ValidationError` from `@
|
|
31
|
-
- **Logging** — `createLogger("stripe:webhook")` from `@
|
|
30
|
+
- **Errors** — `AppError` / `ValidationError` from `@usequark/quark-core/errors` for app errors. Never throw on webhook failures — return 200 to prevent Stripe retries for unfixable errors.
|
|
31
|
+
- **Logging** — `createLogger("stripe:webhook")` from `@usequark/quark-core`.
|
|
32
32
|
- **Models** — add `stripeCustomerId String?` to User, `stripeSessionId String?` / `stripeSubscriptionId String?` to relevant models. Every model needs `createdAt` / `updatedAt`.
|
|
33
33
|
|
|
34
34
|
## Checkout sessions
|
|
@@ -49,7 +49,7 @@ export const checkoutSchema = z.object({
|
|
|
49
49
|
### One-time payment
|
|
50
50
|
|
|
51
51
|
```js
|
|
52
|
-
import { createStripeClient } from "@
|
|
52
|
+
import { createStripeClient } from "@usequark/quark-core/stripe";
|
|
53
53
|
|
|
54
54
|
const stripe = await createStripeClient();
|
|
55
55
|
const session = await stripe.checkout.sessions.create({
|
|
@@ -82,8 +82,8 @@ const session = await stripe.checkout.sessions.create({
|
|
|
82
82
|
```js
|
|
83
83
|
// apps/web/src/app/api/stripe/webhook/route.js
|
|
84
84
|
import { NextResponse } from "next/server";
|
|
85
|
-
import { getStripeWebhookEvent } from "@
|
|
86
|
-
import { createLogger } from "@
|
|
85
|
+
import { getStripeWebhookEvent } from "@usequark/quark-core/stripe";
|
|
86
|
+
import { createLogger } from "@usequark/quark-core";
|
|
87
87
|
import { prisma } from "@__QUARK_SCOPE__/db";
|
|
88
88
|
|
|
89
89
|
const log = createLogger("stripe:webhook");
|
|
@@ -180,7 +180,7 @@ model WebhookEvent {
|
|
|
180
180
|
### Create or retrieve Stripe customer
|
|
181
181
|
|
|
182
182
|
```js
|
|
183
|
-
import { createStripeClient } from "@
|
|
183
|
+
import { createStripeClient } from "@usequark/quark-core/stripe";
|
|
184
184
|
|
|
185
185
|
export async function getOrCreateStripeCustomer(user) {
|
|
186
186
|
if (user.stripeCustomerId) return user.stripeCustomerId;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @
|
|
2
|
+
* @usequark/quark-config - Environment Configuration
|
|
3
3
|
* Provides environment-specific defaults for dev, test, staging, and production.
|
|
4
4
|
* Each environment defines sensible defaults that can be overridden via env vars.
|
|
5
5
|
*/
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @
|
|
2
|
+
* @usequark/quark-config - Configuration Loader
|
|
3
3
|
* Centralised configuration management that combines environment validation,
|
|
4
4
|
* environment-specific defaults, and user overrides into a single config object.
|
|
5
5
|
*
|
|
6
6
|
* Usage:
|
|
7
|
-
* import { loadConfig } from "@
|
|
7
|
+
* import { loadConfig } from "@usequark/quark-config";
|
|
8
8
|
* const config = loadConfig(); // validates env + returns typed config
|
|
9
9
|
* const config = loadConfig({ cache: { defaultTtl: 120 } }); // with overrides
|
|
10
10
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createLogger } from "@
|
|
2
|
-
import { ValidationError } from "@
|
|
1
|
+
import { createLogger } from "@usequark/quark-core";
|
|
2
|
+
import { ValidationError } from "@usequark/quark-core/errors";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { syncNextAuthUrl } from "./app-url.js";
|
|
5
5
|
|
package/templates/jobs/README.md
CHANGED
|
@@ -41,11 +41,11 @@ Treat them as examples, not a required domain model.
|
|
|
41
41
|
1. Add a queue or job name in `src/definitions.js`
|
|
42
42
|
2. Create a handler in `apps/worker/src/handlers/`
|
|
43
43
|
3. Register that handler in `apps/worker/src/handlers/index.js`
|
|
44
|
-
4. Dispatch the job from the web app using `createQueue()` and `addJob()` from `@
|
|
44
|
+
4. Dispatch the job from the web app using `createQueue()` and `addJob()` from `@usequark/quark-core`
|
|
45
45
|
|
|
46
46
|
## Relationship to Quark Core
|
|
47
47
|
|
|
48
|
-
`@
|
|
48
|
+
`@usequark/quark-core` provides the queue infrastructure.
|
|
49
49
|
|
|
50
50
|
`@yourscope/jobs` defines **your** queue names and job names.
|
|
51
51
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Mobile equivalent of @
|
|
2
|
+
* Mobile equivalent of @usequark/quark-core's AppError.
|
|
3
3
|
*
|
|
4
4
|
* React Native cannot import Node.js packages, so this module defines a
|
|
5
5
|
* client-side error class whose shape mirrors AppError.toJSON() — same
|
|
@@ -16,7 +16,7 @@ pnpm dev # Starts worker with file watching
|
|
|
16
16
|
2. Create a handler in `apps/worker/src/handlers/<job-name>.js`:
|
|
17
17
|
|
|
18
18
|
```javascript
|
|
19
|
-
import { createLogger } from "@
|
|
19
|
+
import { createLogger } from "@usequark/quark-core";
|
|
20
20
|
|
|
21
21
|
const log = createLogger("job:my-task");
|
|
22
22
|
|
|
@@ -39,7 +39,7 @@ const jobHandlers = {
|
|
|
39
39
|
## Dispatching Jobs
|
|
40
40
|
|
|
41
41
|
```javascript
|
|
42
|
-
import { createQueue, addJob } from "@
|
|
42
|
+
import { createQueue, addJob } from "@usequark/quark-core";
|
|
43
43
|
import { JOB_NAMES } from "@yourscope/jobs";
|
|
44
44
|
|
|
45
45
|
const queue = createQueue("default");
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"packageManager": "pnpm@10.12.1",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@
|
|
26
|
-
"@
|
|
27
|
-
"@
|
|
28
|
-
"@
|
|
25
|
+
"@usequark/quark-config": "workspace:*",
|
|
26
|
+
"@usequark/quark-core": "^2.0.0",
|
|
27
|
+
"@usequark/quark-db": "workspace:*",
|
|
28
|
+
"@usequark/quark-jobs": "workspace:*",
|
|
29
29
|
"bullmq": "^6.3.8",
|
|
30
30
|
"jose": "^6.2.12"
|
|
31
31
|
},
|
|
@@ -7,9 +7,9 @@ import {
|
|
|
7
7
|
createEmailService,
|
|
8
8
|
passwordResetEmail,
|
|
9
9
|
welcomeEmail,
|
|
10
|
-
} from "@
|
|
11
|
-
import { prisma } from "@
|
|
12
|
-
import { JOB_NAMES } from "@
|
|
10
|
+
} from "@usequark/quark-core";
|
|
11
|
+
import { prisma } from "@usequark/quark-db";
|
|
12
|
+
import { JOB_NAMES } from "@usequark/quark-jobs";
|
|
13
13
|
import {
|
|
14
14
|
requireResetPasswordEmailData,
|
|
15
15
|
requireUserEmailRecord,
|
|
@@ -21,7 +21,7 @@ const emailService = createEmailService();
|
|
|
21
21
|
/**
|
|
22
22
|
* Job handler for SEND_WELCOME_EMAIL
|
|
23
23
|
* @param {import("bullmq").Job} bullJob
|
|
24
|
-
* @param {import("@
|
|
24
|
+
* @param {import("@usequark/quark-core").Logger} logger
|
|
25
25
|
*/
|
|
26
26
|
export async function handleSendWelcomeEmail(bullJob, logger) {
|
|
27
27
|
const userId = requireWelcomeEmailUserId(bullJob.data);
|
|
@@ -60,7 +60,7 @@ export async function handleSendWelcomeEmail(bullJob, logger) {
|
|
|
60
60
|
/**
|
|
61
61
|
* Job handler for SEND_RESET_PASSWORD_EMAIL
|
|
62
62
|
* @param {import("bullmq").Job} bullJob
|
|
63
|
-
* @param {import("@
|
|
63
|
+
* @param {import("@usequark/quark-core").Logger} logger
|
|
64
64
|
*/
|
|
65
65
|
export async function handleSendResetPasswordEmail(bullJob, logger) {
|
|
66
66
|
const { userId, resetUrl } = requireResetPasswordEmailData(bullJob.data);
|
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
* Processes file-related background jobs (cleanup, etc.)
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { createStorage } from "@
|
|
7
|
-
import { file } from "@
|
|
8
|
-
import { JOB_NAMES } from "@
|
|
6
|
+
import { createStorage } from "@usequark/quark-core";
|
|
7
|
+
import { file } from "@usequark/quark-db";
|
|
8
|
+
import { JOB_NAMES } from "@usequark/quark-jobs";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Job handler for CLEANUP_ORPHANED_FILES
|
|
12
12
|
* Deletes files with no owner that are older than a retention period.
|
|
13
13
|
*
|
|
14
14
|
* @param {import("bullmq").Job} bullJob
|
|
15
|
-
* @param {import("@
|
|
15
|
+
* @param {import("@usequark/quark-core").Logger} logger
|
|
16
16
|
*/
|
|
17
17
|
export async function handleCleanupOrphanedFiles(bullJob, logger) {
|
|
18
18
|
const retentionHours = bullJob.data?.retentionHours || 24;
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* No Firebase SDK — uses HTTP APIs with service account credentials from env.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { AppError, ValidationError } from "@
|
|
8
|
-
import { prisma } from "@
|
|
7
|
+
import { AppError, ValidationError } from "@usequark/quark-core/errors";
|
|
8
|
+
import { prisma } from "@usequark/quark-db";
|
|
9
9
|
import { importPKCS8, SignJWT } from "jose";
|
|
10
10
|
|
|
11
11
|
const APNS_KEY = process.env.APNS_KEY;
|
|
@@ -19,7 +19,7 @@ const GCP_SERVICE_ACCOUNT = process.env.GCP_SERVICE_ACCOUNT;
|
|
|
19
19
|
/**
|
|
20
20
|
* Job handler for SEND_PUSH_NOTIFICATION
|
|
21
21
|
* @param {import("bullmq").Job} bullJob
|
|
22
|
-
* @param {import("@
|
|
22
|
+
* @param {import("@usequark/quark-core").Logger} logger
|
|
23
23
|
*/
|
|
24
24
|
export async function handleSendPushNotification(bullJob, logger) {
|
|
25
25
|
const { userId, title, body: notificationBody, data } = bullJob.data;
|
|
@@ -11,10 +11,10 @@ import {
|
|
|
11
11
|
createWorker,
|
|
12
12
|
getRedisUrl,
|
|
13
13
|
updateQueueDepths,
|
|
14
|
-
} from "@
|
|
15
|
-
import { AppError } from "@
|
|
16
|
-
import { job, prisma } from "@
|
|
17
|
-
import { JOB_NAMES, JOB_QUEUES } from "@
|
|
14
|
+
} from "@usequark/quark-core";
|
|
15
|
+
import { AppError } from "@usequark/quark-core/errors";
|
|
16
|
+
import { job, prisma } from "@usequark/quark-db";
|
|
17
|
+
import { JOB_NAMES, JOB_QUEUES } from "@usequark/quark-jobs";
|
|
18
18
|
import { jobHandlers } from "./handlers/index.js";
|
|
19
19
|
|
|
20
20
|
const logger = createLogger("worker");
|
|
@@ -242,7 +242,7 @@ export async function waitForDatabase(
|
|
|
242
242
|
*/
|
|
243
243
|
async function preflight() {
|
|
244
244
|
// Load and validate environment variables
|
|
245
|
-
const { loadEnv } = await import("@
|
|
245
|
+
const { loadEnv } = await import("@usequark/quark-config");
|
|
246
246
|
loadEnv("worker");
|
|
247
247
|
|
|
248
248
|
logger.info("Running preflight health checks");
|
|
@@ -362,7 +362,7 @@ async function createQueueWorker(queueName) {
|
|
|
362
362
|
*/
|
|
363
363
|
async function startWorker() {
|
|
364
364
|
// Load and validate environment variables
|
|
365
|
-
const { loadEnv } = await import("@
|
|
365
|
+
const { loadEnv } = await import("@usequark/quark-config");
|
|
366
366
|
loadEnv("worker");
|
|
367
367
|
|
|
368
368
|
logger.info("Starting Quark Worker Service");
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Fetches estimated usage and deployment data from Railway's GraphQL API.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { createLogger } from "@
|
|
7
|
-
import { AppError } from "@
|
|
6
|
+
import { createLogger } from "@usequark/quark-core";
|
|
7
|
+
import { AppError } from "@usequark/quark-core/errors";
|
|
8
8
|
|
|
9
9
|
const log = createLogger("lib:railway");
|
|
10
10
|
|