@revealui/contracts 1.0.0
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 +22 -0
- package/README.md +160 -0
- package/dist/a2a/index.d.ts +383 -0
- package/dist/a2a/index.d.ts.map +1 -0
- package/dist/a2a/index.js +276 -0
- package/dist/a2a/index.js.map +1 -0
- package/dist/actions/action-validator.d.ts +48 -0
- package/dist/actions/action-validator.d.ts.map +1 -0
- package/dist/actions/action-validator.js +288 -0
- package/dist/actions/action-validator.js.map +1 -0
- package/dist/actions/index.d.ts +7 -0
- package/dist/actions/index.d.ts.map +1 -0
- package/dist/actions/index.js +7 -0
- package/dist/actions/index.js.map +1 -0
- package/dist/agents/index.d.ts +628 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +511 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/types.d.ts +22 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/types.js +2 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/api/auth.d.ts +60 -0
- package/dist/api/auth.d.ts.map +1 -0
- package/dist/api/auth.js +84 -0
- package/dist/api/auth.js.map +1 -0
- package/dist/api/chat.d.ts +45 -0
- package/dist/api/chat.d.ts.map +1 -0
- package/dist/api/chat.js +55 -0
- package/dist/api/chat.js.map +1 -0
- package/dist/api/gdpr.d.ts +39 -0
- package/dist/api/gdpr.d.ts.map +1 -0
- package/dist/api/gdpr.js +53 -0
- package/dist/api/gdpr.js.map +1 -0
- package/dist/cms/collection.d.ts +108 -0
- package/dist/cms/collection.d.ts.map +1 -0
- package/dist/cms/collection.js +144 -0
- package/dist/cms/collection.js.map +1 -0
- package/dist/cms/compat.d.ts +128 -0
- package/dist/cms/compat.d.ts.map +1 -0
- package/dist/cms/compat.js +141 -0
- package/dist/cms/compat.js.map +1 -0
- package/dist/cms/config-contract.d.ts +278 -0
- package/dist/cms/config-contract.d.ts.map +1 -0
- package/dist/cms/config-contract.js +220 -0
- package/dist/cms/config-contract.js.map +1 -0
- package/dist/cms/config.d.ts +351 -0
- package/dist/cms/config.d.ts.map +1 -0
- package/dist/cms/config.js +50 -0
- package/dist/cms/config.js.map +1 -0
- package/dist/cms/errors.d.ts +122 -0
- package/dist/cms/errors.d.ts.map +1 -0
- package/dist/cms/errors.js +163 -0
- package/dist/cms/errors.js.map +1 -0
- package/dist/cms/extensibility.d.ts +211 -0
- package/dist/cms/extensibility.d.ts.map +1 -0
- package/dist/cms/extensibility.js +313 -0
- package/dist/cms/extensibility.js.map +1 -0
- package/dist/cms/field.d.ts +69 -0
- package/dist/cms/field.d.ts.map +1 -0
- package/dist/cms/field.js +94 -0
- package/dist/cms/field.js.map +1 -0
- package/dist/cms/functions.d.ts +466 -0
- package/dist/cms/functions.d.ts.map +1 -0
- package/dist/cms/functions.js +19 -0
- package/dist/cms/functions.js.map +1 -0
- package/dist/cms/global.d.ts +45 -0
- package/dist/cms/global.d.ts.map +1 -0
- package/dist/cms/global.js +62 -0
- package/dist/cms/global.js.map +1 -0
- package/dist/cms/index.d.ts +23 -0
- package/dist/cms/index.d.ts.map +1 -0
- package/dist/cms/index.js +42 -0
- package/dist/cms/index.js.map +1 -0
- package/dist/cms/structure.d.ts +1601 -0
- package/dist/cms/structure.d.ts.map +1 -0
- package/dist/cms/structure.js +757 -0
- package/dist/cms/structure.js.map +1 -0
- package/dist/content/index.d.ts +1542 -0
- package/dist/content/index.d.ts.map +1 -0
- package/dist/content/index.js +522 -0
- package/dist/content/index.js.map +1 -0
- package/dist/database/bridge.d.ts +177 -0
- package/dist/database/bridge.d.ts.map +1 -0
- package/dist/database/bridge.js +139 -0
- package/dist/database/bridge.js.map +1 -0
- package/dist/database/index.d.ts +8 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +9 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/type-bridge.d.ts +178 -0
- package/dist/database/type-bridge.d.ts.map +1 -0
- package/dist/database/type-bridge.js +154 -0
- package/dist/database/type-bridge.js.map +1 -0
- package/dist/entities/agent-context.d.ts +280 -0
- package/dist/entities/agent-context.d.ts.map +1 -0
- package/dist/entities/agent-context.js +390 -0
- package/dist/entities/agent-context.js.map +1 -0
- package/dist/entities/agent-memory.d.ts +661 -0
- package/dist/entities/agent-memory.d.ts.map +1 -0
- package/dist/entities/agent-memory.js +544 -0
- package/dist/entities/agent-memory.js.map +1 -0
- package/dist/entities/board.d.ts +95 -0
- package/dist/entities/board.d.ts.map +1 -0
- package/dist/entities/board.js +99 -0
- package/dist/entities/board.js.map +1 -0
- package/dist/entities/code-provenance.d.ts +270 -0
- package/dist/entities/code-provenance.d.ts.map +1 -0
- package/dist/entities/code-provenance.js +339 -0
- package/dist/entities/code-provenance.js.map +1 -0
- package/dist/entities/index.d.ts +22 -0
- package/dist/entities/index.d.ts.map +1 -0
- package/dist/entities/index.js +22 -0
- package/dist/entities/index.js.map +1 -0
- package/dist/entities/media.d.ts +485 -0
- package/dist/entities/media.d.ts.map +1 -0
- package/dist/entities/media.js +606 -0
- package/dist/entities/media.js.map +1 -0
- package/dist/entities/page-revision.d.ts +390 -0
- package/dist/entities/page-revision.d.ts.map +1 -0
- package/dist/entities/page-revision.js +406 -0
- package/dist/entities/page-revision.js.map +1 -0
- package/dist/entities/page.d.ts +2349 -0
- package/dist/entities/page.d.ts.map +1 -0
- package/dist/entities/page.js +377 -0
- package/dist/entities/page.js.map +1 -0
- package/dist/entities/post.d.ts +619 -0
- package/dist/entities/post.d.ts.map +1 -0
- package/dist/entities/post.js +555 -0
- package/dist/entities/post.js.map +1 -0
- package/dist/entities/price.d.ts +772 -0
- package/dist/entities/price.d.ts.map +1 -0
- package/dist/entities/price.js +308 -0
- package/dist/entities/price.js.map +1 -0
- package/dist/entities/product.d.ts +753 -0
- package/dist/entities/product.d.ts.map +1 -0
- package/dist/entities/product.js +307 -0
- package/dist/entities/product.js.map +1 -0
- package/dist/entities/session.d.ts +222 -0
- package/dist/entities/session.d.ts.map +1 -0
- package/dist/entities/session.js +253 -0
- package/dist/entities/session.js.map +1 -0
- package/dist/entities/site.d.ts +387 -0
- package/dist/entities/site.d.ts.map +1 -0
- package/dist/entities/site.js +348 -0
- package/dist/entities/site.js.map +1 -0
- package/dist/entities/ticket-comment.d.ts +49 -0
- package/dist/entities/ticket-comment.d.ts.map +1 -0
- package/dist/entities/ticket-comment.js +58 -0
- package/dist/entities/ticket-comment.js.map +1 -0
- package/dist/entities/ticket-label.d.ts +64 -0
- package/dist/entities/ticket-label.d.ts.map +1 -0
- package/dist/entities/ticket-label.js +77 -0
- package/dist/entities/ticket-label.js.map +1 -0
- package/dist/entities/ticket.d.ts +204 -0
- package/dist/entities/ticket.d.ts.map +1 -0
- package/dist/entities/ticket.js +205 -0
- package/dist/entities/ticket.js.map +1 -0
- package/dist/entities/user.d.ts +336 -0
- package/dist/entities/user.d.ts.map +1 -0
- package/dist/entities/user.js +255 -0
- package/dist/entities/user.js.map +1 -0
- package/dist/foundation/contract.d.ts +221 -0
- package/dist/foundation/contract.d.ts.map +1 -0
- package/dist/foundation/contract.js +133 -0
- package/dist/foundation/contract.js.map +1 -0
- package/dist/foundation/index.d.ts +7 -0
- package/dist/foundation/index.d.ts.map +1 -0
- package/dist/foundation/index.js +7 -0
- package/dist/foundation/index.js.map +1 -0
- package/dist/generated/contracts.d.ts +1514 -0
- package/dist/generated/contracts.d.ts.map +1 -0
- package/dist/generated/contracts.js +959 -0
- package/dist/generated/contracts.js.map +1 -0
- package/dist/generated/database.d.ts +48 -0
- package/dist/generated/database.d.ts.map +1 -0
- package/dist/generated/database.js +17 -0
- package/dist/generated/database.js.map +1 -0
- package/dist/generated/zod-schemas.d.ts +14793 -0
- package/dist/generated/zod-schemas.d.ts.map +1 -0
- package/dist/generated/zod-schemas.js +547 -0
- package/dist/generated/zod-schemas.js.map +1 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +81 -0
- package/dist/index.js.map +1 -0
- package/dist/representation/index.d.ts +304 -0
- package/dist/representation/index.d.ts.map +1 -0
- package/dist/representation/index.js +280 -0
- package/dist/representation/index.js.map +1 -0
- package/package.json +117 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product.d.ts","sourceRoot":"","sources":["../../src/entities/product.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Product Schema
|
|
3
|
+
*
|
|
4
|
+
* Products represent Stripe-backed product information with associated pricing.
|
|
5
|
+
* They support content management and integrate with RevealUI's CMS.
|
|
6
|
+
*
|
|
7
|
+
* This schema provides:
|
|
8
|
+
* - Stripe product validation (prod_xxx format)
|
|
9
|
+
* - Stripe product data structure validation
|
|
10
|
+
* - Business rules (published products require valid Stripe data)
|
|
11
|
+
* - Type-safe relationship handling
|
|
12
|
+
* - Runtime validation with Zod
|
|
13
|
+
*/
|
|
14
|
+
import { z } from 'zod/v4';
|
|
15
|
+
import { createContract } from '../foundation/contract.js';
|
|
16
|
+
import { DualEntitySchema } from '../representation/index.js';
|
|
17
|
+
// =============================================================================
|
|
18
|
+
// Schema Version
|
|
19
|
+
// =============================================================================
|
|
20
|
+
export const PRODUCT_SCHEMA_VERSION = 1;
|
|
21
|
+
// =============================================================================
|
|
22
|
+
// Stripe Product Format
|
|
23
|
+
// =============================================================================
|
|
24
|
+
/**
|
|
25
|
+
* Stripe Product ID format: prod_xxxxx
|
|
26
|
+
* @example "prod_MowQVLkdIwHu7ixraBm864M"
|
|
27
|
+
*/
|
|
28
|
+
export const StripeProductIDSchema = z
|
|
29
|
+
.string()
|
|
30
|
+
.regex(/^prod_[a-zA-Z0-9]+$/, {
|
|
31
|
+
message: 'Stripe Product ID must match format: prod_xxxxx',
|
|
32
|
+
})
|
|
33
|
+
.min(14) // prod_ + minimum ID length
|
|
34
|
+
.max(100);
|
|
35
|
+
// =============================================================================
|
|
36
|
+
// Stripe Product Data
|
|
37
|
+
// =============================================================================
|
|
38
|
+
/**
|
|
39
|
+
* Stripe Product object structure (subset of fields from Stripe API)
|
|
40
|
+
* Stored as JSON in product metadata
|
|
41
|
+
*/
|
|
42
|
+
export const StripeProductDataSchema = z.object({
|
|
43
|
+
id: z.string(),
|
|
44
|
+
object: z.literal('product'),
|
|
45
|
+
active: z.boolean(),
|
|
46
|
+
name: z.string(),
|
|
47
|
+
description: z.string().nullable().optional(),
|
|
48
|
+
metadata: z.record(z.string(), z.string()).optional(),
|
|
49
|
+
images: z.array(z.string()).optional(),
|
|
50
|
+
features: z.array(z.object({ name: z.string() })).optional(),
|
|
51
|
+
default_price: z.string().nullable().optional(), // Default price ID
|
|
52
|
+
shippable: z.boolean().optional(),
|
|
53
|
+
url: z.string().nullable().optional(),
|
|
54
|
+
});
|
|
55
|
+
/**
|
|
56
|
+
* Stripe Price List (stored in priceJSON)
|
|
57
|
+
*/
|
|
58
|
+
export const StripePriceListSchema = z.object({
|
|
59
|
+
object: z.literal('list'),
|
|
60
|
+
data: z.array(z.object({
|
|
61
|
+
id: z.string(),
|
|
62
|
+
object: z.literal('price'),
|
|
63
|
+
active: z.boolean().optional(),
|
|
64
|
+
currency: z.string().length(3),
|
|
65
|
+
unit_amount: z.number().int().nonnegative().nullable().optional(),
|
|
66
|
+
type: z.enum(['one_time', 'recurring']).optional(),
|
|
67
|
+
recurring: z
|
|
68
|
+
.object({
|
|
69
|
+
interval: z.enum(['day', 'week', 'month', 'year']),
|
|
70
|
+
interval_count: z.number().int().positive(),
|
|
71
|
+
})
|
|
72
|
+
.optional(),
|
|
73
|
+
})),
|
|
74
|
+
has_more: z.boolean(),
|
|
75
|
+
});
|
|
76
|
+
// =============================================================================
|
|
77
|
+
// Product Status
|
|
78
|
+
// =============================================================================
|
|
79
|
+
export const ProductStatusSchema = z.enum(['draft', 'published']);
|
|
80
|
+
// =============================================================================
|
|
81
|
+
// Content Blocks
|
|
82
|
+
// =============================================================================
|
|
83
|
+
const ProductBlockSchema = z
|
|
84
|
+
.object({
|
|
85
|
+
blockType: z.string(),
|
|
86
|
+
blockName: z.string().optional(),
|
|
87
|
+
})
|
|
88
|
+
.passthrough();
|
|
89
|
+
// =============================================================================
|
|
90
|
+
// Product Base Schema
|
|
91
|
+
// =============================================================================
|
|
92
|
+
// Base object schema without refinements (for extending)
|
|
93
|
+
const ProductObjectSchema = DualEntitySchema.extend({
|
|
94
|
+
/** Schema version for migrations */
|
|
95
|
+
schemaVersion: z.number().int().default(PRODUCT_SCHEMA_VERSION),
|
|
96
|
+
/** Numeric ID (from CMS) */
|
|
97
|
+
id: z.number().int().positive(),
|
|
98
|
+
/** Product title */
|
|
99
|
+
title: z.string().min(1).max(200),
|
|
100
|
+
/** Published date */
|
|
101
|
+
publishedOn: z.string().datetime().nullable().optional(),
|
|
102
|
+
/** Content layout blocks */
|
|
103
|
+
layout: z.array(ProductBlockSchema).nullable().optional(),
|
|
104
|
+
/** Stripe Product ID (validated format) */
|
|
105
|
+
stripeProductID: StripeProductIDSchema.nullable().optional(),
|
|
106
|
+
/** Stripe price list (JSON string) */
|
|
107
|
+
priceJSON: z
|
|
108
|
+
.string()
|
|
109
|
+
.nullable()
|
|
110
|
+
.optional()
|
|
111
|
+
.transform((val) => {
|
|
112
|
+
if (!val)
|
|
113
|
+
return null;
|
|
114
|
+
try {
|
|
115
|
+
return JSON.parse(val);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
.pipe(StripePriceListSchema.nullable()),
|
|
122
|
+
/** Enable paywall */
|
|
123
|
+
enablePaywall: z.boolean().nullable().optional(),
|
|
124
|
+
/** Paywall content blocks */
|
|
125
|
+
paywall: z.array(ProductBlockSchema).nullable().optional(),
|
|
126
|
+
/** Categories (populated or IDs) */
|
|
127
|
+
categories: z
|
|
128
|
+
.array(z.union([z.number().int().positive(), z.object({}).passthrough()]))
|
|
129
|
+
.nullable()
|
|
130
|
+
.optional(),
|
|
131
|
+
/** Related products (populated or IDs) */
|
|
132
|
+
relatedProducts: z
|
|
133
|
+
.array(z.union([z.number().int().positive(), z.object({}).passthrough()]))
|
|
134
|
+
.nullable()
|
|
135
|
+
.optional(),
|
|
136
|
+
/** Skip Stripe sync flag */
|
|
137
|
+
skipSync: z.boolean().nullable().optional(),
|
|
138
|
+
/** Timestamps */
|
|
139
|
+
updatedAt: z.string().datetime(),
|
|
140
|
+
createdAt: z.string().datetime(),
|
|
141
|
+
/** CMS status */
|
|
142
|
+
_status: ProductStatusSchema.nullable().optional(),
|
|
143
|
+
});
|
|
144
|
+
// Full schema with business rule refinements
|
|
145
|
+
const ProductBaseSchema = ProductObjectSchema.refine((data) => {
|
|
146
|
+
// Business rule: published products must have a valid Stripe product
|
|
147
|
+
if (data._status === 'published') {
|
|
148
|
+
return !!data.stripeProductID;
|
|
149
|
+
}
|
|
150
|
+
return true;
|
|
151
|
+
}, {
|
|
152
|
+
message: 'Published products must have a valid Stripe Product ID',
|
|
153
|
+
path: ['stripeProductID'],
|
|
154
|
+
});
|
|
155
|
+
/** Main schema export */
|
|
156
|
+
export const ProductSchema = ProductBaseSchema;
|
|
157
|
+
// =============================================================================
|
|
158
|
+
// Create Product Input
|
|
159
|
+
// =============================================================================
|
|
160
|
+
export const CreateProductInputSchema = z.object({
|
|
161
|
+
title: z.string().min(1).max(200),
|
|
162
|
+
stripeProductID: StripeProductIDSchema.optional(),
|
|
163
|
+
enablePaywall: z.boolean().optional(),
|
|
164
|
+
categories: z.array(z.number().int().positive()).optional(),
|
|
165
|
+
relatedProducts: z.array(z.number().int().positive()).optional(),
|
|
166
|
+
_status: ProductStatusSchema.optional(),
|
|
167
|
+
});
|
|
168
|
+
// =============================================================================
|
|
169
|
+
// Update Product Input
|
|
170
|
+
// =============================================================================
|
|
171
|
+
export const UpdateProductInputSchema = CreateProductInputSchema.partial();
|
|
172
|
+
// =============================================================================
|
|
173
|
+
// Product with Populated Relationships
|
|
174
|
+
// =============================================================================
|
|
175
|
+
/**
|
|
176
|
+
* Product with categories populated
|
|
177
|
+
*/
|
|
178
|
+
export const ProductWithCategoriesSchema = ProductObjectSchema.extend({
|
|
179
|
+
categories: z.array(z.object({ id: z.number(), name: z.string() }).passthrough()).nullable(),
|
|
180
|
+
});
|
|
181
|
+
/**
|
|
182
|
+
* Product with all relationships populated
|
|
183
|
+
*/
|
|
184
|
+
export const ProductWithRelatedSchema = ProductObjectSchema.extend({
|
|
185
|
+
categories: z.array(z.object({ id: z.number(), name: z.string() }).passthrough()).nullable(),
|
|
186
|
+
relatedProducts: z
|
|
187
|
+
.array(z.object({
|
|
188
|
+
id: z.number(),
|
|
189
|
+
title: z.string(),
|
|
190
|
+
stripeProductID: z.string().nullable(),
|
|
191
|
+
}))
|
|
192
|
+
.nullable(),
|
|
193
|
+
});
|
|
194
|
+
// =============================================================================
|
|
195
|
+
// Type Guards
|
|
196
|
+
// =============================================================================
|
|
197
|
+
/**
|
|
198
|
+
* Check if product has a valid Stripe product configured
|
|
199
|
+
*/
|
|
200
|
+
export function hasStripeProduct(product) {
|
|
201
|
+
return !!product.stripeProductID;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Check if product is published
|
|
205
|
+
*/
|
|
206
|
+
export function isPublishedProduct(product) {
|
|
207
|
+
return product._status === 'published' && hasStripeProduct(product);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Check if product has prices
|
|
211
|
+
*/
|
|
212
|
+
export function hasProductPrices(product) {
|
|
213
|
+
return !!product.priceJSON && product.priceJSON !== null;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Check if product has images
|
|
217
|
+
*/
|
|
218
|
+
export function hasProductImages(product) {
|
|
219
|
+
// No dedicated images field on the local schema yet.
|
|
220
|
+
// Guard checks stripeProductID as prerequisite for potential Stripe-hosted images.
|
|
221
|
+
if (!hasStripeProduct(product))
|
|
222
|
+
return false;
|
|
223
|
+
// Images field not yet in schema; will be checked when added
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
// =============================================================================
|
|
227
|
+
// Product Utilities
|
|
228
|
+
// =============================================================================
|
|
229
|
+
/**
|
|
230
|
+
* Get available prices for a product
|
|
231
|
+
*/
|
|
232
|
+
export function getAvailablePrices(product) {
|
|
233
|
+
if (!hasProductPrices(product))
|
|
234
|
+
return [];
|
|
235
|
+
return product.priceJSON.data.filter((price) => price.active !== false);
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Get price count for product
|
|
239
|
+
*/
|
|
240
|
+
export function getPriceCount(product) {
|
|
241
|
+
return getAvailablePrices(product).length;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Get price range for product (lowest to highest)
|
|
245
|
+
*/
|
|
246
|
+
export function getPriceRange(product) {
|
|
247
|
+
const prices = getAvailablePrices(product);
|
|
248
|
+
if (prices.length === 0)
|
|
249
|
+
return null;
|
|
250
|
+
const amounts = prices
|
|
251
|
+
.map((p) => p.unit_amount)
|
|
252
|
+
.filter((amount) => amount !== null && amount !== undefined);
|
|
253
|
+
if (amounts.length === 0)
|
|
254
|
+
return null;
|
|
255
|
+
return {
|
|
256
|
+
min: Math.min(...amounts),
|
|
257
|
+
max: Math.max(...amounts),
|
|
258
|
+
currency: prices[0]?.currency || null,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Get default price ID for product
|
|
263
|
+
*/
|
|
264
|
+
export function getDefaultPriceId(product) {
|
|
265
|
+
const prices = getAvailablePrices(product);
|
|
266
|
+
return prices.length > 0 && prices[0] ? prices[0].id : null;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Format price range for display
|
|
270
|
+
*/
|
|
271
|
+
export function formatPriceRange(product) {
|
|
272
|
+
const range = getPriceRange(product);
|
|
273
|
+
if (!range?.currency)
|
|
274
|
+
return null;
|
|
275
|
+
const formatter = new Intl.NumberFormat('en-US', {
|
|
276
|
+
style: 'currency',
|
|
277
|
+
currency: range.currency.toUpperCase(),
|
|
278
|
+
});
|
|
279
|
+
const minAmount = range.min ?? 0;
|
|
280
|
+
const maxAmount = range.max ?? 0;
|
|
281
|
+
if (minAmount === maxAmount) {
|
|
282
|
+
return formatter.format(minAmount / 100);
|
|
283
|
+
}
|
|
284
|
+
return `${formatter.format(minAmount / 100)} - ${formatter.format(maxAmount / 100)}`;
|
|
285
|
+
}
|
|
286
|
+
// =============================================================================
|
|
287
|
+
// Contracts
|
|
288
|
+
// =============================================================================
|
|
289
|
+
export const ProductContract = createContract({
|
|
290
|
+
name: 'Product',
|
|
291
|
+
version: '1',
|
|
292
|
+
schema: ProductSchema,
|
|
293
|
+
description: 'Stripe-backed product entity with content management',
|
|
294
|
+
});
|
|
295
|
+
export const CreateProductContract = createContract({
|
|
296
|
+
name: 'CreateProduct',
|
|
297
|
+
version: '1',
|
|
298
|
+
schema: CreateProductInputSchema,
|
|
299
|
+
description: 'Input contract for creating a new product',
|
|
300
|
+
});
|
|
301
|
+
export const UpdateProductContract = createContract({
|
|
302
|
+
name: 'UpdateProduct',
|
|
303
|
+
version: '1',
|
|
304
|
+
schema: UpdateProductInputSchema,
|
|
305
|
+
description: 'Input contract for updating an existing product',
|
|
306
|
+
});
|
|
307
|
+
//# sourceMappingURL=product.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product.js","sourceRoot":"","sources":["../../src/entities/product.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Entity Contract
|
|
3
|
+
*
|
|
4
|
+
* Manages authentication session lifecycle with security-critical validation.
|
|
5
|
+
* Sessions can be persistent (7 days) or regular (1 day) with automatic expiration.
|
|
6
|
+
*
|
|
7
|
+
* Business Rules:
|
|
8
|
+
* - Persistent sessions last 7 days
|
|
9
|
+
* - Regular sessions last 1 day
|
|
10
|
+
* - Sessions expire based on expiresAt timestamp
|
|
11
|
+
* - Last activity tracked on each request
|
|
12
|
+
* - Token hash stored (never plain token)
|
|
13
|
+
* - Cascading deletion when user is deleted
|
|
14
|
+
*/
|
|
15
|
+
import { z } from 'zod/v4';
|
|
16
|
+
export declare const SESSION_SCHEMA_VERSION = 1;
|
|
17
|
+
export declare const SESSION_DURATION: {
|
|
18
|
+
readonly REGULAR: number;
|
|
19
|
+
readonly PERSISTENT: number;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Session object schema
|
|
23
|
+
*/
|
|
24
|
+
export declare const SessionObjectSchema: z.ZodObject<{
|
|
25
|
+
id: z.ZodString;
|
|
26
|
+
schemaVersion: z.ZodDefault<z.ZodString>;
|
|
27
|
+
userId: z.ZodString;
|
|
28
|
+
tokenHash: z.ZodString;
|
|
29
|
+
expiresAt: z.ZodDate;
|
|
30
|
+
userAgent: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
31
|
+
ipAddress: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
32
|
+
persistent: z.ZodDefault<z.ZodNullable<z.ZodBoolean>>;
|
|
33
|
+
lastActivityAt: z.ZodDate;
|
|
34
|
+
createdAt: z.ZodDate;
|
|
35
|
+
}, z.core.$strip>;
|
|
36
|
+
/**
|
|
37
|
+
* Session schema with validation rules
|
|
38
|
+
*/
|
|
39
|
+
export declare const SessionBaseSchema: z.ZodObject<{
|
|
40
|
+
id: z.ZodString;
|
|
41
|
+
schemaVersion: z.ZodDefault<z.ZodString>;
|
|
42
|
+
userId: z.ZodString;
|
|
43
|
+
tokenHash: z.ZodString;
|
|
44
|
+
expiresAt: z.ZodDate;
|
|
45
|
+
userAgent: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
46
|
+
ipAddress: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
47
|
+
persistent: z.ZodDefault<z.ZodNullable<z.ZodBoolean>>;
|
|
48
|
+
lastActivityAt: z.ZodDate;
|
|
49
|
+
createdAt: z.ZodDate;
|
|
50
|
+
}, z.core.$strip>;
|
|
51
|
+
export declare const SessionSchema: z.ZodObject<{
|
|
52
|
+
id: z.ZodString;
|
|
53
|
+
schemaVersion: z.ZodDefault<z.ZodString>;
|
|
54
|
+
userId: z.ZodString;
|
|
55
|
+
tokenHash: z.ZodString;
|
|
56
|
+
expiresAt: z.ZodDate;
|
|
57
|
+
userAgent: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
58
|
+
ipAddress: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
59
|
+
persistent: z.ZodDefault<z.ZodNullable<z.ZodBoolean>>;
|
|
60
|
+
lastActivityAt: z.ZodDate;
|
|
61
|
+
createdAt: z.ZodDate;
|
|
62
|
+
}, z.core.$strip>;
|
|
63
|
+
/**
|
|
64
|
+
* Schema for creating new sessions
|
|
65
|
+
*/
|
|
66
|
+
export declare const SessionInsertSchema: z.ZodObject<{
|
|
67
|
+
userId: z.ZodString;
|
|
68
|
+
expiresAt: z.ZodDate;
|
|
69
|
+
schemaVersion: z.ZodDefault<z.ZodString>;
|
|
70
|
+
tokenHash: z.ZodString;
|
|
71
|
+
userAgent: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
72
|
+
ipAddress: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
73
|
+
persistent: z.ZodDefault<z.ZodNullable<z.ZodBoolean>>;
|
|
74
|
+
id: z.ZodOptional<z.ZodString>;
|
|
75
|
+
createdAt: z.ZodOptional<z.ZodDate>;
|
|
76
|
+
lastActivityAt: z.ZodOptional<z.ZodDate>;
|
|
77
|
+
}, z.core.$strip>;
|
|
78
|
+
export type Session = z.infer<typeof SessionSchema>;
|
|
79
|
+
export type SessionInsert = z.infer<typeof SessionInsertSchema>;
|
|
80
|
+
/**
|
|
81
|
+
* Check if a session is expired
|
|
82
|
+
*/
|
|
83
|
+
export declare function isSessionExpired(session: Session): boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Check if a session is still valid (not expired)
|
|
86
|
+
*/
|
|
87
|
+
export declare function isSessionValid(session: Session): boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Calculate session duration based on persistent flag
|
|
90
|
+
*/
|
|
91
|
+
export declare function calculateSessionDuration(persistent: boolean): number;
|
|
92
|
+
/**
|
|
93
|
+
* Calculate expiration date for a new session
|
|
94
|
+
*/
|
|
95
|
+
export declare function calculateExpiresAt(persistent: boolean, from?: Date): Date;
|
|
96
|
+
/**
|
|
97
|
+
* Check if session needs activity update (last activity > 5 minutes ago)
|
|
98
|
+
*/
|
|
99
|
+
export declare function needsActivityUpdate(session: Session, thresholdMinutes?: number): boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Get remaining session time in milliseconds
|
|
102
|
+
*/
|
|
103
|
+
export declare function getSessionTimeRemaining(session: Session): number;
|
|
104
|
+
/**
|
|
105
|
+
* Get session age in milliseconds
|
|
106
|
+
*/
|
|
107
|
+
export declare function getSessionAge(session: Session): number;
|
|
108
|
+
/**
|
|
109
|
+
* Check if session is nearing expiration (< 1 hour remaining)
|
|
110
|
+
*/
|
|
111
|
+
export declare function isSessionNearExpiration(session: Session, thresholdMinutes?: number): boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Validate session token hash format
|
|
114
|
+
*/
|
|
115
|
+
export declare function validateTokenHash(tokenHash: string): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Validate IP address format (IPv4 or IPv6)
|
|
118
|
+
*/
|
|
119
|
+
export declare function validateIpAddress(ip: string | null): boolean;
|
|
120
|
+
/**
|
|
121
|
+
* Create session insert data with computed fields
|
|
122
|
+
*/
|
|
123
|
+
export declare function createSessionInsert(userId: string, tokenHash: string, options?: {
|
|
124
|
+
persistent?: boolean;
|
|
125
|
+
userAgent?: string | null;
|
|
126
|
+
ipAddress?: string | null;
|
|
127
|
+
id?: string;
|
|
128
|
+
}): Omit<Session, 'id'> & {
|
|
129
|
+
id?: string;
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Update session activity timestamp
|
|
133
|
+
*/
|
|
134
|
+
export declare function updateSessionActivity(): Partial<Session>;
|
|
135
|
+
/**
|
|
136
|
+
* Session with computed fields for UI display
|
|
137
|
+
*/
|
|
138
|
+
export interface SessionWithComputed extends Session {
|
|
139
|
+
_computed: {
|
|
140
|
+
isExpired: boolean;
|
|
141
|
+
isValid: boolean;
|
|
142
|
+
timeRemaining: number;
|
|
143
|
+
age: number;
|
|
144
|
+
isNearExpiration: boolean;
|
|
145
|
+
needsRefresh: boolean;
|
|
146
|
+
durationMs: number;
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Convert session to format with computed fields
|
|
151
|
+
*/
|
|
152
|
+
export declare function sessionToHuman(session: Session): SessionWithComputed;
|
|
153
|
+
/**
|
|
154
|
+
* Session with metadata for agent/API consumption
|
|
155
|
+
*/
|
|
156
|
+
export interface SessionAgent extends Session {
|
|
157
|
+
metadata: {
|
|
158
|
+
expired: boolean;
|
|
159
|
+
valid: boolean;
|
|
160
|
+
timeRemainingMs: number;
|
|
161
|
+
ageMs: number;
|
|
162
|
+
nearExpiration: boolean;
|
|
163
|
+
type: 'persistent' | 'regular';
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Convert session to agent-compatible format
|
|
168
|
+
*/
|
|
169
|
+
export declare function sessionToAgent(session: Session): SessionAgent;
|
|
170
|
+
/**
|
|
171
|
+
* Zod schema for session with computed fields
|
|
172
|
+
*/
|
|
173
|
+
export declare const SessionWithComputedSchema: z.ZodIntersection<z.ZodObject<{
|
|
174
|
+
id: z.ZodString;
|
|
175
|
+
schemaVersion: z.ZodDefault<z.ZodString>;
|
|
176
|
+
userId: z.ZodString;
|
|
177
|
+
tokenHash: z.ZodString;
|
|
178
|
+
expiresAt: z.ZodDate;
|
|
179
|
+
userAgent: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
180
|
+
ipAddress: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
181
|
+
persistent: z.ZodDefault<z.ZodNullable<z.ZodBoolean>>;
|
|
182
|
+
lastActivityAt: z.ZodDate;
|
|
183
|
+
createdAt: z.ZodDate;
|
|
184
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
185
|
+
_computed: z.ZodObject<{
|
|
186
|
+
isExpired: z.ZodBoolean;
|
|
187
|
+
isValid: z.ZodBoolean;
|
|
188
|
+
timeRemaining: z.ZodNumber;
|
|
189
|
+
age: z.ZodNumber;
|
|
190
|
+
isNearExpiration: z.ZodBoolean;
|
|
191
|
+
needsRefresh: z.ZodBoolean;
|
|
192
|
+
durationMs: z.ZodNumber;
|
|
193
|
+
}, z.core.$strip>;
|
|
194
|
+
}, z.core.$strip>>;
|
|
195
|
+
/**
|
|
196
|
+
* Zod schema for session with agent metadata
|
|
197
|
+
*/
|
|
198
|
+
export declare const SessionAgentSchema: z.ZodIntersection<z.ZodObject<{
|
|
199
|
+
id: z.ZodString;
|
|
200
|
+
schemaVersion: z.ZodDefault<z.ZodString>;
|
|
201
|
+
userId: z.ZodString;
|
|
202
|
+
tokenHash: z.ZodString;
|
|
203
|
+
expiresAt: z.ZodDate;
|
|
204
|
+
userAgent: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
205
|
+
ipAddress: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
206
|
+
persistent: z.ZodDefault<z.ZodNullable<z.ZodBoolean>>;
|
|
207
|
+
lastActivityAt: z.ZodDate;
|
|
208
|
+
createdAt: z.ZodDate;
|
|
209
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
210
|
+
metadata: z.ZodObject<{
|
|
211
|
+
expired: z.ZodBoolean;
|
|
212
|
+
valid: z.ZodBoolean;
|
|
213
|
+
timeRemainingMs: z.ZodNumber;
|
|
214
|
+
ageMs: z.ZodNumber;
|
|
215
|
+
nearExpiration: z.ZodBoolean;
|
|
216
|
+
type: z.ZodEnum<{
|
|
217
|
+
persistent: "persistent";
|
|
218
|
+
regular: "regular";
|
|
219
|
+
}>;
|
|
220
|
+
}, z.core.$strip>;
|
|
221
|
+
}, z.core.$strip>>;
|
|
222
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/entities/session.ts"],"names":[],"mappings":"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"}
|