385 lines
8.0 KiB
TypeScript
385 lines
8.0 KiB
TypeScript
/**
|
|
* rCart Automerge document schemas.
|
|
*
|
|
* Two document types:
|
|
* - Catalog: one doc per space holding all catalog entries.
|
|
* DocId: {space}:cart:catalog
|
|
* - Orders: one doc per order (server-validated via Intent/Claim).
|
|
* DocId: {space}:cart:orders:{orderId}
|
|
*/
|
|
|
|
import type { DocSchema } from '../../shared/local-first/document';
|
|
|
|
// ── Document types ──
|
|
|
|
export interface CatalogEntry {
|
|
id: string;
|
|
artifactId: string;
|
|
artifact: unknown;
|
|
title: string;
|
|
productType: string | null;
|
|
requiredCapabilities: string[];
|
|
substrates: string[];
|
|
creatorId: string | null;
|
|
sourceSpace: string | null;
|
|
tags: string[];
|
|
status: string;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
}
|
|
|
|
export interface CatalogDoc {
|
|
meta: {
|
|
module: string;
|
|
collection: string;
|
|
version: number;
|
|
spaceSlug: string;
|
|
createdAt: number;
|
|
};
|
|
items: Record<string, CatalogEntry>;
|
|
}
|
|
|
|
export interface OrderMeta {
|
|
id: string;
|
|
catalogEntryId: string;
|
|
artifactId: string;
|
|
buyerId: string | null;
|
|
buyerLocation: string | null;
|
|
buyerContact: string | null;
|
|
providerId: string | null;
|
|
providerName: string | null;
|
|
providerDistanceKm: number | null;
|
|
quantity: number;
|
|
productionCost: number | null;
|
|
creatorPayout: number | null;
|
|
communityPayout: number | null;
|
|
totalPrice: number | null;
|
|
currency: string;
|
|
status: string;
|
|
paymentMethod: string | null;
|
|
paymentTx: string | null;
|
|
paymentNetwork: string | null;
|
|
createdAt: number;
|
|
paidAt: number;
|
|
acceptedAt: number;
|
|
completedAt: number;
|
|
updatedAt: number;
|
|
}
|
|
|
|
export interface OrderDoc {
|
|
meta: {
|
|
module: string;
|
|
collection: string;
|
|
version: number;
|
|
spaceSlug: string;
|
|
createdAt: number;
|
|
};
|
|
order: OrderMeta;
|
|
}
|
|
|
|
// ── Schema registration ──
|
|
|
|
export const catalogSchema: DocSchema<CatalogDoc> = {
|
|
module: 'cart',
|
|
collection: 'catalog',
|
|
version: 1,
|
|
init: (): CatalogDoc => ({
|
|
meta: {
|
|
module: 'cart',
|
|
collection: 'catalog',
|
|
version: 1,
|
|
spaceSlug: '',
|
|
createdAt: Date.now(),
|
|
},
|
|
items: {},
|
|
}),
|
|
};
|
|
|
|
export const orderSchema: DocSchema<OrderDoc> = {
|
|
module: 'cart',
|
|
collection: 'orders',
|
|
version: 1,
|
|
init: (): OrderDoc => ({
|
|
meta: {
|
|
module: 'cart',
|
|
collection: 'orders',
|
|
version: 1,
|
|
spaceSlug: '',
|
|
createdAt: Date.now(),
|
|
},
|
|
order: {
|
|
id: '',
|
|
catalogEntryId: '',
|
|
artifactId: '',
|
|
buyerId: null,
|
|
buyerLocation: null,
|
|
buyerContact: null,
|
|
providerId: null,
|
|
providerName: null,
|
|
providerDistanceKm: null,
|
|
quantity: 1,
|
|
productionCost: null,
|
|
creatorPayout: null,
|
|
communityPayout: null,
|
|
totalPrice: null,
|
|
currency: 'USD',
|
|
status: 'pending',
|
|
paymentMethod: null,
|
|
paymentTx: null,
|
|
paymentNetwork: null,
|
|
createdAt: Date.now(),
|
|
paidAt: 0,
|
|
acceptedAt: 0,
|
|
completedAt: 0,
|
|
updatedAt: Date.now(),
|
|
},
|
|
}),
|
|
};
|
|
|
|
// ── Shopping Cart types ──
|
|
|
|
export type CartStatus = 'OPEN' | 'FUNDING' | 'FUNDED' | 'CHECKING_OUT' | 'ORDERED' | 'CLOSED';
|
|
|
|
export interface CartItemVendor {
|
|
name: string;
|
|
domain: string;
|
|
platform: string | null; // 'amazon' | 'shopify' | 'etsy' | null
|
|
}
|
|
|
|
export interface CartItem {
|
|
name: string;
|
|
price: number | null;
|
|
currency: string;
|
|
quantity: number;
|
|
sourceUrl: string;
|
|
imageUrl: string | null;
|
|
description: string | null;
|
|
vendor: CartItemVendor;
|
|
addedBy: string | null; // DID
|
|
addedAt: number;
|
|
sku: string | null;
|
|
}
|
|
|
|
export interface CartContribution {
|
|
userId: string | null;
|
|
username: string;
|
|
amount: number;
|
|
currency: string;
|
|
paymentMethod: string; // 'MANUAL' for MVP
|
|
status: string; // 'pending' | 'confirmed'
|
|
txHash: string | null;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
}
|
|
|
|
export interface CartEvent {
|
|
type: string; // 'item_added' | 'item_removed' | 'contribution' | 'status_change'
|
|
actor: string;
|
|
detail: string;
|
|
timestamp: number;
|
|
}
|
|
|
|
export interface ShoppingCartDoc {
|
|
meta: {
|
|
module: string;
|
|
collection: string;
|
|
version: number;
|
|
spaceSlug: string;
|
|
createdAt: number;
|
|
};
|
|
cart: {
|
|
id: string;
|
|
name: string;
|
|
description: string;
|
|
status: CartStatus;
|
|
createdBy: string | null;
|
|
targetAmount: number;
|
|
fundedAmount: number;
|
|
currency: string;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
};
|
|
items: Record<string, CartItem>;
|
|
contributions: Record<string, CartContribution>;
|
|
events: CartEvent[];
|
|
}
|
|
|
|
export interface ShoppingCartIndexEntry {
|
|
name: string;
|
|
status: CartStatus;
|
|
itemCount: number;
|
|
totalAmount: number;
|
|
fundedAmount: number;
|
|
currency: string;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
}
|
|
|
|
export interface ShoppingCartIndexDoc {
|
|
meta: {
|
|
module: string;
|
|
collection: string;
|
|
version: number;
|
|
spaceSlug: string;
|
|
createdAt: number;
|
|
};
|
|
carts: Record<string, ShoppingCartIndexEntry>;
|
|
}
|
|
|
|
// ── Shopping Cart schema registration ──
|
|
|
|
export const shoppingCartSchema: DocSchema<ShoppingCartDoc> = {
|
|
module: 'cart',
|
|
collection: 'shopping',
|
|
version: 1,
|
|
init: (): ShoppingCartDoc => ({
|
|
meta: {
|
|
module: 'cart',
|
|
collection: 'shopping',
|
|
version: 1,
|
|
spaceSlug: '',
|
|
createdAt: Date.now(),
|
|
},
|
|
cart: {
|
|
id: '',
|
|
name: '',
|
|
description: '',
|
|
status: 'OPEN',
|
|
createdBy: null,
|
|
targetAmount: 0,
|
|
fundedAmount: 0,
|
|
currency: 'USD',
|
|
createdAt: Date.now(),
|
|
updatedAt: Date.now(),
|
|
},
|
|
items: {},
|
|
contributions: {},
|
|
events: [],
|
|
}),
|
|
};
|
|
|
|
export const shoppingCartIndexSchema: DocSchema<ShoppingCartIndexDoc> = {
|
|
module: 'cart',
|
|
collection: 'shopping-index',
|
|
version: 1,
|
|
init: (): ShoppingCartIndexDoc => ({
|
|
meta: {
|
|
module: 'cart',
|
|
collection: 'shopping-index',
|
|
version: 1,
|
|
spaceSlug: '',
|
|
createdAt: Date.now(),
|
|
},
|
|
carts: {},
|
|
}),
|
|
};
|
|
|
|
// ── Payment Request types ──
|
|
|
|
export interface PaymentRequestMeta {
|
|
id: string;
|
|
description: string;
|
|
amount: string;
|
|
amountEditable: boolean;
|
|
token: string;
|
|
chainId: number;
|
|
recipientAddress: string;
|
|
fiatAmount: string | null;
|
|
fiatCurrency: string;
|
|
creatorDid: string;
|
|
status: 'pending' | 'paid' | 'confirmed' | 'expired' | 'cancelled' | 'filled';
|
|
paymentMethod: 'transak' | 'wallet' | 'encryptid' | null;
|
|
txHash: string | null;
|
|
payerIdentity: string | null;
|
|
transakOrderId: string | null;
|
|
// Payment type: one-time, recurring, or payer's choice
|
|
paymentType: 'single' | 'subscription' | 'payer_choice';
|
|
// Inventory: max number of payments (0 = unlimited)
|
|
maxPayments: number;
|
|
// How many have been paid
|
|
paymentCount: number;
|
|
// Which payment methods are enabled for payers
|
|
enabledMethods: {
|
|
card: boolean;
|
|
wallet: boolean;
|
|
encryptid: boolean;
|
|
};
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
paidAt: number;
|
|
expiresAt: number;
|
|
}
|
|
|
|
export interface PaymentRequestDoc {
|
|
meta: {
|
|
module: string;
|
|
collection: string;
|
|
version: number;
|
|
spaceSlug: string;
|
|
createdAt: number;
|
|
};
|
|
payment: PaymentRequestMeta;
|
|
}
|
|
|
|
export const paymentRequestSchema: DocSchema<PaymentRequestDoc> = {
|
|
module: 'cart',
|
|
collection: 'payments',
|
|
version: 1,
|
|
init: (): PaymentRequestDoc => ({
|
|
meta: {
|
|
module: 'cart',
|
|
collection: 'payments',
|
|
version: 1,
|
|
spaceSlug: '',
|
|
createdAt: Date.now(),
|
|
},
|
|
payment: {
|
|
id: '',
|
|
description: '',
|
|
amount: '0',
|
|
amountEditable: false,
|
|
token: 'USDC',
|
|
chainId: 8453,
|
|
recipientAddress: '',
|
|
fiatAmount: null,
|
|
fiatCurrency: 'USD',
|
|
creatorDid: '',
|
|
status: 'pending',
|
|
paymentMethod: null,
|
|
txHash: null,
|
|
payerIdentity: null,
|
|
transakOrderId: null,
|
|
paymentType: 'single',
|
|
maxPayments: 0,
|
|
paymentCount: 0,
|
|
enabledMethods: { card: true, wallet: true, encryptid: true },
|
|
createdAt: Date.now(),
|
|
updatedAt: Date.now(),
|
|
paidAt: 0,
|
|
expiresAt: 0,
|
|
},
|
|
}),
|
|
};
|
|
|
|
// ── Helpers ──
|
|
|
|
export function catalogDocId(space: string) {
|
|
return `${space}:cart:catalog` as const;
|
|
}
|
|
|
|
export function orderDocId(space: string, orderId: string) {
|
|
return `${space}:cart:orders:${orderId}` as const;
|
|
}
|
|
|
|
export function shoppingCartDocId(space: string, cartId: string) {
|
|
return `${space}:cart:shopping:${cartId}` as const;
|
|
}
|
|
|
|
export function shoppingCartIndexDocId(space: string) {
|
|
return `${space}:cart:shopping-index` as const;
|
|
}
|
|
|
|
export function paymentRequestDocId(space: string, paymentId: string) {
|
|
return `${space}:cart:payments:${paymentId}` as const;
|
|
}
|