feat: initial commit — storefront, convex backend, and shared packages

Completes the first milestone of The Pet Loft ecommerce platform:
- apps/storefront: full customer-facing Next.js app with HeroUI (cart,
  checkout, orders, wishlist, product detail, shop, search, auth)
- convex/: serverless backend with schema, queries, mutations, actions,
  HTTP routes, Stripe/Shippo integrations, and co-located tests
- packages/types, packages/utils, packages/convex: shared workspace packages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 09:31:18 +03:00
commit cc15338ad9
361 changed files with 45005 additions and 0 deletions

View File

@@ -0,0 +1,127 @@
import { describe, it, expect, expectTypeOf } from "vitest";
import type {
ShippoConfidenceScore,
ShippoValidationValue,
ShippoAddressType,
ShippoValidationReason,
RecommendedAddress,
AddressValidationResult,
} from "./checkout";
describe("AddressValidationResult types", () => {
it("ShippoConfidenceScore accepts valid literals", () => {
expectTypeOf<"high">().toMatchTypeOf<ShippoConfidenceScore>();
expectTypeOf<"medium">().toMatchTypeOf<ShippoConfidenceScore>();
expectTypeOf<"low">().toMatchTypeOf<ShippoConfidenceScore>();
});
it("ShippoValidationValue accepts valid literals", () => {
expectTypeOf<"valid">().toMatchTypeOf<ShippoValidationValue>();
expectTypeOf<"partially_valid">().toMatchTypeOf<ShippoValidationValue>();
expectTypeOf<"invalid">().toMatchTypeOf<ShippoValidationValue>();
});
it("ShippoAddressType accepts valid literals", () => {
expectTypeOf<"residential">().toMatchTypeOf<ShippoAddressType>();
expectTypeOf<"commercial">().toMatchTypeOf<ShippoAddressType>();
expectTypeOf<"unknown">().toMatchTypeOf<ShippoAddressType>();
expectTypeOf<"po_box">().toMatchTypeOf<ShippoAddressType>();
expectTypeOf<"military">().toMatchTypeOf<ShippoAddressType>();
});
it("ShippoValidationReason has code and description", () => {
expectTypeOf<ShippoValidationReason>().toHaveProperty("code");
expectTypeOf<ShippoValidationReason>().toHaveProperty("description");
});
it("RecommendedAddress has required fields and no state", () => {
expectTypeOf<RecommendedAddress>().toHaveProperty("addressLine1");
expectTypeOf<RecommendedAddress>().toHaveProperty("city");
expectTypeOf<RecommendedAddress>().toHaveProperty("postalCode");
expectTypeOf<RecommendedAddress>().toHaveProperty("country");
expectTypeOf<RecommendedAddress>().toHaveProperty("confidenceScore");
expectTypeOf<RecommendedAddress>().toHaveProperty("confidenceCode");
expectTypeOf<RecommendedAddress>().toHaveProperty("confidenceDescription");
type Keys = keyof RecommendedAddress;
expectTypeOf<"state" extends Keys ? true : false>().toEqualTypeOf<false>();
expectTypeOf<"addressLine2" extends Keys ? true : false>().toEqualTypeOf<false>();
});
it("AddressValidationResult is structurally complete", () => {
expectTypeOf<AddressValidationResult>().toHaveProperty("isValid");
expectTypeOf<AddressValidationResult>().toHaveProperty("validationValue");
expectTypeOf<AddressValidationResult>().toHaveProperty("reasons");
expectTypeOf<AddressValidationResult>().toHaveProperty("addressType");
expectTypeOf<AddressValidationResult>().toHaveProperty("changedAttributes");
expectTypeOf<AddressValidationResult>().toHaveProperty("originalAddress");
});
it("recommendedAddress is optional on AddressValidationResult", () => {
const withoutRecommended: AddressValidationResult = {
isValid: true,
validationValue: "valid",
reasons: [],
addressType: "unknown",
changedAttributes: [],
originalAddress: {
addressLine1: "10 Downing Street",
city: "London",
postalCode: "SW1A 2AA",
country: "GB",
},
};
expect(withoutRecommended.recommendedAddress).toBeUndefined();
});
it("AddressValidationResult accepts a full object with recommended address", () => {
const full: AddressValidationResult = {
isValid: false,
validationValue: "partially_valid",
reasons: [{ code: "postal_data_match", description: "Postal code matched" }],
addressType: "unknown",
changedAttributes: ["postalCode"],
recommendedAddress: {
addressLine1: "10 Downing Street",
city: "London",
postalCode: "SW1A 2AA",
country: "GB",
completeAddress: "10 Downing Street;LONDON;SW1A 2AA;UNITED KINGDOM",
confidenceScore: "high",
confidenceCode: "postal_data_match",
confidenceDescription: "Matched via postal data",
},
originalAddress: {
addressLine1: "10 Downing St",
city: "London",
postalCode: "SW1A2AA",
country: "GB",
},
};
expect(full.isValid).toBe(false);
expect(full.recommendedAddress).toBeDefined();
expect(full.recommendedAddress!.confidenceScore).toBe("high");
});
it("originalAddress uses additionalInformation instead of addressLine2", () => {
const result: AddressValidationResult = {
isValid: true,
validationValue: "valid",
reasons: [],
addressType: "unknown",
changedAttributes: [],
originalAddress: {
addressLine1: "10 Downing Street",
additionalInformation: "Flat 1",
city: "London",
postalCode: "SW1A 2AA",
country: "GB",
},
};
expect(result.originalAddress.additionalInformation).toBe("Flat 1");
type OrigKeys = keyof AddressValidationResult["originalAddress"];
expectTypeOf<"state" extends OrigKeys ? true : false>().toEqualTypeOf<false>();
expectTypeOf<"addressLine2" extends OrigKeys ? true : false>().toEqualTypeOf<false>();
});
});