create-nextblock 0.10.9 → 0.11.2

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 (64) hide show
  1. package/package.json +1 -1
  2. package/templates/nextblock-template/app/actions/interactions.test.ts +301 -0
  3. package/templates/nextblock-template/app/actions/interactions.ts +372 -0
  4. package/templates/nextblock-template/app/api/ai/cortex/build-widget/route.ts +4 -4
  5. package/templates/nextblock-template/app/api/ai/generate-blocks/route.ts +2 -2
  6. package/templates/nextblock-template/app/api/ai/global-agent/route.ts +56 -57
  7. package/templates/nextblock-template/app/api/cron/reset-sandbox/route.ts +1 -1
  8. package/templates/nextblock-template/app/api/cron/reset-sandbox/sandboxResetSql.ts +837 -0
  9. package/templates/nextblock-template/app/article/[slug]/PostClientContent.tsx +6 -0
  10. package/templates/nextblock-template/app/cms/CmsClientLayout.tsx +4 -0
  11. package/templates/nextblock-template/app/cms/components/ConnectGitHubButton.tsx +122 -0
  12. package/templates/nextblock-template/app/cms/components/github-connect-actions.ts +102 -0
  13. package/templates/nextblock-template/app/cms/dashboard/components/DashboardOnboarding.tsx +18 -13
  14. package/templates/nextblock-template/app/cms/interactions/InteractionsModerationClient.tsx +408 -0
  15. package/templates/nextblock-template/app/cms/interactions/page.tsx +51 -0
  16. package/templates/nextblock-template/app/cms/settings/cortex-ai/SandboxCortexAiSettingsClient.tsx +4 -3
  17. package/templates/nextblock-template/app/cms/settings/cortex-ai/StoredCortexAiSettingsClient.tsx +1 -1
  18. package/templates/nextblock-template/app/cms/settings/cortex-ai/actions.ts +3 -5
  19. package/templates/nextblock-template/app/cms/settings/cortex-ai/page.tsx +1 -1
  20. package/templates/nextblock-template/app/page.tsx +2 -2
  21. package/templates/nextblock-template/app/product/[slug]/page.tsx +2 -0
  22. package/templates/nextblock-template/components/AppShell.tsx +1 -1
  23. package/templates/nextblock-template/components/PostCommentsSection.tsx +369 -0
  24. package/templates/nextblock-template/components/ProductReviewsSection.tsx +419 -0
  25. package/templates/nextblock-template/components/blocks/renderers/ProductDetailsBlockRenderer.tsx +2 -0
  26. package/templates/nextblock-template/components/privacy/ConsentBanner.tsx +62 -19
  27. package/templates/nextblock-template/docs/08-NEXTBLOCK-CORTEX-AI-ARCHITECTURE.md +19 -19
  28. package/templates/nextblock-template/docs/10-CUSTOM-BLOCKS.md +4 -4
  29. package/templates/nextblock-template/docs/12-VERCEL-DEPLOYMENT.md +9 -8
  30. package/templates/nextblock-template/docs/13-STAYING-UP-TO-DATE.md +38 -9
  31. package/templates/nextblock-template/lib/blocks/ProductGridBlock.tsx +2 -0
  32. package/templates/nextblock-template/lib/onboarding/status.ts +13 -6
  33. package/templates/nextblock-template/lib/setup/actions.ts +3 -1
  34. package/templates/nextblock-template/lib/setup/migrations-bundle.ts +30 -0
  35. package/templates/nextblock-template/lib/updates/check-upstream.ts +44 -7
  36. package/templates/nextblock-template/lib/updates/github-device.ts +206 -0
  37. package/templates/nextblock-template/lib/updates/repo-identity.ts +11 -1
  38. package/templates/nextblock-template/package.json +2 -1
  39. package/templates/nextblock-template/scripts/verify-cortex-ai-build-widget.tsx +2 -4
  40. package/templates/nextblock-template/scripts/verify-cortex-ai-generate-blocks.ts +1 -1
  41. package/templates/nextblock-template/scripts/verify-cortex-ai-global-tools.ts +1 -1
  42. package/templates/nextblock-template/scripts/verify-cortex-ai-routing.ts +1 -1
  43. package/templates/nextblock-template/tsconfig.tsbuildinfo +1 -1
  44. package/templates/nextblock-template/lib/ai-block-generation.ts +0 -339
  45. package/templates/nextblock-template/lib/ai-client.ts +0 -247
  46. package/templates/nextblock-template/lib/ai-config.ts +0 -98
  47. package/templates/nextblock-template/lib/ai-cortex-widget-builder.ts +0 -125
  48. package/templates/nextblock-template/lib/ai-global-agent-custom-block-tools.ts +0 -363
  49. package/templates/nextblock-template/lib/ai-global-agent-db-tools.test.ts +0 -405
  50. package/templates/nextblock-template/lib/ai-global-agent-db-tools.ts +0 -1228
  51. package/templates/nextblock-template/lib/ai-global-agent-ecommerce.ts +0 -5
  52. package/templates/nextblock-template/lib/ai-global-agent-tools-stats.test.ts +0 -223
  53. package/templates/nextblock-template/lib/ai-global-agent-tools.test.ts +0 -2183
  54. package/templates/nextblock-template/lib/ai-global-agent-tools.ts +0 -4807
  55. package/templates/nextblock-template/lib/ai-key-crypto.test.ts +0 -70
  56. package/templates/nextblock-template/lib/ai-key-crypto.ts +0 -132
  57. package/templates/nextblock-template/lib/ai-model-catalog.test.ts +0 -49
  58. package/templates/nextblock-template/lib/ai-model-catalog.ts +0 -41
  59. package/templates/nextblock-template/lib/ai-model-registry.test.ts +0 -231
  60. package/templates/nextblock-template/lib/ai-model-registry.ts +0 -522
  61. package/templates/nextblock-template/lib/cortex-widget-registry.test.ts +0 -199
  62. package/templates/nextblock-template/lib/cortex-widget-registry.ts +0 -88
  63. package/templates/nextblock-template/lib/cortex-widget-schema.test.tsx +0 -237
  64. package/templates/nextblock-template/lib/cortex-widget-schema.ts +0 -393
@@ -1,5 +0,0 @@
1
- export {
2
- createProduct,
3
- productSchema,
4
- updateProduct,
5
- } from '@nextblock-cms/ecommerce/server';
@@ -1,223 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
- import { executeFetchEcommerceStats } from './ai-global-agent-tools';
3
-
4
- type MockRow = Record<string, any>;
5
- type MockDatabase = Record<string, MockRow[]>;
6
-
7
- class MockQuery {
8
- private equalsFilters: Array<{ column: string; value: unknown }> = [];
9
- private gteFilters: Array<{ column: string; value: string }> = [];
10
- private lteFilters: Array<{ column: string; value: string }> = [];
11
-
12
- constructor(
13
- private readonly database: MockDatabase,
14
- private readonly table: string,
15
- private readonly errors: Record<string, unknown> = {}
16
- ) {}
17
-
18
- select() {
19
- return this;
20
- }
21
-
22
- eq(column: string, value: unknown) {
23
- this.equalsFilters.push({ column, value });
24
- return this;
25
- }
26
-
27
- gte(column: string, value: string) {
28
- this.gteFilters.push({ column, value });
29
- return this;
30
- }
31
-
32
- lte(column: string, value: string) {
33
- this.lteFilters.push({ column, value });
34
- return this;
35
- }
36
-
37
- then<TResult1 = any, TResult2 = never>(
38
- onfulfilled?: ((value: any) => TResult1 | PromiseLike<TResult1>) | null,
39
- onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null
40
- ) {
41
- return this.execute().then(onfulfilled, onrejected);
42
- }
43
-
44
- private getValue(row: MockRow, column: string) {
45
- return column.split('.').reduce((value: any, key) => {
46
- const target = Array.isArray(value) ? value[0] : value;
47
- return target?.[key];
48
- }, row);
49
- }
50
-
51
- private matches(row: MockRow) {
52
- return (
53
- this.equalsFilters.every((filter) => this.getValue(row, filter.column) === filter.value) &&
54
- this.gteFilters.every((filter) => String(this.getValue(row, filter.column)) >= filter.value) &&
55
- this.lteFilters.every((filter) => String(this.getValue(row, filter.column)) <= filter.value)
56
- );
57
- }
58
-
59
- private async execute() {
60
- const error = this.errors[this.table];
61
-
62
- if (error) {
63
- return { data: null, error };
64
- }
65
-
66
- return {
67
- data: (this.database[this.table] || []).filter((row) => this.matches(row)),
68
- error: null,
69
- };
70
- }
71
- }
72
-
73
- function createMockSupabase(database: MockDatabase, errors: Record<string, unknown> = {}) {
74
- return {
75
- from: vi.fn((table: string) => new MockQuery(database, table, errors)),
76
- };
77
- }
78
-
79
- describe('fetch_ecommerce_stats tool executor', () => {
80
- it('fetches ecommerce stats and aggregates revenue by product', async () => {
81
- const supabase = createMockSupabase({
82
- order_items: [
83
- {
84
- quantity: 2,
85
- price_at_purchase: 5000,
86
- products: { id: 'p1', title: 'Digital Art', product_type: 'digital' },
87
- orders: {
88
- id: 'o1',
89
- status: 'paid',
90
- paid_at: '2026-04-15T10:00:00Z',
91
- currency: 'USD',
92
- },
93
- },
94
- {
95
- quantity: 1,
96
- price_at_purchase: 3000,
97
- products: { id: 'p2', title: 'Physical Tee', product_type: 'physical' },
98
- orders: {
99
- id: 'o2',
100
- status: 'paid',
101
- paid_at: '2026-04-16T10:00:00Z',
102
- currency: 'USD',
103
- },
104
- },
105
- ],
106
- orders: [
107
- { id: 'o1', status: 'paid', created_at: '2026-04-15T10:00:00Z', currency: 'USD' },
108
- { id: 'o2', status: 'paid', created_at: '2026-04-16T10:00:00Z', currency: 'USD' },
109
- ],
110
- });
111
-
112
- const result = await executeFetchEcommerceStats(
113
- {
114
- query: 'Which product generated most revenue?',
115
- reportType: 'revenue',
116
- timeRange: 'all_time',
117
- },
118
- { supabase: supabase as any }
119
- );
120
-
121
- expect(result.success).toBe(true);
122
- expect(result.report.totalOrders).toBe(2);
123
- expect(result.report.paidOrderCount).toBe(2);
124
- expect(result.report.totalRevenue).toBe(130);
125
- expect(result.report.revenueByCurrency).toEqual({ USD: 130 });
126
- expect(result.report.topProducts).toHaveLength(2);
127
- expect(result.report.topProducts[0].title).toBe('Digital Art');
128
- expect(result.report.topProducts[0].revenue).toBe(100);
129
- expect(result.report.topProducts[1].title).toBe('Physical Tee');
130
- expect(result.report.topProducts[1].revenue).toBe(30);
131
- });
132
-
133
- it('counts trial and pending orders directly from order statuses', async () => {
134
- const supabase = createMockSupabase({
135
- order_items: [],
136
- orders: [
137
- { id: 'o1', status: 'trial', created_at: '2026-04-15T10:00:00Z', currency: 'USD' },
138
- { id: 'o2', status: 'Pending', created_at: '2026-04-16T10:00:00Z', currency: 'CAD' },
139
- ],
140
- });
141
-
142
- const trialResult = await executeFetchEcommerceStats(
143
- {
144
- query: 'How many orders are trials?',
145
- reportType: 'orders',
146
- },
147
- { supabase: supabase as any }
148
- );
149
-
150
- expect(trialResult.report.timeRange).toBe('all_time');
151
- expect(trialResult.report.currencyFiltered).toBe(false);
152
- expect(trialResult.report.totalOrders).toBe(2);
153
- expect(trialResult.report.orderStatusCounts.trial).toBe(1);
154
- expect(trialResult.report.orderStatusCounts.pending).toBe(1);
155
- expect(trialResult.report.matchingOrderStatus).toEqual({
156
- allTimeCount: 1,
157
- count: 1,
158
- status: 'trial',
159
- timeRange: 'all_time',
160
- });
161
-
162
- const pendingResult = await executeFetchEcommerceStats(
163
- {
164
- query: 'How many orders are pending?',
165
- reportType: 'orders',
166
- },
167
- { supabase: supabase as any }
168
- );
169
-
170
- expect(pendingResult.report.matchingOrderStatus).toEqual({
171
- allTimeCount: 1,
172
- count: 1,
173
- status: 'pending',
174
- timeRange: 'all_time',
175
- });
176
- });
177
-
178
- it('includes all-time status counts for scoped status questions', async () => {
179
- const supabase = createMockSupabase({
180
- order_items: [],
181
- orders: [
182
- { id: 'o1', status: 'trial', created_at: '2026-04-15T10:00:00Z', currency: 'USD' },
183
- { id: 'o2', status: 'pending', created_at: '2026-05-07T10:00:00Z', currency: 'USD' },
184
- ],
185
- });
186
-
187
- const result = await executeFetchEcommerceStats(
188
- {
189
- query: 'How many trial orders are there in the last 7 days?',
190
- reportType: 'orders',
191
- timeRange: 'last_7_days',
192
- },
193
- { supabase: supabase as any }
194
- );
195
-
196
- expect(result.report.orderStatusCounts.trial).toBe(0);
197
- expect(result.report.allTimeOrderStatusCounts.trial).toBe(1);
198
- expect(result.report.matchingOrderStatus).toEqual({
199
- allTimeCount: 1,
200
- count: 0,
201
- status: 'trial',
202
- timeRange: 'last_7_days',
203
- });
204
- });
205
-
206
- it('handles errors from supabase', async () => {
207
- const supabase = createMockSupabase(
208
- { order_items: [], orders: [] },
209
- { orders: { message: 'Database error' } }
210
- );
211
-
212
- await expect(
213
- executeFetchEcommerceStats(
214
- {
215
- query: 'Show me revenue',
216
- reportType: 'revenue',
217
- timeRange: 'last_30_days',
218
- },
219
- { supabase: supabase as any }
220
- )
221
- ).rejects.toThrow('Failed to fetch ecommerce stats: Database error');
222
- });
223
- });