@jarwizz/create-jarshop 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/README.md +10 -2
  2. package/dist/generator.js +10 -4
  3. package/dist/generator.js.map +1 -1
  4. package/dist/template/AGENTS.md +3 -3
  5. package/dist/template/CONTEXT.md +14 -0
  6. package/dist/template/README.md +25 -3
  7. package/dist/template/docker-compose.yml +5 -0
  8. package/dist/template/docs/smtp-smoke.md +37 -0
  9. package/dist/template/env.example.template +18 -0
  10. package/dist/template/gitignore.template +2 -0
  11. package/dist/template/package.json +19 -6
  12. package/dist/template/pnpm-lock.yaml +2389 -98
  13. package/dist/template/pnpm-workspace.yaml +12 -1
  14. package/dist/template/src/dev-storefront.ts +58 -0
  15. package/dist/template/src/dev.ts +67 -4
  16. package/dist/template/src/email-smoke.ts +27 -0
  17. package/dist/template/src/environment.d.ts +6 -0
  18. package/dist/template/src/migrate.ts +16 -0
  19. package/dist/template/src/migrations/1786024108434-jarshop-checkout-attempt.ts +28 -0
  20. package/dist/template/src/migrations/1786024108435-jarshop-legal-and-confirmation.ts +60 -0
  21. package/dist/template/src/migrations/1786024108436-jarshop-order-email-outbox.ts +37 -0
  22. package/dist/template/src/migrations/1786030000000-jarshop-order-email-delivery-lease.ts +27 -0
  23. package/dist/template/src/plugins/jarshop-checkout/checkout-attempt.entity.ts +42 -0
  24. package/dist/template/src/plugins/jarshop-checkout/cod-payment.test.ts +44 -0
  25. package/dist/template/src/plugins/jarshop-checkout/cod-payment.ts +28 -0
  26. package/dist/template/src/plugins/jarshop-checkout/confirmation-token.entity.ts +31 -0
  27. package/dist/template/src/plugins/jarshop-checkout/confirmation.ts +59 -0
  28. package/dist/template/src/plugins/jarshop-checkout/dashboard/index.tsx +107 -0
  29. package/dist/template/src/plugins/jarshop-checkout/dashboard/order-email-delivery-status.ts +43 -0
  30. package/dist/template/src/plugins/jarshop-checkout/email-smoke-core.ts +56 -0
  31. package/dist/template/src/plugins/jarshop-checkout/index.ts +51 -0
  32. package/dist/template/src/plugins/jarshop-checkout/jarshop-checkout.plugin.ts +870 -0
  33. package/dist/template/src/plugins/jarshop-checkout/legal.entity.ts +39 -0
  34. package/dist/template/src/plugins/jarshop-checkout/order-consent.entity.ts +32 -0
  35. package/dist/template/src/plugins/jarshop-checkout/order-email-delivery-core.ts +337 -0
  36. package/dist/template/src/plugins/jarshop-checkout/order-email-delivery-status.ts +39 -0
  37. package/dist/template/src/plugins/jarshop-checkout/order-email-delivery.entity.ts +66 -0
  38. package/dist/template/src/plugins/jarshop-checkout/order-email-outbox.ts +108 -0
  39. package/dist/template/src/plugins/jarshop-checkout/order-email-transport.ts +35 -0
  40. package/dist/template/src/plugins/jarshop-checkout/order-email-worker.ts +281 -0
  41. package/dist/template/src/plugins/jarshop-checkout/shipping.test.ts +41 -0
  42. package/dist/template/src/plugins/jarshop-checkout/shipping.ts +162 -0
  43. package/dist/template/src/seed.ts +171 -0
  44. package/dist/template/src/vendure-config.ts +72 -7
  45. package/dist/template/static/email/templates/email-verification/body.hbs +4 -4
  46. package/dist/template/storefront/app/[locale]/[slug]/add-to-cart-form.tsx +44 -0
  47. package/dist/template/storefront/app/[locale]/[slug]/page.tsx +35 -26
  48. package/dist/template/storefront/app/[locale]/account/account-mutation-form.tsx +44 -0
  49. package/dist/template/storefront/app/[locale]/account/change-password-form.tsx +65 -0
  50. package/dist/template/storefront/app/[locale]/account/login/login-form.tsx +60 -0
  51. package/dist/template/storefront/app/[locale]/account/login/page.tsx +23 -0
  52. package/dist/template/storefront/app/[locale]/account/page.tsx +215 -0
  53. package/dist/template/storefront/app/[locale]/account/password-reset/callback/route.ts +33 -0
  54. package/dist/template/storefront/app/[locale]/account/password-reset/complete/page.tsx +27 -0
  55. package/dist/template/storefront/app/[locale]/account/password-reset/page.tsx +37 -0
  56. package/dist/template/storefront/app/[locale]/account/password-reset/password-reset-forms.tsx +99 -0
  57. package/dist/template/storefront/app/[locale]/account/register/page.tsx +23 -0
  58. package/dist/template/storefront/app/[locale]/account/register/register-form.tsx +67 -0
  59. package/dist/template/storefront/app/[locale]/account/verify/complete/route.ts +33 -0
  60. package/dist/template/storefront/app/[locale]/account/verify/page.tsx +41 -0
  61. package/dist/template/storefront/app/[locale]/account/verify/refresh-form.tsx +35 -0
  62. package/dist/template/storefront/app/[locale]/cart/page.tsx +78 -0
  63. package/dist/template/storefront/app/[locale]/checkout/checkout-form.tsx +112 -0
  64. package/dist/template/storefront/app/[locale]/checkout/confirmation/route.ts +21 -0
  65. package/dist/template/storefront/app/[locale]/checkout/page.tsx +44 -0
  66. package/dist/template/storefront/app/[locale]/checkout/success/page.tsx +28 -0
  67. package/dist/template/storefront/app/[locale]/layout.tsx +48 -0
  68. package/dist/template/storefront/app/[locale]/page.tsx +12 -13
  69. package/dist/template/storefront/app/globals.css +372 -4
  70. package/dist/template/storefront/app/layout.tsx +13 -0
  71. package/dist/template/storefront/eslint.config.mjs +8 -1
  72. package/dist/template/storefront/gitignore.template +1 -0
  73. package/dist/template/storefront/lib/account-security.test.ts +74 -0
  74. package/dist/template/storefront/lib/account-security.ts +81 -0
  75. package/dist/template/storefront/lib/account.ts +366 -0
  76. package/dist/template/storefront/lib/cart-contract.ts +52 -0
  77. package/dist/template/storefront/lib/cart.test.ts +30 -0
  78. package/dist/template/storefront/lib/cart.ts +130 -0
  79. package/dist/template/storefront/lib/checkout-contract.test.ts +20 -0
  80. package/dist/template/storefront/lib/checkout-contract.ts +16 -0
  81. package/dist/template/storefront/lib/checkout.ts +149 -0
  82. package/dist/template/storefront/lib/commerce-session.test.ts +77 -0
  83. package/dist/template/storefront/lib/commerce-session.ts +85 -0
  84. package/dist/template/storefront/lib/commerce.ts +129 -4
  85. package/dist/template/storefront/lib/confirmation-cookie.ts +9 -0
  86. package/dist/template/storefront/lib/confirmation.ts +95 -0
  87. package/dist/template/storefront/lib/form-values.test.ts +14 -0
  88. package/dist/template/storefront/lib/form-values.ts +7 -0
  89. package/dist/template/storefront/lib/i18n.test.ts +50 -0
  90. package/dist/template/storefront/lib/i18n.ts +44 -0
  91. package/dist/template/storefront/lib/password-reset-token.test.ts +31 -0
  92. package/dist/template/storefront/lib/password-reset-token.ts +17 -0
  93. package/dist/template/storefront/lib/valkey-rate-limit.ts +72 -0
  94. package/dist/template/storefront/messages/en.json +89 -0
  95. package/dist/template/storefront/messages/sk.json +89 -0
  96. package/dist/template/storefront/next.config.ts +3 -1
  97. package/dist/template/storefront/package.json +11 -4
  98. package/dist/template/storefront/vitest.config.ts +8 -0
  99. package/dist/template/tsconfig.json +2 -1
  100. package/dist/template/turbo.json +8 -0
  101. package/dist/template/vite.config.mts +4 -1
  102. package/dist/template-manifest.json +1 -1
  103. package/dist/template.js +3 -0
  104. package/dist/template.js.map +1 -1
  105. package/package.json +1 -1
  106. package/dist/template/storefront/pnpm-lock.yaml +0 -3562
  107. package/dist/template/storefront/pnpm-workspace.yaml +0 -26
@@ -0,0 +1,107 @@
1
+ import { api, defineDashboardExtension, useQuery } from "@vendure/dashboard";
2
+ import { graphql } from "@/gql";
3
+ import {
4
+ getDashboardOrderId,
5
+ toOrderEmailDeliveryStatusPanel,
6
+ } from "./order-email-delivery-status.js";
7
+
8
+ const orderEmailDeliveryStatusDocument = graphql(`
9
+ query JarShopOrderEmailDeliveryStatus($orderId: ID!) {
10
+ jarShopOrderEmailDeliveryStatus(orderId: $orderId) {
11
+ status
12
+ attemptCount
13
+ nextAttemptAt
14
+ sentAt
15
+ lastErrorCode
16
+ }
17
+ }
18
+ `);
19
+
20
+ function formatDateTime(value: string): string {
21
+ return new Intl.DateTimeFormat(undefined, {
22
+ dateStyle: "medium",
23
+ timeStyle: "short",
24
+ }).format(new Date(value));
25
+ }
26
+
27
+ function OrderEmailDeliveryStatusBlock({ context }: { context: unknown }) {
28
+ const orderId = getDashboardOrderId((context as { entity?: unknown }).entity);
29
+ const query = useQuery({
30
+ queryKey: ["jarshop-order-email-delivery-status", orderId],
31
+ enabled: orderId !== undefined,
32
+ queryFn: () =>
33
+ api.query(orderEmailDeliveryStatusDocument, {
34
+ orderId: orderId ?? "",
35
+ }),
36
+ });
37
+
38
+ if (!orderId) return null;
39
+ if (query.isPending) {
40
+ return (
41
+ <p className="text-sm text-muted-foreground">Loading delivery status…</p>
42
+ );
43
+ }
44
+ if (query.isError) {
45
+ return (
46
+ <p className="text-sm text-destructive">
47
+ Delivery status is currently unavailable.
48
+ </p>
49
+ );
50
+ }
51
+
52
+ const panel = toOrderEmailDeliveryStatusPanel(
53
+ query.data?.jarShopOrderEmailDeliveryStatus,
54
+ );
55
+ if (panel.kind === "unavailable") {
56
+ return (
57
+ <p className="text-sm text-muted-foreground">
58
+ No JarShop order email is queued for this order.
59
+ </p>
60
+ );
61
+ }
62
+
63
+ return (
64
+ <dl className="grid gap-2 text-sm">
65
+ <div className="flex justify-between gap-4">
66
+ <dt className="text-muted-foreground">Status</dt>
67
+ <dd className="font-medium capitalize">{panel.status}</dd>
68
+ </div>
69
+ <div className="flex justify-between gap-4">
70
+ <dt className="text-muted-foreground">Attempts</dt>
71
+ <dd>{panel.attemptCount}</dd>
72
+ </div>
73
+ <div className="flex justify-between gap-4">
74
+ <dt className="text-muted-foreground">Next attempt</dt>
75
+ <dd>{formatDateTime(panel.nextAttemptAt)}</dd>
76
+ </div>
77
+ {panel.sentAt ? (
78
+ <div className="flex justify-between gap-4">
79
+ <dt className="text-muted-foreground">Sent</dt>
80
+ <dd>{formatDateTime(panel.sentAt)}</dd>
81
+ </div>
82
+ ) : null}
83
+ {panel.lastErrorCode ? (
84
+ <div className="flex justify-between gap-4">
85
+ <dt className="text-muted-foreground">Error code</dt>
86
+ <dd className="font-mono text-xs">{panel.lastErrorCode}</dd>
87
+ </div>
88
+ ) : null}
89
+ </dl>
90
+ );
91
+ }
92
+
93
+ defineDashboardExtension({
94
+ pageBlocks: [
95
+ {
96
+ id: "jarshop-order-email-delivery-status",
97
+ title: "Email delivery",
98
+ location: {
99
+ pageId: "order-detail",
100
+ column: "side",
101
+ position: { blockId: "state", order: "after" },
102
+ },
103
+ component: OrderEmailDeliveryStatusBlock,
104
+ requiresPermission: "ReadOrder",
105
+ },
106
+ ],
107
+ });
@@ -0,0 +1,43 @@
1
+ export type OrderEmailDeliveryStatusPanel =
2
+ | { kind: "unavailable" }
3
+ | {
4
+ kind: "ready";
5
+ status: "pending" | "processing" | "sent" | "failed";
6
+ attemptCount: number;
7
+ nextAttemptAt: string;
8
+ sentAt: string | null;
9
+ lastErrorCode: string | null;
10
+ };
11
+
12
+ export function getDashboardOrderId(entity: unknown): string | undefined {
13
+ if (!entity || typeof entity !== "object") return undefined;
14
+ const id = (entity as { id?: unknown }).id;
15
+ if (typeof id === "string" && id.trim()) return id;
16
+ if (typeof id === "number" && Number.isSafeInteger(id) && id > 0) {
17
+ return String(id);
18
+ }
19
+ return undefined;
20
+ }
21
+
22
+ export function toOrderEmailDeliveryStatusPanel(
23
+ delivery:
24
+ | {
25
+ status: "pending" | "processing" | "sent" | "failed";
26
+ attemptCount: number;
27
+ nextAttemptAt: string;
28
+ sentAt: string | null;
29
+ lastErrorCode: string | null;
30
+ }
31
+ | null
32
+ | undefined,
33
+ ): OrderEmailDeliveryStatusPanel {
34
+ if (!delivery) return { kind: "unavailable" };
35
+ return {
36
+ kind: "ready",
37
+ status: delivery.status,
38
+ attemptCount: delivery.attemptCount,
39
+ nextAttemptAt: delivery.nextAttemptAt,
40
+ sentAt: delivery.sentAt,
41
+ lastErrorCode: delivery.lastErrorCode,
42
+ };
43
+ }
@@ -0,0 +1,56 @@
1
+ import {
2
+ readOrderEmailTransportConfiguration,
3
+ type SmtpOrderEmailTransportConfiguration,
4
+ } from "./order-email-delivery-core.js";
5
+
6
+ type Environment = Readonly<Record<string, string | undefined>>;
7
+
8
+ export type SmtpSmokeCommand = {
9
+ recipient: string;
10
+ configuration: SmtpOrderEmailTransportConfiguration;
11
+ };
12
+
13
+ export function parseSmtpSmokeCommand(
14
+ arguments_: readonly string[],
15
+ environment: Environment,
16
+ ): SmtpSmokeCommand {
17
+ if (environment.APP_ENV !== "staging") {
18
+ throw new Error("SMTP smoke is allowed only when APP_ENV=staging");
19
+ }
20
+ if (!arguments_.includes("--confirm-external-send")) {
21
+ throw new Error("SMTP smoke requires --confirm-external-send");
22
+ }
23
+ const recipient = readRecipient(arguments_);
24
+ const configuration = readOrderEmailTransportConfiguration(environment);
25
+ if (configuration.kind !== "smtp") {
26
+ throw new Error("SMTP smoke requires JARSHOP_EMAIL_TRANSPORT=smtp");
27
+ }
28
+ return { recipient, configuration };
29
+ }
30
+
31
+ function readRecipient(arguments_: readonly string[]): string {
32
+ const toIndex = arguments_.indexOf("--to");
33
+ const recipient =
34
+ toIndex === -1 ? undefined : arguments_[toIndex + 1]?.trim();
35
+ if (recipient === undefined || !isEmailAddress(recipient)) {
36
+ throw new Error("SMTP smoke requires a valid --to email address");
37
+ }
38
+ if (
39
+ arguments_.some(
40
+ (argument, index) =>
41
+ (argument === "--to" && index !== toIndex) ||
42
+ (argument !== "--to" &&
43
+ argument !== "--confirm-external-send" &&
44
+ index !== toIndex + 1),
45
+ )
46
+ ) {
47
+ throw new Error(
48
+ "SMTP smoke supports only --to and --confirm-external-send",
49
+ );
50
+ }
51
+ return recipient;
52
+ }
53
+
54
+ function isEmailAddress(value: string): boolean {
55
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/u.test(value);
56
+ }
@@ -0,0 +1,51 @@
1
+ export { CheckoutAttempt } from "./checkout-attempt.entity.js";
2
+ export type { CheckoutAttemptStatus } from "./checkout-attempt.entity.js";
3
+ export { jarShopCodPaymentHandler } from "./cod-payment.js";
4
+ export { JarShopConfirmationToken } from "./confirmation-token.entity.js";
5
+ export {
6
+ CONFIRMATION_TTL_MS,
7
+ CONFIRMATION_COOKIE_NAME,
8
+ canExchangeConfirmationToken,
9
+ canReadConfirmationCredential,
10
+ createConfirmationToken,
11
+ hashConfirmationToken,
12
+ readCookieValue,
13
+ } from "./confirmation.js";
14
+ export { JarShopLegalConfiguration } from "./legal.entity.js";
15
+ export { JarShopOrderEmailDelivery } from "./order-email-delivery.entity.js";
16
+ export type { OrderEmailDeliveryStatus } from "./order-email-delivery.entity.js";
17
+ export {
18
+ assertOrderEmailOutboxEncryptionConfiguration,
19
+ createPendingOrderEmailDelivery,
20
+ decryptOrderEmailOutboxPayload,
21
+ encryptOrderEmailOutboxPayload,
22
+ parseOrderEmailEncryptionKey,
23
+ } from "./order-email-outbox.js";
24
+ export {
25
+ assertOrderEmailDeliveryConfiguration,
26
+ createFileOrderEmailTransport,
27
+ createSmtpOrderEmailTransport,
28
+ orderEmailDeliveryPolicy,
29
+ readOrderEmailTransportConfiguration,
30
+ registerUniqueScheduledTask,
31
+ renderOrderConfirmationEmail,
32
+ scheduleOrderEmailRetry,
33
+ sanitizeFileTransportEmail,
34
+ writeSanitizedFileTransport,
35
+ } from "./order-email-delivery-core.js";
36
+ export type {
37
+ OrderConfirmationEmail,
38
+ OrderConfirmationEmailInput,
39
+ OrderEmailLanguageCode,
40
+ OrderEmailTransport,
41
+ OrderEmailTransportConfiguration,
42
+ SmtpOrderEmailTransportConfiguration,
43
+ } from "./order-email-delivery-core.js";
44
+ export { createConfiguredOrderEmailTransport } from "./order-email-transport.js";
45
+ export { parseSmtpSmokeCommand } from "./email-smoke-core.js";
46
+ export {
47
+ jarShopOrderEmailWorkerTask,
48
+ registerJarShopOrderEmailWorkerTask,
49
+ } from "./order-email-worker.js";
50
+ export { JarShopOrderConsent } from "./order-consent.entity.js";
51
+ export { JarShopCheckoutPlugin } from "./jarshop-checkout.plugin.js";