@happyvertical/smrt-products 0.37.10 → 0.38.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.
Files changed (29) hide show
  1. package/AGENTS.md +8 -0
  2. package/dist/lib/chunks/__smrt-register__-TadwWhw0.js +6 -0
  3. package/dist/lib/chunks/{__smrt-register__-6LdK7jmu.js.map → __smrt-register__-TadwWhw0.js.map} +1 -1
  4. package/dist/lib/chunks/{collections-CrGxcTBr.js → collections-BGe17mnv.js} +2 -2
  5. package/dist/lib/chunks/{collections-CrGxcTBr.js.map → collections-BGe17mnv.js.map} +1 -1
  6. package/dist/lib/chunks/{generated-DNuvx5h-.js → generated-BvhTCo8i.js} +2 -2
  7. package/dist/lib/chunks/{generated-DNuvx5h-.js.map → generated-BvhTCo8i.js.map} +1 -1
  8. package/dist/lib/chunks/models-DIAe1TCG.js +2 -0
  9. package/dist/lib/collections.js +1 -1
  10. package/dist/lib/generated.js +1 -1
  11. package/dist/lib/index.js +4 -4
  12. package/dist/lib/lib/components/LiveProductList.svelte +219 -0
  13. package/dist/lib/lib/components/LiveProductList.svelte.d.ts +16 -0
  14. package/dist/lib/lib/components/LiveProductList.svelte.d.ts.map +1 -0
  15. package/dist/lib/lib/i18n.d.ts +13 -0
  16. package/dist/lib/lib/i18n.d.ts.map +1 -1
  17. package/dist/lib/lib/i18n.js +13 -0
  18. package/dist/lib/lib/i18n.js.map +1 -1
  19. package/dist/lib/lib/stores/product-collection.d.ts +86 -0
  20. package/dist/lib/lib/stores/product-collection.d.ts.map +1 -0
  21. package/dist/lib/lib/stores/product-collection.js +80 -0
  22. package/dist/lib/manifest.json +2 -2
  23. package/dist/lib/models.js +1 -1
  24. package/dist/lib/smrt-knowledge.json +12 -7
  25. package/dist/lib/stores/product-collection.js +85 -0
  26. package/dist/lib/stores/product-collection.js.map +1 -0
  27. package/package.json +15 -7
  28. package/dist/lib/chunks/__smrt-register__-6LdK7jmu.js +0 -6
  29. package/dist/lib/chunks/models-D-yBusXS.js +0 -2
@@ -0,0 +1,16 @@
1
+ import { type ProductCollectionDefinition } from '../stores/product-collection';
2
+ interface Props {
3
+ /**
4
+ * The `products` collection definition, resolved by the caller (the hosting
5
+ * page resolves it from the SMRT Vite plugin via `productsCollectionDefinition()`
6
+ * and passes it here). Threading it in as a prop keeps this component — and the
7
+ * store it uses — free of a top-level `@happyvertical/smrt-virt-web` import.
8
+ */
9
+ definition: ProductCollectionDefinition;
10
+ /** API base path for the generated REST surface (default `/api/v1`). */
11
+ basePath?: string;
12
+ }
13
+ declare const LiveProductList: import("svelte").Component<Props, {}, "">;
14
+ type LiveProductList = ReturnType<typeof LiveProductList>;
15
+ export default LiveProductList;
16
+ //# sourceMappingURL=LiveProductList.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LiveProductList.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/LiveProductList.svelte"],"names":[],"mappings":"AAyBA,OAAO,EAEL,KAAK,2BAA2B,EACjC,MAAM,8BAA8B,CAAC;AAItC,UAAU,KAAK;IACb;;;;;OAKG;IACH,UAAU,EAAE,2BAA2B,CAAC;IACxC,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAuGD,QAAA,MAAM,eAAe,2CAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
@@ -65,6 +65,19 @@ export declare const M: {
65
65
  readonly 'products.category_manager.organize_hierarchy': "products.category_manager.organize_hierarchy";
66
66
  readonly 'products.category_manager.manage_permissions': "products.category_manager.manage_permissions";
67
67
  readonly 'products.category_manager.analytics': "products.category_manager.analytics";
68
+ readonly 'products.live_page.title': "products.live_page.title";
69
+ readonly 'products.live_page.description': "products.live_page.description";
70
+ readonly 'products.live_page.load_failed': "products.live_page.load_failed";
71
+ readonly 'products.live_page.loading_runtime': "products.live_page.loading_runtime";
72
+ readonly 'products.live_list.title': "products.live_list.title";
73
+ readonly 'products.live_list.hint': "products.live_list.hint";
74
+ readonly 'products.live_list.name_placeholder': "products.live_list.name_placeholder";
75
+ readonly 'products.live_list.add': "products.live_list.add";
76
+ readonly 'products.live_list.adding': "products.live_list.adding";
77
+ readonly 'products.live_list.insert_failed': "products.live_list.insert_failed";
78
+ readonly 'products.live_list.load_failed': "products.live_list.load_failed";
79
+ readonly 'products.live_list.empty': "products.live_list.empty";
80
+ readonly 'products.live_list.loading': "products.live_list.loading";
68
81
  readonly 'products.product_catalog.title': "products.product_catalog.title";
69
82
  readonly 'products.product_catalog.in_stock': "products.product_catalog.in_stock";
70
83
  readonly 'products.product_catalog.total_value': "products.product_catalog.total_value";
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../src/lib/i18n.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwHZ,CAAC"}
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../src/lib/i18n.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2IZ,CAAC"}
@@ -67,6 +67,19 @@ var M = defineMessages({
67
67
  "products.category_manager.organize_hierarchy": "Organize category hierarchy",
68
68
  "products.category_manager.manage_permissions": "Manage category permissions",
69
69
  "products.category_manager.analytics": "Category analytics",
70
+ "products.live_page.title": "Live products",
71
+ "products.live_page.description": "The @happyvertical/smrt-web browser runtime as the reference store — live rows plus optimistic insert, loaded in a code-split chunk so public pages never pay for the engine.",
72
+ "products.live_page.load_failed": "Failed to load runtime:",
73
+ "products.live_page.loading_runtime": "Loading live runtime…",
74
+ "products.live_list.title": "Live products",
75
+ "products.live_list.hint": "Reactive rows from the @happyvertical/smrt-web runtime. Adding a product is optimistic.",
76
+ "products.live_list.name_placeholder": "New product name",
77
+ "products.live_list.add": "Add product",
78
+ "products.live_list.adding": "Adding…",
79
+ "products.live_list.insert_failed": "Insert failed:",
80
+ "products.live_list.load_failed": "Failed to load:",
81
+ "products.live_list.empty": "No products yet.",
82
+ "products.live_list.loading": "Loading…",
70
83
  "products.product_catalog.title": "Product Catalog",
71
84
  "products.product_catalog.in_stock": "in stock",
72
85
  "products.product_catalog.total_value": "Total value:",
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.js","names":[],"sources":["../../../src/lib/i18n.ts"],"sourcesContent":["import { defineMessages } from '@happyvertical/smrt-ui/i18n';\n\nexport const M = defineMessages({\n // App\n 'products.app.categories_coming_soon': 'Category management coming soon...',\n 'products.app.analytics_coming_soon': 'Analytics dashboard coming soon...',\n\n // AppLayout\n 'products.app_layout.service_title': 'Product Service',\n 'products.app_layout.footer_copyright':\n '2024 SMRT Product Service - Auto-generated with ❤️',\n 'products.app_layout.api_docs': 'API Docs',\n 'products.app_layout.mcp_tools': 'MCP Tools',\n\n // DemoPage\n 'products.demo_page.title': 'SMRT Framework Demo',\n 'products.demo_page.subtitle':\n 'Define Once, Consume Everywhere - Progressive Customization',\n 'products.demo_page.custom_components_tab': 'Custom Components',\n 'products.demo_page.auto_generated_heading':\n 'Auto-Generated UI from SMRT Object',\n 'products.demo_page.auto_generated_description':\n 'This form is automatically generated from the Product class definition.\\n The field types, labels, and validation rules are inferred from the TypeScript schema.',\n 'products.demo_page.generated_form_heading': 'Generated Form',\n 'products.demo_page.auto_form_title': 'Auto-Generated Product Form',\n 'products.demo_page.generated_display_heading': 'Generated Display',\n 'products.demo_page.custom_components_heading':\n 'Custom Components with SMRT Integration',\n 'products.demo_page.custom_components_description':\n 'These are hand-crafted components that still leverage the SMRT data structure\\n but provide custom UI/UX for specific business requirements.',\n 'products.demo_page.custom_form_heading': 'Custom Form',\n 'products.demo_page.custom_display_heading': 'Custom Display',\n 'products.demo_page.progressive_heading': 'Progressive Customization',\n 'products.demo_page.progressive_description':\n 'Start with auto-generated components, then progressively customize as needed.\\n Both approaches use the same underlying SMRT Product model.',\n 'products.demo_page.feature_zero_config': '✅ Zero configuration',\n 'products.demo_page.feature_instant_ui': '✅ Instant UI from schema',\n 'products.demo_page.feature_type_safe': '✅ Type-safe by default',\n 'products.demo_page.feature_prototyping': '⚡ Perfect for prototyping',\n 'products.demo_page.custom_components_label': '🎨 Custom Components',\n 'products.demo_page.feature_tailored_ux': '✅ Tailored UX',\n 'products.demo_page.feature_business_workflows':\n '✅ Business-specific workflows',\n 'products.demo_page.feature_advanced_interactions':\n '✅ Advanced interactions',\n 'products.demo_page.simple_auto_form_title': 'Auto Form',\n 'products.demo_page.benefits_heading': 'SMRT Framework Benefits',\n 'products.demo_page.benefit_define_once_label': 'Define Once:',\n 'products.demo_page.benefit_define_once_text':\n 'Product class with @smrt decorator',\n 'products.demo_page.benefit_auto_generate_label': 'Auto-Generate:',\n 'products.demo_page.benefit_auto_generate_text':\n 'REST APIs, MCP tools, TypeScript clients, default UI',\n 'products.demo_page.benefit_progressive_label': 'Progressive Enhancement:',\n 'products.demo_page.benefit_progressive_text':\n 'Start with defaults, customize as needed',\n 'products.demo_page.benefit_type_safety_label': 'Type Safety:',\n 'products.demo_page.benefit_type_safety_text':\n 'End-to-end TypeScript integration',\n 'products.demo_page.benefit_multiple_consumption_label':\n 'Multiple Consumption:',\n 'products.demo_page.benefit_multiple_consumption_text':\n 'Library, federation, standalone',\n\n // ProductsPage\n 'products.products_page.description':\n 'Manage your product catalog with auto-generated CRUD operations, \\n real-time updates, and AI-powered tools via MCP.',\n 'products.products_page.auto_generated_text':\n 'REST API endpoints automatically created from @smrt() decorated Product class',\n 'products.products_page.ai_ready_heading': '🤖 AI Ready',\n 'products.products_page.ai_ready_text':\n 'MCP tools available for Claude and other AI models to interact with products',\n 'products.products_page.federatable_text':\n 'Components can be consumed by other applications via module federation',\n 'products.products_page.library_text':\n 'Install as NPM package: npm install @have/smrt-template',\n\n // ProductForm\n 'products.product_form.name_label': 'Product Name *',\n 'products.product_form.name_placeholder': 'Enter product name',\n 'products.product_form.description_placeholder':\n 'Product description (optional)',\n 'products.product_form.category_placeholder': 'Product category',\n 'products.product_form.tags_placeholder': 'tag1, tag2, tag3',\n 'products.product_form.tags_hint': 'Separate tags with commas',\n 'products.product_form.in_stock_label': 'In Stock',\n\n // TestComponent\n 'products.test_component.title': 'Test Component',\n\n // AutoForm\n 'products.auto_form.subtitle': 'Auto-generated from SMRT Product model',\n 'products.auto_form.debug_summary': 'Form Data (Debug)',\n\n // FieldRenderer\n 'products.field_renderer.array_hint': 'Enter values separated by commas',\n 'products.field_renderer.object_hint': 'Enter valid JSON',\n\n // CategoryManager\n 'products.category_manager.title': 'Category Manager',\n 'products.category_manager.subtitle': 'Manage product categories',\n 'products.category_manager.coming_soon':\n 'Category management feature coming soon...',\n 'products.category_manager.will_include': 'This will include:',\n 'products.category_manager.create_edit': 'Create and edit categories',\n 'products.category_manager.organize_hierarchy': 'Organize category hierarchy',\n 'products.category_manager.manage_permissions': 'Manage category permissions',\n 'products.category_manager.analytics': 'Category analytics',\n\n // ProductCatalog\n 'products.product_catalog.title': 'Product Catalog',\n 'products.product_catalog.in_stock': 'in stock',\n 'products.product_catalog.total_value': 'Total value:',\n 'products.product_catalog.search_placeholder': 'Search products...',\n 'products.product_catalog.all_categories': 'All Categories',\n 'products.product_catalog.add_product': 'Add Product',\n 'products.product_catalog.loading': 'Loading products...',\n 'products.product_catalog.empty':\n 'No products yet. Create your first product to get started!',\n 'products.product_catalog.create_first': 'Create First Product',\n 'products.product_catalog.no_match':\n 'No products match your search criteria.',\n});\n"],"mappings":";;AAEA,IAAa,IAAI,eAAe;CAE9B,uCAAuC;CACvC,sCAAsC;CAGtC,qCAAqC;CACrC,wCACE;CACF,gCAAgC;CAChC,iCAAiC;CAGjC,4BAA4B;CAC5B,+BACE;CACF,4CAA4C;CAC5C,6CACE;CACF,iDACE;CACF,6CAA6C;CAC7C,sCAAsC;CACtC,gDAAgD;CAChD,gDACE;CACF,oDACE;CACF,0CAA0C;CAC1C,6CAA6C;CAC7C,0CAA0C;CAC1C,8CACE;CACF,0CAA0C;CAC1C,yCAAyC;CACzC,wCAAwC;CACxC,0CAA0C;CAC1C,8CAA8C;CAC9C,0CAA0C;CAC1C,iDACE;CACF,oDACE;CACF,6CAA6C;CAC7C,uCAAuC;CACvC,gDAAgD;CAChD,+CACE;CACF,kDAAkD;CAClD,iDACE;CACF,gDAAgD;CAChD,+CACE;CACF,gDAAgD;CAChD,+CACE;CACF,yDACE;CACF,wDACE;CAGF,sCACE;CACF,8CACE;CACF,2CAA2C;CAC3C,wCACE;CACF,2CACE;CACF,uCACE;CAGF,oCAAoC;CACpC,0CAA0C;CAC1C,iDACE;CACF,8CAA8C;CAC9C,0CAA0C;CAC1C,mCAAmC;CACnC,wCAAwC;CAGxC,iCAAiC;CAGjC,+BAA+B;CAC/B,oCAAoC;CAGpC,sCAAsC;CACtC,uCAAuC;CAGvC,mCAAmC;CACnC,sCAAsC;CACtC,yCACE;CACF,0CAA0C;CAC1C,yCAAyC;CACzC,gDAAgD;CAChD,gDAAgD;CAChD,uCAAuC;CAGvC,kCAAkC;CAClC,qCAAqC;CACrC,wCAAwC;CACxC,+CAA+C;CAC/C,2CAA2C;CAC3C,wCAAwC;CACxC,oCAAoC;CACpC,kCACE;CACF,yCAAyC;CACzC,qCACE;AACJ,CAAC"}
1
+ {"version":3,"file":"i18n.js","names":[],"sources":["../../../src/lib/i18n.ts"],"sourcesContent":["import { defineMessages } from '@happyvertical/smrt-ui/i18n';\n\nexport const M = defineMessages({\n // App\n 'products.app.categories_coming_soon': 'Category management coming soon...',\n 'products.app.analytics_coming_soon': 'Analytics dashboard coming soon...',\n\n // AppLayout\n 'products.app_layout.service_title': 'Product Service',\n 'products.app_layout.footer_copyright':\n '2024 SMRT Product Service - Auto-generated with ❤️',\n 'products.app_layout.api_docs': 'API Docs',\n 'products.app_layout.mcp_tools': 'MCP Tools',\n\n // DemoPage\n 'products.demo_page.title': 'SMRT Framework Demo',\n 'products.demo_page.subtitle':\n 'Define Once, Consume Everywhere - Progressive Customization',\n 'products.demo_page.custom_components_tab': 'Custom Components',\n 'products.demo_page.auto_generated_heading':\n 'Auto-Generated UI from SMRT Object',\n 'products.demo_page.auto_generated_description':\n 'This form is automatically generated from the Product class definition.\\n The field types, labels, and validation rules are inferred from the TypeScript schema.',\n 'products.demo_page.generated_form_heading': 'Generated Form',\n 'products.demo_page.auto_form_title': 'Auto-Generated Product Form',\n 'products.demo_page.generated_display_heading': 'Generated Display',\n 'products.demo_page.custom_components_heading':\n 'Custom Components with SMRT Integration',\n 'products.demo_page.custom_components_description':\n 'These are hand-crafted components that still leverage the SMRT data structure\\n but provide custom UI/UX for specific business requirements.',\n 'products.demo_page.custom_form_heading': 'Custom Form',\n 'products.demo_page.custom_display_heading': 'Custom Display',\n 'products.demo_page.progressive_heading': 'Progressive Customization',\n 'products.demo_page.progressive_description':\n 'Start with auto-generated components, then progressively customize as needed.\\n Both approaches use the same underlying SMRT Product model.',\n 'products.demo_page.feature_zero_config': '✅ Zero configuration',\n 'products.demo_page.feature_instant_ui': '✅ Instant UI from schema',\n 'products.demo_page.feature_type_safe': '✅ Type-safe by default',\n 'products.demo_page.feature_prototyping': '⚡ Perfect for prototyping',\n 'products.demo_page.custom_components_label': '🎨 Custom Components',\n 'products.demo_page.feature_tailored_ux': '✅ Tailored UX',\n 'products.demo_page.feature_business_workflows':\n '✅ Business-specific workflows',\n 'products.demo_page.feature_advanced_interactions':\n '✅ Advanced interactions',\n 'products.demo_page.simple_auto_form_title': 'Auto Form',\n 'products.demo_page.benefits_heading': 'SMRT Framework Benefits',\n 'products.demo_page.benefit_define_once_label': 'Define Once:',\n 'products.demo_page.benefit_define_once_text':\n 'Product class with @smrt decorator',\n 'products.demo_page.benefit_auto_generate_label': 'Auto-Generate:',\n 'products.demo_page.benefit_auto_generate_text':\n 'REST APIs, MCP tools, TypeScript clients, default UI',\n 'products.demo_page.benefit_progressive_label': 'Progressive Enhancement:',\n 'products.demo_page.benefit_progressive_text':\n 'Start with defaults, customize as needed',\n 'products.demo_page.benefit_type_safety_label': 'Type Safety:',\n 'products.demo_page.benefit_type_safety_text':\n 'End-to-end TypeScript integration',\n 'products.demo_page.benefit_multiple_consumption_label':\n 'Multiple Consumption:',\n 'products.demo_page.benefit_multiple_consumption_text':\n 'Library, federation, standalone',\n\n // ProductsPage\n 'products.products_page.description':\n 'Manage your product catalog with auto-generated CRUD operations, \\n real-time updates, and AI-powered tools via MCP.',\n 'products.products_page.auto_generated_text':\n 'REST API endpoints automatically created from @smrt() decorated Product class',\n 'products.products_page.ai_ready_heading': '🤖 AI Ready',\n 'products.products_page.ai_ready_text':\n 'MCP tools available for Claude and other AI models to interact with products',\n 'products.products_page.federatable_text':\n 'Components can be consumed by other applications via module federation',\n 'products.products_page.library_text':\n 'Install as NPM package: npm install @have/smrt-template',\n\n // ProductForm\n 'products.product_form.name_label': 'Product Name *',\n 'products.product_form.name_placeholder': 'Enter product name',\n 'products.product_form.description_placeholder':\n 'Product description (optional)',\n 'products.product_form.category_placeholder': 'Product category',\n 'products.product_form.tags_placeholder': 'tag1, tag2, tag3',\n 'products.product_form.tags_hint': 'Separate tags with commas',\n 'products.product_form.in_stock_label': 'In Stock',\n\n // TestComponent\n 'products.test_component.title': 'Test Component',\n\n // AutoForm\n 'products.auto_form.subtitle': 'Auto-generated from SMRT Product model',\n 'products.auto_form.debug_summary': 'Form Data (Debug)',\n\n // FieldRenderer\n 'products.field_renderer.array_hint': 'Enter values separated by commas',\n 'products.field_renderer.object_hint': 'Enter valid JSON',\n\n // CategoryManager\n 'products.category_manager.title': 'Category Manager',\n 'products.category_manager.subtitle': 'Manage product categories',\n 'products.category_manager.coming_soon':\n 'Category management feature coming soon...',\n 'products.category_manager.will_include': 'This will include:',\n 'products.category_manager.create_edit': 'Create and edit categories',\n 'products.category_manager.organize_hierarchy': 'Organize category hierarchy',\n 'products.category_manager.manage_permissions': 'Manage category permissions',\n 'products.category_manager.analytics': 'Category analytics',\n\n // LiveProductsPage (smrt-web reference surface)\n 'products.live_page.title': 'Live products',\n 'products.live_page.description':\n 'The @happyvertical/smrt-web browser runtime as the reference store — live rows plus optimistic insert, loaded in a code-split chunk so public pages never pay for the engine.',\n 'products.live_page.load_failed': 'Failed to load runtime:',\n 'products.live_page.loading_runtime': 'Loading live runtime…',\n\n // LiveProductList (smrt-web reference surface)\n 'products.live_list.title': 'Live products',\n 'products.live_list.hint':\n 'Reactive rows from the @happyvertical/smrt-web runtime. Adding a product is optimistic.',\n 'products.live_list.name_placeholder': 'New product name',\n 'products.live_list.add': 'Add product',\n 'products.live_list.adding': 'Adding…',\n 'products.live_list.insert_failed': 'Insert failed:',\n 'products.live_list.load_failed': 'Failed to load:',\n 'products.live_list.empty': 'No products yet.',\n 'products.live_list.loading': 'Loading…',\n\n // ProductCatalog\n 'products.product_catalog.title': 'Product Catalog',\n 'products.product_catalog.in_stock': 'in stock',\n 'products.product_catalog.total_value': 'Total value:',\n 'products.product_catalog.search_placeholder': 'Search products...',\n 'products.product_catalog.all_categories': 'All Categories',\n 'products.product_catalog.add_product': 'Add Product',\n 'products.product_catalog.loading': 'Loading products...',\n 'products.product_catalog.empty':\n 'No products yet. Create your first product to get started!',\n 'products.product_catalog.create_first': 'Create First Product',\n 'products.product_catalog.no_match':\n 'No products match your search criteria.',\n});\n"],"mappings":";;AAEA,IAAa,IAAI,eAAe;CAE9B,uCAAuC;CACvC,sCAAsC;CAGtC,qCAAqC;CACrC,wCACE;CACF,gCAAgC;CAChC,iCAAiC;CAGjC,4BAA4B;CAC5B,+BACE;CACF,4CAA4C;CAC5C,6CACE;CACF,iDACE;CACF,6CAA6C;CAC7C,sCAAsC;CACtC,gDAAgD;CAChD,gDACE;CACF,oDACE;CACF,0CAA0C;CAC1C,6CAA6C;CAC7C,0CAA0C;CAC1C,8CACE;CACF,0CAA0C;CAC1C,yCAAyC;CACzC,wCAAwC;CACxC,0CAA0C;CAC1C,8CAA8C;CAC9C,0CAA0C;CAC1C,iDACE;CACF,oDACE;CACF,6CAA6C;CAC7C,uCAAuC;CACvC,gDAAgD;CAChD,+CACE;CACF,kDAAkD;CAClD,iDACE;CACF,gDAAgD;CAChD,+CACE;CACF,gDAAgD;CAChD,+CACE;CACF,yDACE;CACF,wDACE;CAGF,sCACE;CACF,8CACE;CACF,2CAA2C;CAC3C,wCACE;CACF,2CACE;CACF,uCACE;CAGF,oCAAoC;CACpC,0CAA0C;CAC1C,iDACE;CACF,8CAA8C;CAC9C,0CAA0C;CAC1C,mCAAmC;CACnC,wCAAwC;CAGxC,iCAAiC;CAGjC,+BAA+B;CAC/B,oCAAoC;CAGpC,sCAAsC;CACtC,uCAAuC;CAGvC,mCAAmC;CACnC,sCAAsC;CACtC,yCACE;CACF,0CAA0C;CAC1C,yCAAyC;CACzC,gDAAgD;CAChD,gDAAgD;CAChD,uCAAuC;CAGvC,4BAA4B;CAC5B,kCACE;CACF,kCAAkC;CAClC,sCAAsC;CAGtC,4BAA4B;CAC5B,2BACE;CACF,uCAAuC;CACvC,0BAA0B;CAC1B,6BAA6B;CAC7B,oCAAoC;CACpC,kCAAkC;CAClC,4BAA4B;CAC5B,8BAA8B;CAG9B,kCAAkC;CAClC,qCAAqC;CACrC,wCAAwC;CACxC,+CAA+C;CAC/C,2CAA2C;CAC3C,wCAAwC;CACxC,oCAAoC;CACpC,kCACE;CACF,yCAAyC;CACzC,qCACE;AACJ,CAAC"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Reference `@happyvertical/smrt-web` store for the products package (#1761,
3
+ * slice D).
4
+ *
5
+ * Products is the reference consumer of the browser client-data runtime. This
6
+ * module materializes a manifest-generated `products` web collection definition
7
+ * into a cached, reactive {@link SmrtWebCollection} over the generated
8
+ * `/api/v1/products` REST surface via {@link createSmrtCollection}. The Svelte
9
+ * live-query binding + optimistic insert live in
10
+ * `../components/LiveProductList.svelte`.
11
+ *
12
+ * ── Plugin-agnostic on purpose ──────────────────────────────────────────────
13
+ * The `products` definition comes from the `@happyvertical/smrt-virt-web`
14
+ * virtual module, which exists ONLY under a SMRT Vite-plugin build. To keep
15
+ * this module importable everywhere (unit tests, plain `tsc`, an npm consumer
16
+ * wiring its own definition), it does NOT import that virtual module at the top
17
+ * level. Instead the definition is supplied by the caller:
18
+ * - the live component resolves it from the plugin (see LiveProductList),
19
+ * - {@link productsCollectionDefinition} lazily resolves it on demand.
20
+ * A caller passing an explicit `definition` never touches the virtual module.
21
+ *
22
+ * ── Engine-absorption boundary ──────────────────────────────────────────────
23
+ * `createSmrtCollection` pulls the client-data engine (currently the ~76 kB
24
+ * TanStack DB/Query layer). This module is therefore engine-bearing. It is
25
+ * imported ONLY through a dynamic `import()` (see
26
+ * `../components/LiveProductList.svelte`, reached from
27
+ * `src/app/pages/LiveProductsPage.svelte` via `import()`), so the bundler lands
28
+ * the engine in a lazily-loaded chunk that public / smrt-sites pages never
29
+ * fetch (ratified condition ① of #1761). NEVER import this module (or the live
30
+ * component) statically from an app-root / public entry — doing so pulls the
31
+ * engine into the entry bundle and defeats the split. The
32
+ * `scripts/check-web-engine-code-split.mjs` assertion guards this.
33
+ */
34
+ import { type CreateSmrtCollectionOptions, type SmrtWebClient, type SmrtWebCollection, type SmrtWebCollectionDefinition } from '@happyvertical/smrt-web';
35
+ import type { ProductData } from '../types';
36
+ /**
37
+ * The public DTO carried by the products collection: the persisted product
38
+ * columns plus the required `id` key the client collection stores rows under.
39
+ */
40
+ export type ProductRow = ProductData & {
41
+ id: string;
42
+ };
43
+ /** The `products` collection definition, typed to this package's row shape. */
44
+ export type ProductCollectionDefinition = SmrtWebCollectionDefinition<ProductData>;
45
+ /** Options for {@link createProductCollection}. */
46
+ export type CreateProductCollectionOptions = Pick<CreateSmrtCollectionOptions, 'basePath' | 'fetchFn' | 'client' | 'scope' | 'staleTimeMs' | 'retry'>;
47
+ /**
48
+ * Lazily resolve the manifest-generated `products` definition from the
49
+ * `@happyvertical/smrt-virt-web` virtual module.
50
+ *
51
+ * Kept out of module top-level so importing this store never eagerly resolves a
52
+ * module that exists only under a SMRT Vite-plugin build — a unit test or npm
53
+ * consumer that supplies its own definition must never trigger it. The dynamic
54
+ * `import()` also keeps the virtual specifier out of every static import graph.
55
+ * Resolved for `tsc` via the ambient `@happyvertical/smrt-virt-web` → `@smrt/web`
56
+ * alias in `ambient.d.ts`.
57
+ */
58
+ export declare function productsCollectionDefinition(): Promise<ProductCollectionDefinition>;
59
+ /**
60
+ * Build the reference products collection over the generated REST surface from
61
+ * a `products` collection definition.
62
+ *
63
+ * The definition is a parameter (not resolved here) so this factory is
64
+ * synchronous and plugin-agnostic: the live component passes the
65
+ * plugin-provided definition (via {@link productsCollectionDefinition}); a unit
66
+ * test or npm consumer passes its own. Neither path imports the virtual module
67
+ * unless it explicitly calls {@link productsCollectionDefinition}.
68
+ *
69
+ * Reads are stale-while-revalidate; `insert({ ...data, id })` is optimistic and
70
+ * rolls back automatically if the server rejects the create. Pass a shared
71
+ * {@link SmrtWebClient} (from `createSmrtWebClient()`) as `client` so this
72
+ * collection shares a cache and deduplicates requests with the rest of the app;
73
+ * omit it for an isolated cache.
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * const definition = await productsCollectionDefinition();
78
+ * const products = createProductCollection(definition, { basePath: '/api/v1' });
79
+ * await products.preload();
80
+ * const tx = products.insert({ id: crypto.randomUUID(), name: 'New' });
81
+ * await tx.isPersisted.promise;
82
+ * ```
83
+ */
84
+ export declare function createProductCollection(definition: ProductCollectionDefinition, options?: CreateProductCollectionOptions): SmrtWebCollection<ProductData>;
85
+ export type { SmrtWebClient, SmrtWebCollection, SmrtWebCollectionDefinition };
86
+ //# sourceMappingURL=product-collection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product-collection.d.ts","sourceRoot":"","sources":["../../../../src/lib/stores/product-collection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EACL,KAAK,2BAA2B,EAEhC,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,2BAA2B,EACjC,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtD,+EAA+E;AAC/E,MAAM,MAAM,2BAA2B,GACrC,2BAA2B,CAAC,WAAW,CAAC,CAAC;AAE3C,mDAAmD;AACnD,MAAM,MAAM,8BAA8B,GAAG,IAAI,CAC/C,2BAA2B,EAC3B,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,aAAa,GAAG,OAAO,CACtE,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,2BAA2B,CAAC,CAOzF;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,2BAA2B,EACvC,OAAO,GAAE,8BAAmC,GAC3C,iBAAiB,CAAC,WAAW,CAAC,CAKhC;AAED,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,CAAC"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Reference `@happyvertical/smrt-web` store for the products package (#1761,
3
+ * slice D).
4
+ *
5
+ * Products is the reference consumer of the browser client-data runtime. This
6
+ * module materializes a manifest-generated `products` web collection definition
7
+ * into a cached, reactive {@link SmrtWebCollection} over the generated
8
+ * `/api/v1/products` REST surface via {@link createSmrtCollection}. The Svelte
9
+ * live-query binding + optimistic insert live in
10
+ * `../components/LiveProductList.svelte`.
11
+ *
12
+ * ── Plugin-agnostic on purpose ──────────────────────────────────────────────
13
+ * The `products` definition comes from the `@happyvertical/smrt-virt-web`
14
+ * virtual module, which exists ONLY under a SMRT Vite-plugin build. To keep
15
+ * this module importable everywhere (unit tests, plain `tsc`, an npm consumer
16
+ * wiring its own definition), it does NOT import that virtual module at the top
17
+ * level. Instead the definition is supplied by the caller:
18
+ * - the live component resolves it from the plugin (see LiveProductList),
19
+ * - {@link productsCollectionDefinition} lazily resolves it on demand.
20
+ * A caller passing an explicit `definition` never touches the virtual module.
21
+ *
22
+ * ── Engine-absorption boundary ──────────────────────────────────────────────
23
+ * `createSmrtCollection` pulls the client-data engine (currently the ~76 kB
24
+ * TanStack DB/Query layer). This module is therefore engine-bearing. It is
25
+ * imported ONLY through a dynamic `import()` (see
26
+ * `../components/LiveProductList.svelte`, reached from
27
+ * `src/app/pages/LiveProductsPage.svelte` via `import()`), so the bundler lands
28
+ * the engine in a lazily-loaded chunk that public / smrt-sites pages never
29
+ * fetch (ratified condition ① of #1761). NEVER import this module (or the live
30
+ * component) statically from an app-root / public entry — doing so pulls the
31
+ * engine into the entry bundle and defeats the split. The
32
+ * `scripts/check-web-engine-code-split.mjs` assertion guards this.
33
+ */
34
+ import { createSmrtCollection, } from '@happyvertical/smrt-web';
35
+ /**
36
+ * Lazily resolve the manifest-generated `products` definition from the
37
+ * `@happyvertical/smrt-virt-web` virtual module.
38
+ *
39
+ * Kept out of module top-level so importing this store never eagerly resolves a
40
+ * module that exists only under a SMRT Vite-plugin build — a unit test or npm
41
+ * consumer that supplies its own definition must never trigger it. The dynamic
42
+ * `import()` also keeps the virtual specifier out of every static import graph.
43
+ * Resolved for `tsc` via the ambient `@happyvertical/smrt-virt-web` → `@smrt/web`
44
+ * alias in `ambient.d.ts`.
45
+ */
46
+ export async function productsCollectionDefinition() {
47
+ const { getCollectionDefinition } = await import('@happyvertical/smrt-virt-web');
48
+ return getCollectionDefinition('products');
49
+ }
50
+ /**
51
+ * Build the reference products collection over the generated REST surface from
52
+ * a `products` collection definition.
53
+ *
54
+ * The definition is a parameter (not resolved here) so this factory is
55
+ * synchronous and plugin-agnostic: the live component passes the
56
+ * plugin-provided definition (via {@link productsCollectionDefinition}); a unit
57
+ * test or npm consumer passes its own. Neither path imports the virtual module
58
+ * unless it explicitly calls {@link productsCollectionDefinition}.
59
+ *
60
+ * Reads are stale-while-revalidate; `insert({ ...data, id })` is optimistic and
61
+ * rolls back automatically if the server rejects the create. Pass a shared
62
+ * {@link SmrtWebClient} (from `createSmrtWebClient()`) as `client` so this
63
+ * collection shares a cache and deduplicates requests with the rest of the app;
64
+ * omit it for an isolated cache.
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * const definition = await productsCollectionDefinition();
69
+ * const products = createProductCollection(definition, { basePath: '/api/v1' });
70
+ * await products.preload();
71
+ * const tx = products.insert({ id: crypto.randomUUID(), name: 'New' });
72
+ * await tx.isPersisted.promise;
73
+ * ```
74
+ */
75
+ export function createProductCollection(definition, options = {}) {
76
+ return createSmrtCollection(definition, {
77
+ basePath: '/api/v1',
78
+ ...options,
79
+ });
80
+ }
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "version": "1.0.0",
3
- "timestamp": 1783100603910,
3
+ "timestamp": 1783111325589,
4
4
  "packageName": "@happyvertical/smrt-products",
5
- "packageVersion": "0.37.10",
5
+ "packageVersion": "0.38.0",
6
6
  "objects": {
7
7
  "@happyvertical/smrt-products:CategoryCollection": {
8
8
  "name": "categorycollection",
@@ -1,3 +1,3 @@
1
1
  import { a as Product, i as Material, n as ProductVariant, o as ProductType, r as ProductAsset, s as Category, t as Sku } from "./chunks/Sku-B0w2dfHb.js";
2
- import "./chunks/models-D-yBusXS.js";
2
+ import "./chunks/models-DIAe1TCG.js";
3
3
  export { Category, Material, Product, ProductAsset, ProductType, ProductVariant, Sku };
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "generatedAt": "2026-07-03T17:43:24.298Z",
3
+ "generatedAt": "2026-07-03T20:42:06.020Z",
4
4
  "packageName": "@happyvertical/smrt-products",
5
- "packageVersion": "0.37.10",
5
+ "packageVersion": "0.38.0",
6
6
  "sourceManifestPath": "dist/lib/manifest.json",
7
7
  "agentDocPath": "AGENTS.md",
8
8
  "sourceHashes": {
9
- "manifest": "72d153e764dc6645c1a844d1eaf411a855297681c6c912b0fdd6372ce4ab0cd4",
10
- "packageJson": "1f1e1549b01c0d07a453baf291e109346c5918e93e5a9613af006b1cdbe7356e",
11
- "agents": "ede6063b72600b84908e1e32216fbbdd69d70d309f0b23c2add338ad080702d4"
9
+ "manifest": "4b9452c33b2268713b1c3bbf59ac5e65e19eca73fdc5384d3100ba89f4a8b168",
10
+ "packageJson": "2d5857f9b546771973468602416c8b3fc5ec70b060ca1df00ea381bbd279aad2",
11
+ "agents": "33d82ef8e2eb4597c4165e7576c20a02a76d224a75cadcbd89f9ce9cc1deae3c"
12
12
  },
13
13
  "exports": [
14
14
  ".",
@@ -19,6 +19,7 @@
19
19
  "./manifest.json",
20
20
  "./models",
21
21
  "./stores",
22
+ "./stores/product-collection",
22
23
  "./utils"
23
24
  ],
24
25
  "dependencies": {
@@ -28,8 +29,10 @@
28
29
  "@happyvertical/smrt-assets": "workspace:*",
29
30
  "@happyvertical/smrt-core": "workspace:*",
30
31
  "@happyvertical/smrt-scanner": "workspace:*",
32
+ "@happyvertical/smrt-svelte": "workspace:*",
31
33
  "@happyvertical/smrt-tenancy": "workspace:*",
32
34
  "@happyvertical/smrt-ui": "workspace:*",
35
+ "@happyvertical/smrt-web": "workspace:*",
33
36
  "@happyvertical/sql": "catalog:",
34
37
  "@happyvertical/utils": "catalog:",
35
38
  "cors": "^2.8.6",
@@ -52,9 +55,11 @@
52
55
  "@happyvertical/smrt-assets",
53
56
  "@happyvertical/smrt-core",
54
57
  "@happyvertical/smrt-scanner",
58
+ "@happyvertical/smrt-svelte",
55
59
  "@happyvertical/smrt-tenancy",
56
60
  "@happyvertical/smrt-ui",
57
- "@happyvertical/smrt-vitest"
61
+ "@happyvertical/smrt-vitest",
62
+ "@happyvertical/smrt-web"
58
63
  ],
59
64
  "sdkDependencies": [
60
65
  "@happyvertical/ai",
@@ -1578,5 +1583,5 @@
1578
1583
  "polymorphicAssociations": 0,
1579
1584
  "uuidColumns": 21
1580
1585
  },
1581
- "agentDoc": "# @happyvertical/smrt-products\n\nProduct catalog — reference template for triple-consumption: npm package library, module federation, and standalone REST API server.\n\n## Models\n\n- **Product**: STI base. Tenant-scoped (`@TenantScoped({ mode: 'optional' })`, nullable `tenantId`). Knowledge base product with specs, tags, and the `productType` discriminator. Consumers subclass this with vertical-specific subtypes (apparel `Style`, automotive `Model`, furniture `Design`, etc.).\n- **Material**: STI subtype. Raw input consumed by manufacturing (fabric, trim, thread, packaging, component). Meta fields: `materialKind`, `uom`, `costPerUnit`. Materials are first-class products in the catalog — the SAP/NetSuite pattern. Bills of materials in `@happyvertical/smrt-manufacturing` reference Materials by id.\n- **ProductVariant**: standalone (NOT a Product STI subtype). Declarative axis definition: `productId`, `axisName` (e.g. `'size'`, `'color'`, `'finish'`), `allowedValues` (JSON-stored array), optional `label` and `sortOrder`. Per-SKU value pins live on `Sku.attributes`. Lives in its own `product_variants` table; `conflictColumns: ['product_id', 'axis_name', 'tenant_id']`.\n- **Sku**: standalone. The smallest sellable / countable unit. `productId` points at a `Product` or any of its STI subtypes; `code` is the human-meaningful identifier; `attributes` JSON pins each axis value (`{ size: 'M', color: 'navy' }`). Lives in its own `product_skus` table; `conflictColumns: ['code', 'tenant_id']`. Stock balance and movement history for a Sku live in `@happyvertical/smrt-inventory`.\n- **ProductAsset**: dedicated owned-asset join in `product_assets` with `relationship` and `sortOrder`. Tenant-scoped to match Product.\n- **Category**: hierarchical (parentId, level, productCount). STI base, tenant-scoped.\n\n## Vertical-specific Product subtypes\n\nThis package deliberately ships ONLY the generic primitives. Domain-specific top-level item types live in the consumer's template:\n\n- Apparel: `Style extends Product`, `Makeup extends Product`\n- Furniture: `Design extends Product`, `Configuration extends Product`\n- Automotive: `Model extends Product`, `Trim extends Product`\n- CPG: `Brand extends Product`, `Recipe extends Product`\n\nEach is a small subclass: `@smrt()`, override `productType`, add `@meta()` fields. See `packages/template-apparel-erp` for a worked example.\n\n## Variants — the two concepts\n\nThe framework's variant story uses two distinct primitives that look similar but do different jobs:\n\n- **`ProductVariant`** — *axis declaration*. \"For product X, axis `size` accepts the values `[XS, S, M, L, XL]`.\" Drives form/UI choices.\n- **`Sku.attributes`** — *per-unit value pins*. `{ color: 'navy', size: 'M' }` on each concrete sellable SKU.\n\nBoth live in this package — all catalog shapes are here. Stock motion (where the SKU is, how many, history) lives in `@happyvertical/smrt-inventory`.\n\nThere is deliberately no separate \"catalog grouping above SKU\" row (a la a \"Navy colorway\" row sitting between the Product and its Skus). Group SKUs by axis value via `attributes.color = 'navy'` queries; attach per-axis-value assets via `ProductAsset` rows with relationship metadata. Matches how Shopify, Stripe Products, and most e-commerce platforms model the same shape.\n\n## Collections\n\n- **ProductCollection** — base. Polymorphic queries return the correct subclass instance per row.\n- **MaterialCollection** — STI-filtered subclass. Override `_itemClass`; framework auto-filters by `_meta_type`.\n- **ProductVariantCollection** — standalone collection over `product_variants`. Helpers: `findForProduct(productId)`, `findAxis(productId, axisName)`.\n- **SkuCollection** — standalone collection over `product_skus`. Helpers: `findByCode`, `findByBarcode`, `findByProduct`, `findByParent`, `findActive`.\n- **CategoryCollection** — standard Category CRUD with `getRootCategories()`.\n- **ProductAssetCollection** — direct access to `product_assets` rows and product asset helper wrappers.\n\n## Multi-tenancy\n\nOptional. With `withTenant(id, fn)` (from `@happyvertical/smrt-tenancy`), all queries auto-filter and inserts auto-stamp `tenantId`. Without it, models behave globally (`tenantId = null`). This lets the same package serve both shared reference catalogs and per-merchant SaaS catalogs.\n\n## Triple-Consumption Pattern\n\nSame codebase consumed three ways:\n1. **NPM library**: import classes directly\n2. **Module federation**: runtime component sharing (experimental)\n3. **Standalone API**: `startRestServer([Product, Category])`\n\n## Virtual Modules (Vite)\n\nAuto-generated via Vite plugins: `@happyvertical/smrt-client` (TypeScript client), `@happyvertical/smrt-types`, `@happyvertical/smrt-routes` (Express), `@happyvertical/smrt-mcp`, `@happyvertical/smrt-manifest`.\n\nSvelte 5 stores use runes (`$state`, `$derived`, `$effect`). `product-store.svelte.ts` is the main store (backed by the SMRT client); `product-store.client.svelte.ts` is a virtual-module-free variant for federation builds.\n\n## Schema migrations (Phase 1 release)\n\nThis package's schema changed shape between the previous release and the Phase 1 apparel-ERP release. Consumers upgrading need to migrate two tables.\n\n### `Sku` rows moved tables\n\nPreviously `Sku` shipped in `@happyvertical/smrt-inventory` under table `inventory_skus`. It now lives here under `product_skus`. Cross-package refs (`StockLevel.skuId`, `BomLine.componentSkuId`) carry plain string ids that still resolve.\n\n**Upgrade procedure** (works on SQLite + Postgres; does NOT rely on `CREATE TABLE AS` which strips constraints):\n\n1. **Boot the new version once** so the framework's lazy `syncSchema` creates `product_skus` with the right PRIMARY KEY, NOT NULL, UNIQUE (`code`, `tenant_id`), and indexes derived from the `Sku` model.\n\n2. **Idempotently copy rows**:\n\n ```sql\n BEGIN;\n INSERT INTO product_skus (\n id, slug, context, created_at, updated_at,\n tenant_id, product_id, code, barcode, name,\n attributes, weight_grams, parent_sku_id, active\n )\n SELECT\n id, slug, context, created_at, updated_at,\n tenant_id, product_id, code, barcode, name,\n attributes, weight_grams, parent_sku_id, active\n FROM inventory_skus\n WHERE NOT EXISTS (\n SELECT 1 FROM product_skus p WHERE p.id = inventory_skus.id\n );\n COMMIT;\n ```\n\n3. **Drop the legacy table** once row counts match:\n\n ```sql\n DROP TABLE IF EXISTS inventory_skus;\n ```\n\n### `ProductVariant` changed shape entirely\n\nPreviously a Product STI subtype carrying `parentProductId` + `axisValues` JSON inside `_meta_data` on the shared `products` table (`_meta_type='@happyvertical/smrt-products:ProductVariant'`). It is now a **standalone model** on its own `product_variants` table, with columns `productId`, `axisName`, `allowedValues`, `label`, `sortOrder`.\n\n**There is no automatic data conversion.** The old \"catalog grouping above SKU\" concept doesn't map 1:1 to the new \"per-axis declaration\" concept. Recommended procedure:\n\n1. Inspect the old rows: `SELECT * FROM products WHERE _meta_type = '@happyvertical/smrt-products:ProductVariant';`. Treat them as historical reference.\n2. Re-author axis declarations against the new shape (one `ProductVariant` row per `(productId, axisName)` pair, with `allowedValues` listing the values).\n3. Once the new declarations are populated and verified, remove the legacy rows: `DELETE FROM products WHERE _meta_type = '@happyvertical/smrt-products:ProductVariant';`.\n\nIf you had per-colorway / per-variant images attached via `ProductAsset` rows pointing at old ProductVariant ids, repoint those to the parent Product id; group-by-axis-value queries on `Sku.attributes` cover the same use case at the SKU level.\n\n## Gotchas\n\n- **`ProductVariant` and `Sku` are NOT Product STI subtypes** — they each have their own table (`product_variants`, `product_skus`) because their shapes don't fit the Product schema. Don't try to query them via `ProductCollection`.\n- **`npm run build` emits the published library surface directly**: package consumers read model, collection, and helper exports from `dist/lib`. Cross-package imports from this package should target `/models` or `/collections` subpaths (not the main entry) when the consumer isn't a vite app — the main entry pulls in vite virtual modules.\n- **Use `npm run build:all` only when you need standalone or federation bundles** in addition to the library output\n- **Constructor must explicitly assign all properties**: `Object.assign` doesn't work reliably with decorators\n- **STI subtype-specific fields use `Meta<T>`** — declare them as `fieldName: Meta<FieldType> = defaultValue`. The AST scanner detects the `Meta<T>` type wrapper at build time and routes the field through `_meta_data` JSON storage instead of materializing it as a column on the parent's table. Do **NOT** use the runtime `@meta()` decorator on STI children — it never reaches the manifest, so the schema generator treats the field as an ordinary column on the parent table and the framework's hydration path can't tell it's meta. Override `productType` on each subclass.\n- **Tenant-scoped STI children must repeat `@TenantScoped`** — `@TenantScoped` registers per concrete className, so `Material extends Product` inheriting from a tenant-scoped `Product` is NOT automatically tenant-scoped itself. `MaterialCollection.list/save` passes `'Material'` to the tenant interceptor, which looks up `'Material'` (not `'Product'`) in the per-class registry. Without an explicit `@TenantScoped({ mode: 'optional' })` on `Material`, material rows skip the tenant auto-filter and auto-populate.\n- **STI children must repeat `@smrt({ api, mcp, cli })` generation config (S5 #1406)** — like `@TenantScoped`, the generation config is registered per concrete className and is NOT inherited from the STI parent. An empty `@smrt()` on a child resolves `getConfig(child).api/.mcp` to `undefined`, which the REST and MCP generators treat as \"expose EVERYTHING\" — including `delete` and write-capable MCP tools — even when the parent deliberately restricts its surface. The package's `mcp.ts` generator enumerates the whole registry, so an under-configured child ships a wide-open surface silently. Re-declare the parent's `api`/`mcp`/`cli` posture on every subtype (see `Material`). Consumer subtypes (apparel `Style`/`Makeup`, automotive `Model`/`Trim`, …) must do the same.\n- **Two-tenant same-slug is currently a hard error** for tenant-scoped STI bases (`Product`, `Category`). The core schema generator hardcodes the STI unique index as `(slug, context, _meta_type)` and does NOT include `tenant_id` even for `@TenantScoped` classes. Two tenants saving a row with the same slug + context + meta_type collide at the SQL layer. Workaround: namespace slugs per tenant on the application side (e.g. `${tenantId}-widget`) until the upstream framework fix lands.\n- **Module Federation marked experimental**: may change\n"
1586
+ "agentDoc": "# @happyvertical/smrt-products\n\nProduct catalog — reference template for triple-consumption: npm package library, module federation, and standalone REST API server.\n\n## Models\n\n- **Product**: STI base. Tenant-scoped (`@TenantScoped({ mode: 'optional' })`, nullable `tenantId`). Knowledge base product with specs, tags, and the `productType` discriminator. Consumers subclass this with vertical-specific subtypes (apparel `Style`, automotive `Model`, furniture `Design`, etc.).\n- **Material**: STI subtype. Raw input consumed by manufacturing (fabric, trim, thread, packaging, component). Meta fields: `materialKind`, `uom`, `costPerUnit`. Materials are first-class products in the catalog — the SAP/NetSuite pattern. Bills of materials in `@happyvertical/smrt-manufacturing` reference Materials by id.\n- **ProductVariant**: standalone (NOT a Product STI subtype). Declarative axis definition: `productId`, `axisName` (e.g. `'size'`, `'color'`, `'finish'`), `allowedValues` (JSON-stored array), optional `label` and `sortOrder`. Per-SKU value pins live on `Sku.attributes`. Lives in its own `product_variants` table; `conflictColumns: ['product_id', 'axis_name', 'tenant_id']`.\n- **Sku**: standalone. The smallest sellable / countable unit. `productId` points at a `Product` or any of its STI subtypes; `code` is the human-meaningful identifier; `attributes` JSON pins each axis value (`{ size: 'M', color: 'navy' }`). Lives in its own `product_skus` table; `conflictColumns: ['code', 'tenant_id']`. Stock balance and movement history for a Sku live in `@happyvertical/smrt-inventory`.\n- **ProductAsset**: dedicated owned-asset join in `product_assets` with `relationship` and `sortOrder`. Tenant-scoped to match Product.\n- **Category**: hierarchical (parentId, level, productCount). STI base, tenant-scoped.\n\n## Vertical-specific Product subtypes\n\nThis package deliberately ships ONLY the generic primitives. Domain-specific top-level item types live in the consumer's template:\n\n- Apparel: `Style extends Product`, `Makeup extends Product`\n- Furniture: `Design extends Product`, `Configuration extends Product`\n- Automotive: `Model extends Product`, `Trim extends Product`\n- CPG: `Brand extends Product`, `Recipe extends Product`\n\nEach is a small subclass: `@smrt()`, override `productType`, add `@meta()` fields. See `packages/template-apparel-erp` for a worked example.\n\n## Variants — the two concepts\n\nThe framework's variant story uses two distinct primitives that look similar but do different jobs:\n\n- **`ProductVariant`** — *axis declaration*. \"For product X, axis `size` accepts the values `[XS, S, M, L, XL]`.\" Drives form/UI choices.\n- **`Sku.attributes`** — *per-unit value pins*. `{ color: 'navy', size: 'M' }` on each concrete sellable SKU.\n\nBoth live in this package — all catalog shapes are here. Stock motion (where the SKU is, how many, history) lives in `@happyvertical/smrt-inventory`.\n\nThere is deliberately no separate \"catalog grouping above SKU\" row (a la a \"Navy colorway\" row sitting between the Product and its Skus). Group SKUs by axis value via `attributes.color = 'navy'` queries; attach per-axis-value assets via `ProductAsset` rows with relationship metadata. Matches how Shopify, Stripe Products, and most e-commerce platforms model the same shape.\n\n## Collections\n\n- **ProductCollection** — base. Polymorphic queries return the correct subclass instance per row.\n- **MaterialCollection** — STI-filtered subclass. Override `_itemClass`; framework auto-filters by `_meta_type`.\n- **ProductVariantCollection** — standalone collection over `product_variants`. Helpers: `findForProduct(productId)`, `findAxis(productId, axisName)`.\n- **SkuCollection** — standalone collection over `product_skus`. Helpers: `findByCode`, `findByBarcode`, `findByProduct`, `findByParent`, `findActive`.\n- **CategoryCollection** — standard Category CRUD with `getRootCategories()`.\n- **ProductAssetCollection** — direct access to `product_assets` rows and product asset helper wrappers.\n\n## Multi-tenancy\n\nOptional. With `withTenant(id, fn)` (from `@happyvertical/smrt-tenancy`), all queries auto-filter and inserts auto-stamp `tenantId`. Without it, models behave globally (`tenantId = null`). This lets the same package serve both shared reference catalogs and per-merchant SaaS catalogs.\n\n## Triple-Consumption Pattern\n\nSame codebase consumed three ways:\n1. **NPM library**: import classes directly\n2. **Module federation**: runtime component sharing (experimental)\n3. **Standalone API**: `startRestServer([Product, Category])`\n\n## Virtual Modules (Vite)\n\nAuto-generated via Vite plugins: `@happyvertical/smrt-client` (TypeScript client), `@happyvertical/smrt-types`, `@happyvertical/smrt-routes` (Express), `@happyvertical/smrt-mcp`, `@happyvertical/smrt-manifest`.\n\nSvelte 5 stores use runes (`$state`, `$derived`, `$effect`). `product-store.svelte.ts` is the main store (backed by the SMRT client); `product-store.client.svelte.ts` is a virtual-module-free variant for federation builds.\n\n## Client-data runtime — reference store (#1761)\n\nProducts is the reference consumer of the `@happyvertical/smrt-web` browser client-data runtime.\n\n- **Store** — `src/lib/stores/product-collection.ts` (subpath `@happyvertical/smrt-products/stores/product-collection`). `createProductCollection(definition, options)` builds a cached, reactive `SmrtWebCollection<ProductData>` over the generated `/api/v1/products` REST surface via `createSmrtCollection`. It is plugin-agnostic on purpose: the `products` definition is a PARAMETER (not a top-level import), so importing the store never eagerly resolves `@happyvertical/smrt-virt-web` (which exists only under the SMRT Vite plugin) — a unit test / npm consumer supplies its own definition. `productsCollectionDefinition()` lazily resolves the plugin definition (dynamic `import()`; resolved for `tsc` via the `@smrt/web` ambient alias). Deliberately NOT re-exported from the always-loaded `./stores` barrel — importing it is an explicit opt-in to the engine.\n- **Live surface** — `src/lib/components/LiveProductList.svelte` binds the store with `liveCollection` from `@happyvertical/smrt-svelte/web` (live rows + optimistic insert); it takes the definition as a prop. `src/app/pages/LiveProductsPage.svelte` (route `#live`) resolves the component AND the definition via `import()` and passes the definition down.\n- **Code-split (ratified condition ①)** — the ~76 kB TanStack engine must NEVER load on public / smrt-sites pages. `LiveProductsPage` reaches `LiveProductList` and the store ONLY through dynamic `import()`, so the engine lands in a lazily-loaded chunk; the app entry stays engine-free. NEVER import the store or live component statically from an app-root / public entry. `scripts/check-web-engine-code-split.mjs` (wrapped by `src/web-engine-code-split.spec.ts`, `pnpm test:code-split`) proves this against the REAL app graph: it runs the `--mode standalone` vite build and asserts, over the emitted rollup chunk graph, that the entry's static-import closure has zero `@tanstack/*` and the engine is reached only via `dynamicImports`. If the build hits the pre-existing nested-worktree `Tsconfig not found` failure locally, it falls back to a static-import-graph walk of the real `src/app/main.ts` (CI runs the real build).\n\n## Schema migrations (Phase 1 release)\n\nThis package's schema changed shape between the previous release and the Phase 1 apparel-ERP release. Consumers upgrading need to migrate two tables.\n\n### `Sku` rows moved tables\n\nPreviously `Sku` shipped in `@happyvertical/smrt-inventory` under table `inventory_skus`. It now lives here under `product_skus`. Cross-package refs (`StockLevel.skuId`, `BomLine.componentSkuId`) carry plain string ids that still resolve.\n\n**Upgrade procedure** (works on SQLite + Postgres; does NOT rely on `CREATE TABLE AS` which strips constraints):\n\n1. **Boot the new version once** so the framework's lazy `syncSchema` creates `product_skus` with the right PRIMARY KEY, NOT NULL, UNIQUE (`code`, `tenant_id`), and indexes derived from the `Sku` model.\n\n2. **Idempotently copy rows**:\n\n ```sql\n BEGIN;\n INSERT INTO product_skus (\n id, slug, context, created_at, updated_at,\n tenant_id, product_id, code, barcode, name,\n attributes, weight_grams, parent_sku_id, active\n )\n SELECT\n id, slug, context, created_at, updated_at,\n tenant_id, product_id, code, barcode, name,\n attributes, weight_grams, parent_sku_id, active\n FROM inventory_skus\n WHERE NOT EXISTS (\n SELECT 1 FROM product_skus p WHERE p.id = inventory_skus.id\n );\n COMMIT;\n ```\n\n3. **Drop the legacy table** once row counts match:\n\n ```sql\n DROP TABLE IF EXISTS inventory_skus;\n ```\n\n### `ProductVariant` changed shape entirely\n\nPreviously a Product STI subtype carrying `parentProductId` + `axisValues` JSON inside `_meta_data` on the shared `products` table (`_meta_type='@happyvertical/smrt-products:ProductVariant'`). It is now a **standalone model** on its own `product_variants` table, with columns `productId`, `axisName`, `allowedValues`, `label`, `sortOrder`.\n\n**There is no automatic data conversion.** The old \"catalog grouping above SKU\" concept doesn't map 1:1 to the new \"per-axis declaration\" concept. Recommended procedure:\n\n1. Inspect the old rows: `SELECT * FROM products WHERE _meta_type = '@happyvertical/smrt-products:ProductVariant';`. Treat them as historical reference.\n2. Re-author axis declarations against the new shape (one `ProductVariant` row per `(productId, axisName)` pair, with `allowedValues` listing the values).\n3. Once the new declarations are populated and verified, remove the legacy rows: `DELETE FROM products WHERE _meta_type = '@happyvertical/smrt-products:ProductVariant';`.\n\nIf you had per-colorway / per-variant images attached via `ProductAsset` rows pointing at old ProductVariant ids, repoint those to the parent Product id; group-by-axis-value queries on `Sku.attributes` cover the same use case at the SKU level.\n\n## Gotchas\n\n- **`ProductVariant` and `Sku` are NOT Product STI subtypes** — they each have their own table (`product_variants`, `product_skus`) because their shapes don't fit the Product schema. Don't try to query them via `ProductCollection`.\n- **`npm run build` emits the published library surface directly**: package consumers read model, collection, and helper exports from `dist/lib`. Cross-package imports from this package should target `/models` or `/collections` subpaths (not the main entry) when the consumer isn't a vite app — the main entry pulls in vite virtual modules.\n- **Use `npm run build:all` only when you need standalone or federation bundles** in addition to the library output\n- **Constructor must explicitly assign all properties**: `Object.assign` doesn't work reliably with decorators\n- **STI subtype-specific fields use `Meta<T>`** — declare them as `fieldName: Meta<FieldType> = defaultValue`. The AST scanner detects the `Meta<T>` type wrapper at build time and routes the field through `_meta_data` JSON storage instead of materializing it as a column on the parent's table. Do **NOT** use the runtime `@meta()` decorator on STI children — it never reaches the manifest, so the schema generator treats the field as an ordinary column on the parent table and the framework's hydration path can't tell it's meta. Override `productType` on each subclass.\n- **Tenant-scoped STI children must repeat `@TenantScoped`** — `@TenantScoped` registers per concrete className, so `Material extends Product` inheriting from a tenant-scoped `Product` is NOT automatically tenant-scoped itself. `MaterialCollection.list/save` passes `'Material'` to the tenant interceptor, which looks up `'Material'` (not `'Product'`) in the per-class registry. Without an explicit `@TenantScoped({ mode: 'optional' })` on `Material`, material rows skip the tenant auto-filter and auto-populate.\n- **STI children must repeat `@smrt({ api, mcp, cli })` generation config (S5 #1406)** — like `@TenantScoped`, the generation config is registered per concrete className and is NOT inherited from the STI parent. An empty `@smrt()` on a child resolves `getConfig(child).api/.mcp` to `undefined`, which the REST and MCP generators treat as \"expose EVERYTHING\" — including `delete` and write-capable MCP tools — even when the parent deliberately restricts its surface. The package's `mcp.ts` generator enumerates the whole registry, so an under-configured child ships a wide-open surface silently. Re-declare the parent's `api`/`mcp`/`cli` posture on every subtype (see `Material`). Consumer subtypes (apparel `Style`/`Makeup`, automotive `Model`/`Trim`, …) must do the same.\n- **Two-tenant same-slug is currently a hard error** for tenant-scoped STI bases (`Product`, `Category`). The core schema generator hardcodes the STI unique index as `(slug, context, _meta_type)` and does NOT include `tenant_id` even for `@TenantScoped` classes. Two tenants saving a row with the same slug + context + meta_type collide at the SQL layer. Workaround: namespace slugs per tenant on the application side (e.g. `${tenantId}-widget`) until the upstream framework fix lands.\n- **Module Federation marked experimental**: may change\n"
1582
1587
  }
@@ -0,0 +1,85 @@
1
+ import { createSmrtCollection } from "@happyvertical/smrt-web";
2
+ //#region src/lib/stores/product-collection.ts
3
+ /**
4
+ * Reference `@happyvertical/smrt-web` store for the products package (#1761,
5
+ * slice D).
6
+ *
7
+ * Products is the reference consumer of the browser client-data runtime. This
8
+ * module materializes a manifest-generated `products` web collection definition
9
+ * into a cached, reactive {@link SmrtWebCollection} over the generated
10
+ * `/api/v1/products` REST surface via {@link createSmrtCollection}. The Svelte
11
+ * live-query binding + optimistic insert live in
12
+ * `../components/LiveProductList.svelte`.
13
+ *
14
+ * ── Plugin-agnostic on purpose ──────────────────────────────────────────────
15
+ * The `products` definition comes from the `@happyvertical/smrt-virt-web`
16
+ * virtual module, which exists ONLY under a SMRT Vite-plugin build. To keep
17
+ * this module importable everywhere (unit tests, plain `tsc`, an npm consumer
18
+ * wiring its own definition), it does NOT import that virtual module at the top
19
+ * level. Instead the definition is supplied by the caller:
20
+ * - the live component resolves it from the plugin (see LiveProductList),
21
+ * - {@link productsCollectionDefinition} lazily resolves it on demand.
22
+ * A caller passing an explicit `definition` never touches the virtual module.
23
+ *
24
+ * ── Engine-absorption boundary ──────────────────────────────────────────────
25
+ * `createSmrtCollection` pulls the client-data engine (currently the ~76 kB
26
+ * TanStack DB/Query layer). This module is therefore engine-bearing. It is
27
+ * imported ONLY through a dynamic `import()` (see
28
+ * `../components/LiveProductList.svelte`, reached from
29
+ * `src/app/pages/LiveProductsPage.svelte` via `import()`), so the bundler lands
30
+ * the engine in a lazily-loaded chunk that public / smrt-sites pages never
31
+ * fetch (ratified condition ① of #1761). NEVER import this module (or the live
32
+ * component) statically from an app-root / public entry — doing so pulls the
33
+ * engine into the entry bundle and defeats the split. The
34
+ * `scripts/check-web-engine-code-split.mjs` assertion guards this.
35
+ */
36
+ /**
37
+ * Lazily resolve the manifest-generated `products` definition from the
38
+ * `@happyvertical/smrt-virt-web` virtual module.
39
+ *
40
+ * Kept out of module top-level so importing this store never eagerly resolves a
41
+ * module that exists only under a SMRT Vite-plugin build — a unit test or npm
42
+ * consumer that supplies its own definition must never trigger it. The dynamic
43
+ * `import()` also keeps the virtual specifier out of every static import graph.
44
+ * Resolved for `tsc` via the ambient `@happyvertical/smrt-virt-web` → `@smrt/web`
45
+ * alias in `ambient.d.ts`.
46
+ */
47
+ async function productsCollectionDefinition() {
48
+ const { getCollectionDefinition } = await import("@happyvertical/smrt-virt-web");
49
+ return getCollectionDefinition("products");
50
+ }
51
+ /**
52
+ * Build the reference products collection over the generated REST surface from
53
+ * a `products` collection definition.
54
+ *
55
+ * The definition is a parameter (not resolved here) so this factory is
56
+ * synchronous and plugin-agnostic: the live component passes the
57
+ * plugin-provided definition (via {@link productsCollectionDefinition}); a unit
58
+ * test or npm consumer passes its own. Neither path imports the virtual module
59
+ * unless it explicitly calls {@link productsCollectionDefinition}.
60
+ *
61
+ * Reads are stale-while-revalidate; `insert({ ...data, id })` is optimistic and
62
+ * rolls back automatically if the server rejects the create. Pass a shared
63
+ * {@link SmrtWebClient} (from `createSmrtWebClient()`) as `client` so this
64
+ * collection shares a cache and deduplicates requests with the rest of the app;
65
+ * omit it for an isolated cache.
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * const definition = await productsCollectionDefinition();
70
+ * const products = createProductCollection(definition, { basePath: '/api/v1' });
71
+ * await products.preload();
72
+ * const tx = products.insert({ id: crypto.randomUUID(), name: 'New' });
73
+ * await tx.isPersisted.promise;
74
+ * ```
75
+ */
76
+ function createProductCollection(definition, options = {}) {
77
+ return createSmrtCollection(definition, {
78
+ basePath: "/api/v1",
79
+ ...options
80
+ });
81
+ }
82
+ //#endregion
83
+ export { createProductCollection, productsCollectionDefinition };
84
+
85
+ //# sourceMappingURL=product-collection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product-collection.js","names":[],"sources":["../../../src/lib/stores/product-collection.ts"],"sourcesContent":["/**\n * Reference `@happyvertical/smrt-web` store for the products package (#1761,\n * slice D).\n *\n * Products is the reference consumer of the browser client-data runtime. This\n * module materializes a manifest-generated `products` web collection definition\n * into a cached, reactive {@link SmrtWebCollection} over the generated\n * `/api/v1/products` REST surface via {@link createSmrtCollection}. The Svelte\n * live-query binding + optimistic insert live in\n * `../components/LiveProductList.svelte`.\n *\n * ── Plugin-agnostic on purpose ──────────────────────────────────────────────\n * The `products` definition comes from the `@happyvertical/smrt-virt-web`\n * virtual module, which exists ONLY under a SMRT Vite-plugin build. To keep\n * this module importable everywhere (unit tests, plain `tsc`, an npm consumer\n * wiring its own definition), it does NOT import that virtual module at the top\n * level. Instead the definition is supplied by the caller:\n * - the live component resolves it from the plugin (see LiveProductList),\n * - {@link productsCollectionDefinition} lazily resolves it on demand.\n * A caller passing an explicit `definition` never touches the virtual module.\n *\n * ── Engine-absorption boundary ──────────────────────────────────────────────\n * `createSmrtCollection` pulls the client-data engine (currently the ~76 kB\n * TanStack DB/Query layer). This module is therefore engine-bearing. It is\n * imported ONLY through a dynamic `import()` (see\n * `../components/LiveProductList.svelte`, reached from\n * `src/app/pages/LiveProductsPage.svelte` via `import()`), so the bundler lands\n * the engine in a lazily-loaded chunk that public / smrt-sites pages never\n * fetch (ratified condition ① of #1761). NEVER import this module (or the live\n * component) statically from an app-root / public entry — doing so pulls the\n * engine into the entry bundle and defeats the split. The\n * `scripts/check-web-engine-code-split.mjs` assertion guards this.\n */\n\nimport {\n type CreateSmrtCollectionOptions,\n createSmrtCollection,\n type SmrtWebClient,\n type SmrtWebCollection,\n type SmrtWebCollectionDefinition,\n} from '@happyvertical/smrt-web';\nimport type { ProductData } from '../types';\n\n/**\n * The public DTO carried by the products collection: the persisted product\n * columns plus the required `id` key the client collection stores rows under.\n */\nexport type ProductRow = ProductData & { id: string };\n\n/** The `products` collection definition, typed to this package's row shape. */\nexport type ProductCollectionDefinition =\n SmrtWebCollectionDefinition<ProductData>;\n\n/** Options for {@link createProductCollection}. */\nexport type CreateProductCollectionOptions = Pick<\n CreateSmrtCollectionOptions,\n 'basePath' | 'fetchFn' | 'client' | 'scope' | 'staleTimeMs' | 'retry'\n>;\n\n/**\n * Lazily resolve the manifest-generated `products` definition from the\n * `@happyvertical/smrt-virt-web` virtual module.\n *\n * Kept out of module top-level so importing this store never eagerly resolves a\n * module that exists only under a SMRT Vite-plugin build — a unit test or npm\n * consumer that supplies its own definition must never trigger it. The dynamic\n * `import()` also keeps the virtual specifier out of every static import graph.\n * Resolved for `tsc` via the ambient `@happyvertical/smrt-virt-web` → `@smrt/web`\n * alias in `ambient.d.ts`.\n */\nexport async function productsCollectionDefinition(): Promise<ProductCollectionDefinition> {\n const { getCollectionDefinition } = await import(\n '@happyvertical/smrt-virt-web'\n );\n return getCollectionDefinition(\n 'products',\n ) as unknown as ProductCollectionDefinition;\n}\n\n/**\n * Build the reference products collection over the generated REST surface from\n * a `products` collection definition.\n *\n * The definition is a parameter (not resolved here) so this factory is\n * synchronous and plugin-agnostic: the live component passes the\n * plugin-provided definition (via {@link productsCollectionDefinition}); a unit\n * test or npm consumer passes its own. Neither path imports the virtual module\n * unless it explicitly calls {@link productsCollectionDefinition}.\n *\n * Reads are stale-while-revalidate; `insert({ ...data, id })` is optimistic and\n * rolls back automatically if the server rejects the create. Pass a shared\n * {@link SmrtWebClient} (from `createSmrtWebClient()`) as `client` so this\n * collection shares a cache and deduplicates requests with the rest of the app;\n * omit it for an isolated cache.\n *\n * @example\n * ```ts\n * const definition = await productsCollectionDefinition();\n * const products = createProductCollection(definition, { basePath: '/api/v1' });\n * await products.preload();\n * const tx = products.insert({ id: crypto.randomUUID(), name: 'New' });\n * await tx.isPersisted.promise;\n * ```\n */\nexport function createProductCollection(\n definition: ProductCollectionDefinition,\n options: CreateProductCollectionOptions = {},\n): SmrtWebCollection<ProductData> {\n return createSmrtCollection<ProductData>(definition, {\n basePath: '/api/v1',\n ...options,\n });\n}\n\nexport type { SmrtWebClient, SmrtWebCollection, SmrtWebCollectionDefinition };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsEA,eAAsB,+BAAqE;CACzF,MAAM,EAAE,4BAA4B,MAAM,OACxC;CAEF,OAAO,wBACL,UACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,wBACd,YACA,UAA0C,CAAC,GACX;CAChC,OAAO,qBAAkC,YAAY;EACnD,UAAU;EACV,GAAG;CACL,CAAC;AACH"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-products",
3
- "version": "0.37.10",
3
+ "version": "0.38.0",
4
4
  "description": "SMRT products module: triple-purpose microservice template for standalone apps, federated modules, and NPM libraries",
5
5
  "author": "HappyVertical",
6
6
  "type": "module",
@@ -32,6 +32,11 @@
32
32
  "types": "./dist/lib/stores.d.ts",
33
33
  "default": "./dist/lib/stores.js"
34
34
  },
35
+ "./stores/product-collection": {
36
+ "types": "./dist/lib/lib/stores/product-collection.d.ts",
37
+ "svelte": "./dist/lib/stores/product-collection.js",
38
+ "default": "./dist/lib/stores/product-collection.js"
39
+ },
35
40
  "./generated": {
36
41
  "types": "./dist/lib/generated.d.ts",
37
42
  "default": "./dist/lib/generated.js"
@@ -55,11 +60,13 @@
55
60
  "@happyvertical/utils": "^0.74.11",
56
61
  "cors": "^2.8.6",
57
62
  "express": "^5.2.1",
58
- "@happyvertical/smrt-assets": "0.37.10",
59
- "@happyvertical/smrt-scanner": "0.37.10",
60
- "@happyvertical/smrt-tenancy": "0.37.10",
61
- "@happyvertical/smrt-ui": "0.37.10",
62
- "@happyvertical/smrt-core": "0.37.10"
63
+ "@happyvertical/smrt-core": "0.38.0",
64
+ "@happyvertical/smrt-scanner": "0.38.0",
65
+ "@happyvertical/smrt-assets": "0.38.0",
66
+ "@happyvertical/smrt-svelte": "0.38.0",
67
+ "@happyvertical/smrt-tenancy": "0.38.0",
68
+ "@happyvertical/smrt-ui": "0.38.0",
69
+ "@happyvertical/smrt-web": "0.38.0"
63
70
  },
64
71
  "peerDependencies": {
65
72
  "svelte": "^5.56.4"
@@ -82,7 +89,7 @@
82
89
  "typescript": "^5.9.3",
83
90
  "vite": "^8.1.2",
84
91
  "vitest": "^4.1.9",
85
- "@happyvertical/smrt-vitest": "0.37.10"
92
+ "@happyvertical/smrt-vitest": "0.38.0"
86
93
  },
87
94
  "keywords": [
88
95
  "smrt",
@@ -122,6 +129,7 @@
122
129
  "preview": "vite preview",
123
130
  "test": "vitest run",
124
131
  "test:watch": "vitest",
132
+ "test:code-split": "node scripts/check-web-engine-code-split.mjs",
125
133
  "verify:pack": "node ../../scripts/verify-package-types-exports.js .",
126
134
  "clean": "rm -rf dist src/lib/types/smrt-generated"
127
135
  }