@nextsparkjs/core 0.1.0-beta.192 → 0.1.0-beta.194
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/README.md +2 -2
- package/dist/components/app/layouts/PublicFooter.js +1 -1
- package/dist/components/app/layouts/PublicNavbar.js +1 -1
- package/dist/components/app/misc/ThemeToggle.d.ts.map +1 -1
- package/dist/components/app/misc/ThemeToggle.js +4 -3
- package/dist/lib/api/auth/permissions.d.ts +10 -0
- package/dist/lib/api/auth/permissions.d.ts.map +1 -1
- package/dist/lib/api/auth/permissions.js +7 -0
- package/dist/lib/api/rate-limit.d.ts.map +1 -1
- package/dist/lib/api/rate-limit.js +3 -0
- package/dist/lib/api/request-origin.d.ts +26 -0
- package/dist/lib/api/request-origin.d.ts.map +1 -0
- package/dist/lib/api/request-origin.js +46 -0
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +8 -12
- package/dist/lib/config/features-types.d.ts +5 -4
- package/dist/lib/config/features-types.d.ts.map +1 -1
- package/dist/lib/entities/external-api-generator.d.ts.map +1 -1
- package/dist/lib/entities/external-api-generator.js +3 -1
- package/dist/lib/selectors/auth-sel.d.ts +2 -7
- package/dist/lib/selectors/auth-sel.d.ts.map +1 -1
- package/dist/lib/selectors/auth-sel.js +1 -3
- package/dist/lib/selectors/by-domain/auth.d.ts +8 -0
- package/dist/lib/selectors/by-domain/auth.d.ts.map +1 -0
- package/dist/lib/selectors/by-domain/auth.js +10 -0
- package/dist/lib/selectors/by-domain/block-editor.d.ts +8 -0
- package/dist/lib/selectors/by-domain/block-editor.d.ts.map +1 -0
- package/dist/lib/selectors/by-domain/block-editor.js +10 -0
- package/dist/lib/selectors/by-domain/common.d.ts +8 -0
- package/dist/lib/selectors/by-domain/common.d.ts.map +1 -0
- package/dist/lib/selectors/by-domain/common.js +10 -0
- package/dist/lib/selectors/by-domain/dashboard.d.ts +8 -0
- package/dist/lib/selectors/by-domain/dashboard.d.ts.map +1 -0
- package/dist/lib/selectors/by-domain/dashboard.js +10 -0
- package/dist/lib/selectors/by-domain/devtools.d.ts +8 -0
- package/dist/lib/selectors/by-domain/devtools.d.ts.map +1 -0
- package/dist/lib/selectors/by-domain/devtools.js +10 -0
- package/dist/lib/selectors/by-domain/entities.d.ts +8 -0
- package/dist/lib/selectors/by-domain/entities.d.ts.map +1 -0
- package/dist/lib/selectors/by-domain/entities.js +10 -0
- package/dist/lib/selectors/by-domain/global-search.d.ts +8 -0
- package/dist/lib/selectors/by-domain/global-search.d.ts.map +1 -0
- package/dist/lib/selectors/by-domain/global-search.js +10 -0
- package/dist/lib/selectors/by-domain/media.d.ts +8 -0
- package/dist/lib/selectors/by-domain/media.d.ts.map +1 -0
- package/dist/lib/selectors/by-domain/media.js +10 -0
- package/dist/lib/selectors/by-domain/patterns.d.ts +8 -0
- package/dist/lib/selectors/by-domain/patterns.d.ts.map +1 -0
- package/dist/lib/selectors/by-domain/patterns.js +10 -0
- package/dist/lib/selectors/by-domain/public.d.ts +8 -0
- package/dist/lib/selectors/by-domain/public.d.ts.map +1 -0
- package/dist/lib/selectors/by-domain/public.js +10 -0
- package/dist/lib/selectors/by-domain/settings.d.ts +8 -0
- package/dist/lib/selectors/by-domain/settings.d.ts.map +1 -0
- package/dist/lib/selectors/by-domain/settings.js +10 -0
- package/dist/lib/selectors/by-domain/superadmin.d.ts +8 -0
- package/dist/lib/selectors/by-domain/superadmin.d.ts.map +1 -0
- package/dist/lib/selectors/by-domain/superadmin.js +10 -0
- package/dist/lib/selectors/by-domain/taxonomies.d.ts +8 -0
- package/dist/lib/selectors/by-domain/taxonomies.d.ts.map +1 -0
- package/dist/lib/selectors/by-domain/taxonomies.js +10 -0
- package/dist/lib/selectors/by-domain/teams.d.ts +8 -0
- package/dist/lib/selectors/by-domain/teams.d.ts.map +1 -0
- package/dist/lib/selectors/by-domain/teams.js +10 -0
- package/dist/lib/selectors/core-selectors.d.ts +1 -0
- package/dist/lib/selectors/core-selectors.d.ts.map +1 -1
- package/dist/lib/selectors/domains/public.selectors.d.ts +1 -0
- package/dist/lib/selectors/domains/public.selectors.d.ts.map +1 -1
- package/dist/lib/selectors/domains/public.selectors.js +3 -1
- package/dist/lib/selectors/selectors.d.ts +2 -0
- package/dist/lib/selectors/selectors.d.ts.map +1 -1
- package/dist/lib/services/subscription.service.d.ts.map +1 -1
- package/dist/lib/services/subscription.service.js +3 -0
- package/dist/lib/theme/ThemeProvider.d.ts.map +1 -1
- package/dist/lib/theme/ThemeProvider.js +7 -5
- package/dist/lib/utils/cors.d.ts +7 -0
- package/dist/lib/utils/cors.d.ts.map +1 -1
- package/dist/lib/utils/cors.js +8 -0
- package/dist/routes/(auth)/accept-invite/[token]/page.js +1 -1
- package/dist/routes/(auth)/forgot-password/page.js +1 -1
- package/dist/routes/(auth)/reset-password/page.js +1 -1
- package/dist/routes/(auth)/signup/page.cc.d.ts +2 -2
- package/dist/routes/(auth)/signup/page.d.ts +1 -1
- package/dist/routes/(auth)/signup/page.d.ts.map +1 -1
- package/dist/routes/(auth)/signup/page.js +1 -5
- package/dist/routes/(auth)/verify-email/page.js +1 -1
- package/dist/routes/(public)/docs/[section]/[page]/page.cc.js +1 -1
- package/dist/routes/(public)/docs/[section]/[page]/page.js +1 -1
- package/dist/routes/(public)/docs/layout.js +1 -1
- package/dist/routes/(public)/docs/page.js +1 -1
- package/dist/routes/_internal/default-public-layout.d.ts +5 -0
- package/dist/routes/_internal/default-public-layout.d.ts.map +1 -1
- package/dist/routes/_internal/default-public-layout.js +1 -2
- package/dist/routes/api/v1/users/[id]/meta/[key]/route.d.ts.map +1 -1
- package/dist/routes/api/v1/users/[id]/meta/[key]/route.js +13 -0
- package/dist/routes/api/v1/users/[id]/route.d.ts.map +1 -1
- package/dist/routes/api/v1/users/[id]/route.js +17 -0
- package/dist/routes/devtools/blocks/[slug]/page.d.ts +4 -1
- package/dist/routes/devtools/blocks/[slug]/page.d.ts.map +1 -1
- package/dist/routes/devtools/blocks/[slug]/page.js +2 -1
- package/dist/templates/features/blog/blocks/post-content/component.tsx +1 -1
- package/dist/templates/features/blog/entities/posts/posts.config.ts +0 -11
- package/dist/templates/features/pages/blocks/hero/component.tsx +1 -1
- package/dist/templates/features/pages/entities/pages/pages.config.ts +0 -11
- package/dist/templates/projects/blog/lib/block-selectors.ts +29 -0
- package/dist/templates/projects/blog/lib/selectors.ts +2 -9
- package/dist/templates/projects/blog/package.json +4 -7
- package/dist/templates/projects/crm/lib/block-selectors.ts +29 -0
- package/dist/templates/projects/crm/lib/selectors.ts +2 -9
- package/dist/templates/projects/crm/package.json +4 -4
- package/dist/templates/projects/crm/templates/dashboard/(main)/layout.tsx +2 -17
- package/dist/templates/projects/crm/templates/shared/CRMSidebarContext.tsx +23 -0
- package/dist/templates/projects/productivity/entities/boards/boards.service.ts +18 -18
- package/dist/templates/projects/productivity/entities/cards/cards.service.ts +18 -18
- package/dist/templates/projects/productivity/entities/lists/lists.service.ts +18 -18
- package/dist/templates/projects/productivity/lib/block-selectors.ts +29 -0
- package/dist/templates/projects/productivity/lib/selectors.ts +2 -9
- package/dist/templates/projects/productivity/package.json +4 -4
- package/dist/templates/projects/starter/lib/block-selectors.ts +28 -0
- package/dist/templates/projects/starter/lib/selectors.ts +2 -11
- package/package.json +12 -5
- package/scripts/build/auth-readiness.mjs +4 -0
- package/scripts/build/registry/__tests__/build-output.test.mjs +1 -1
- package/scripts/build/registry/__tests__/project-mode-root-first.test.mjs +6 -6
- package/scripts/build/registry/__tests__/write-places.test.mjs +1 -1
- package/scripts/build/registry/contracts/__tests__/contracts-wire.test.mjs +1 -1
- package/scripts/build/registry/contracts/__tests__/contracts.test.mjs +1 -1
- package/scripts/build/registry/contracts/render.mjs +3 -3
- package/scripts/build/registry/host/README.md +2 -2
- package/scripts/build/registry/host/__tests__/facade-emitter.test.mjs +9 -9
- package/scripts/build/registry/host/__tests__/host-mode.test.mjs +1 -1
- package/scripts/build/registry/host/__tests__/host-project-composition.test.mjs +1 -1
- package/scripts/build/registry/host/__tests__/host-project.test.mjs +2 -2
- package/scripts/build/registry/host/__tests__/host-robustness.test.mjs +65 -2
- package/scripts/build/registry/host/facade-emitter.mjs +2 -2
- package/scripts/build/registry/host/generation.mjs +54 -0
- package/scripts/build/registry/host/next-route-exports.json +2 -2
- package/scripts/build/registry/host/prepare.mjs +3 -0
- package/scripts/db/migration-time-limit.mjs +216 -34
- package/scripts/db/run-migrations.mjs +11 -179
- package/scripts/db/verify-theme-migrations.mjs +1 -1
- package/templates/features/blog/blocks/post-content/component.tsx +1 -1
- package/templates/features/blog/entities/posts/posts.config.ts +0 -11
- package/templates/features/pages/blocks/hero/component.tsx +1 -1
- package/templates/features/pages/entities/pages/pages.config.ts +0 -11
- package/templates/projects/blog/lib/block-selectors.ts +29 -0
- package/templates/projects/blog/lib/selectors.ts +2 -9
- package/templates/projects/blog/package.json +4 -7
- package/templates/projects/crm/lib/block-selectors.ts +29 -0
- package/templates/projects/crm/lib/selectors.ts +2 -9
- package/templates/projects/crm/package.json +4 -4
- package/templates/projects/crm/templates/dashboard/(main)/layout.tsx +2 -17
- package/templates/projects/crm/templates/shared/CRMSidebarContext.tsx +23 -0
- package/templates/projects/productivity/entities/boards/boards.service.ts +18 -18
- package/templates/projects/productivity/entities/cards/cards.service.ts +18 -18
- package/templates/projects/productivity/entities/lists/lists.service.ts +18 -18
- package/templates/projects/productivity/lib/block-selectors.ts +29 -0
- package/templates/projects/productivity/lib/selectors.ts +2 -9
- package/templates/projects/productivity/package.json +4 -4
- package/templates/projects/starter/lib/block-selectors.ts +28 -0
- package/templates/projects/starter/lib/selectors.ts +2 -11
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Block selectors, and a `sel` bound to them alone.
|
|
3
|
+
*
|
|
4
|
+
* Block components import `sel` from here, not from ./selectors: that file merges CORE_SELECTORS (every domain's
|
|
5
|
+
* map, ~10 kB gzip), and the loader that renders a page imports every block, so a block importing it puts the
|
|
6
|
+
* whole map on each public page. ./selectors re-exports BLOCK_SELECTORS, so Cypress still reaches the same paths.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createSelectorHelpers } from '@nextsparkjs/core/lib/selectors/selector-factory'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Block-specific selectors for the blog theme.
|
|
13
|
+
* Each block has at minimum a 'container' selector.
|
|
14
|
+
* Dynamic selectors use {index} placeholder.
|
|
15
|
+
*/
|
|
16
|
+
export const BLOCK_SELECTORS = {
|
|
17
|
+
// Blocks the pages and blog content features copy into the project (blocks/hero, blocks/post-content)
|
|
18
|
+
hero: {
|
|
19
|
+
container: 'block-hero',
|
|
20
|
+
cta: 'hero-cta',
|
|
21
|
+
},
|
|
22
|
+
postContent: {
|
|
23
|
+
container: 'block-post-content',
|
|
24
|
+
divider: 'post-content-divider',
|
|
25
|
+
cta: 'post-content-cta',
|
|
26
|
+
},
|
|
27
|
+
} as const
|
|
28
|
+
|
|
29
|
+
export const { sel } = createSelectorHelpers({ blocks: BLOCK_SELECTORS })
|
|
@@ -10,20 +10,13 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { createSelectorHelpers, CORE_SELECTORS } from '@nextsparkjs/core/selectors'
|
|
13
|
+
import { BLOCK_SELECTORS } from './block-selectors'
|
|
13
14
|
|
|
14
15
|
// =============================================================================
|
|
15
16
|
// BLOCK SELECTORS
|
|
16
17
|
// =============================================================================
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
* Block-specific selectors for the blog theme.
|
|
20
|
-
* Each block has at minimum a 'container' selector.
|
|
21
|
-
* Dynamic selectors use {index} placeholder.
|
|
22
|
-
*/
|
|
23
|
-
export const BLOCK_SELECTORS = {
|
|
24
|
-
// Blog theme currently has no custom blocks
|
|
25
|
-
// Add block selectors here when blocks are created
|
|
26
|
-
} as const
|
|
19
|
+
export { BLOCK_SELECTORS }
|
|
27
20
|
|
|
28
21
|
// =============================================================================
|
|
29
22
|
// ENTITY SELECTORS
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextsparkjs/theme-blog",
|
|
3
3
|
"version": "0.1.0-beta.192",
|
|
4
|
-
"private":
|
|
4
|
+
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./config/theme.config.ts",
|
|
7
7
|
"requiredPlugins": [],
|
|
@@ -14,17 +14,14 @@
|
|
|
14
14
|
"@nextsparkjs/core": ">=0.1.0-0",
|
|
15
15
|
"@nextsparkjs/testing": ">=0.1.0-0",
|
|
16
16
|
"lucide-react": "^0.539.0",
|
|
17
|
-
"next": "
|
|
17
|
+
"next": "~16.3.6",
|
|
18
18
|
"next-intl": "^4.0.0",
|
|
19
|
-
"react": "^19.
|
|
20
|
-
"react-dom": "^19.
|
|
19
|
+
"react": "^19.2.0",
|
|
20
|
+
"react-dom": "^19.2.0",
|
|
21
21
|
"zod": "^4.0.0"
|
|
22
22
|
},
|
|
23
23
|
"nextspark": {
|
|
24
24
|
"type": "theme",
|
|
25
25
|
"name": "blog"
|
|
26
|
-
},
|
|
27
|
-
"devDependencies": {
|
|
28
|
-
"@types/dompurify": "^3.2.0"
|
|
29
26
|
}
|
|
30
27
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Block selectors, and a `sel` bound to them alone.
|
|
3
|
+
*
|
|
4
|
+
* Block components import `sel` from here, not from ./selectors: that file merges CORE_SELECTORS (every domain's
|
|
5
|
+
* map, ~10 kB gzip), and the loader that renders a page imports every block, so a block importing it puts the
|
|
6
|
+
* whole map on each public page. ./selectors re-exports BLOCK_SELECTORS, so Cypress still reaches the same paths.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createSelectorHelpers } from '@nextsparkjs/core/lib/selectors/selector-factory'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Block-specific selectors for the CRM theme.
|
|
13
|
+
* Each block has at minimum a 'container' selector.
|
|
14
|
+
* Dynamic selectors use {index} placeholder.
|
|
15
|
+
*/
|
|
16
|
+
export const BLOCK_SELECTORS = {
|
|
17
|
+
// Blocks the pages and blog content features copy into the project (blocks/hero, blocks/post-content)
|
|
18
|
+
hero: {
|
|
19
|
+
container: 'block-hero',
|
|
20
|
+
cta: 'hero-cta',
|
|
21
|
+
},
|
|
22
|
+
postContent: {
|
|
23
|
+
container: 'block-post-content',
|
|
24
|
+
divider: 'post-content-divider',
|
|
25
|
+
cta: 'post-content-cta',
|
|
26
|
+
},
|
|
27
|
+
} as const
|
|
28
|
+
|
|
29
|
+
export const { sel } = createSelectorHelpers({ blocks: BLOCK_SELECTORS })
|
|
@@ -10,20 +10,13 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { createSelectorHelpers, CORE_SELECTORS } from '@nextsparkjs/core/selectors'
|
|
13
|
+
import { BLOCK_SELECTORS } from './block-selectors'
|
|
13
14
|
|
|
14
15
|
// =============================================================================
|
|
15
16
|
// BLOCK SELECTORS
|
|
16
17
|
// =============================================================================
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
* Block-specific selectors for the CRM theme.
|
|
20
|
-
* Each block has at minimum a 'container' selector.
|
|
21
|
-
* Dynamic selectors use {index} placeholder.
|
|
22
|
-
*/
|
|
23
|
-
export const BLOCK_SELECTORS = {
|
|
24
|
-
// CRM theme currently has no custom blocks
|
|
25
|
-
// Add block selectors here when blocks are created
|
|
26
|
-
} as const
|
|
19
|
+
export { BLOCK_SELECTORS }
|
|
27
20
|
|
|
28
21
|
// =============================================================================
|
|
29
22
|
// ENTITY SELECTORS
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextsparkjs/theme-crm",
|
|
3
3
|
"version": "0.1.0-beta.192",
|
|
4
|
-
"private":
|
|
4
|
+
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./config/theme.config.ts",
|
|
7
7
|
"requiredPlugins": [],
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
"@nextsparkjs/core": ">=0.1.0-0",
|
|
14
14
|
"@nextsparkjs/testing": ">=0.1.0-0",
|
|
15
15
|
"lucide-react": "^0.539.0",
|
|
16
|
-
"next": "
|
|
16
|
+
"next": "~16.3.6",
|
|
17
17
|
"next-intl": "^4.0.0",
|
|
18
|
-
"react": "^19.
|
|
19
|
-
"react-dom": "^19.
|
|
18
|
+
"react": "^19.2.0",
|
|
19
|
+
"react-dom": "^19.2.0",
|
|
20
20
|
"zod": "^4.0.0"
|
|
21
21
|
},
|
|
22
22
|
"nextspark": {
|
|
@@ -5,28 +5,13 @@
|
|
|
5
5
|
|
|
6
6
|
'use client'
|
|
7
7
|
|
|
8
|
-
import { useState,
|
|
8
|
+
import { useState, ReactNode, useEffect } from 'react'
|
|
9
9
|
import { CRMSidebar } from '@/templates/shared/CRMSidebar'
|
|
10
10
|
import { CRMTopBar } from '@/templates/shared/CRMTopBar'
|
|
11
11
|
import { CRMMobileNav } from '@/templates/shared/CRMMobileNav'
|
|
12
|
+
import { SidebarContext } from '@/templates/shared/CRMSidebarContext'
|
|
12
13
|
import { cn } from '@nextsparkjs/core/lib/utils'
|
|
13
14
|
|
|
14
|
-
// Context for sidebar state
|
|
15
|
-
interface SidebarContextValue {
|
|
16
|
-
expanded: boolean
|
|
17
|
-
setExpanded: (value: boolean) => void
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const SidebarContext = createContext<SidebarContextValue | undefined>(undefined)
|
|
21
|
-
|
|
22
|
-
export function useCRMSidebar() {
|
|
23
|
-
const context = useContext(SidebarContext)
|
|
24
|
-
if (!context) {
|
|
25
|
-
return { expanded: false, setExpanded: () => {} }
|
|
26
|
-
}
|
|
27
|
-
return context
|
|
28
|
-
}
|
|
29
|
-
|
|
30
15
|
interface CRMDashboardLayoutProps {
|
|
31
16
|
children: ReactNode
|
|
32
17
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CRM sidebar state, shared by the dashboard layout (provider) and any component that reads it.
|
|
3
|
+
* Lives outside the layout: Next only allows a layout to export its default component.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use client'
|
|
7
|
+
|
|
8
|
+
import { createContext, useContext } from 'react'
|
|
9
|
+
|
|
10
|
+
export interface SidebarContextValue {
|
|
11
|
+
expanded: boolean
|
|
12
|
+
setExpanded: (value: boolean) => void
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const SidebarContext = createContext<SidebarContextValue | undefined>(undefined)
|
|
16
|
+
|
|
17
|
+
export function useCRMSidebar() {
|
|
18
|
+
const context = useContext(SidebarContext)
|
|
19
|
+
if (!context) {
|
|
20
|
+
return { expanded: false, setExpanded: () => {} }
|
|
21
|
+
}
|
|
22
|
+
return context
|
|
23
|
+
}
|
|
@@ -82,9 +82,9 @@ export class BoardsService {
|
|
|
82
82
|
*/
|
|
83
83
|
static async getById(id: string, userId: string): Promise<Board | null> {
|
|
84
84
|
const result = await queryOneWithRLS<DbBoard>(
|
|
85
|
-
userId,
|
|
86
85
|
`SELECT * FROM boards WHERE id = $1`,
|
|
87
|
-
[id]
|
|
86
|
+
[id],
|
|
87
|
+
userId
|
|
88
88
|
)
|
|
89
89
|
|
|
90
90
|
return result ? mapDbBoard(result) : null
|
|
@@ -121,9 +121,9 @@ export class BoardsService {
|
|
|
121
121
|
|
|
122
122
|
// Get total count
|
|
123
123
|
const countResult = await queryOneWithRLS<{ count: string }>(
|
|
124
|
-
userId,
|
|
125
124
|
`SELECT COUNT(*) as count FROM boards ${whereClause}`,
|
|
126
|
-
params
|
|
125
|
+
params,
|
|
126
|
+
userId
|
|
127
127
|
)
|
|
128
128
|
const total = parseInt(countResult?.count || '0', 10)
|
|
129
129
|
|
|
@@ -135,9 +135,9 @@ export class BoardsService {
|
|
|
135
135
|
|
|
136
136
|
params.push(limit, offset)
|
|
137
137
|
const boards = await queryWithRLS<DbBoard>(
|
|
138
|
-
userId,
|
|
139
138
|
`SELECT * FROM boards ${whereClause} ORDER BY ${validOrderBy} ${validOrderDir} LIMIT $${paramIndex++} OFFSET $${paramIndex++}`,
|
|
140
|
-
params
|
|
139
|
+
params,
|
|
140
|
+
userId
|
|
141
141
|
)
|
|
142
142
|
|
|
143
143
|
return {
|
|
@@ -173,13 +173,13 @@ export class BoardsService {
|
|
|
173
173
|
teamId,
|
|
174
174
|
} = data
|
|
175
175
|
|
|
176
|
-
const result = await mutateWithRLS<DbBoard>(
|
|
177
|
-
userId,
|
|
176
|
+
const result = (await mutateWithRLS<DbBoard>(
|
|
178
177
|
`INSERT INTO boards (name, description, color, is_archived, position, user_id, team_id)
|
|
179
178
|
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
180
179
|
RETURNING *`,
|
|
181
|
-
[name, description, color, isArchived, position, userId, teamId]
|
|
182
|
-
|
|
180
|
+
[name, description, color, isArchived, position, userId, teamId],
|
|
181
|
+
userId
|
|
182
|
+
)).rows[0] ?? null
|
|
183
183
|
|
|
184
184
|
if (!result) {
|
|
185
185
|
throw new Error('Failed to create board')
|
|
@@ -228,11 +228,11 @@ export class BoardsService {
|
|
|
228
228
|
updates.push(`updated_at = NOW()`)
|
|
229
229
|
params.push(id)
|
|
230
230
|
|
|
231
|
-
const result = await mutateWithRLS<DbBoard>(
|
|
232
|
-
userId,
|
|
231
|
+
const result = (await mutateWithRLS<DbBoard>(
|
|
233
232
|
`UPDATE boards SET ${updates.join(', ')} WHERE id = $${paramIndex} RETURNING *`,
|
|
234
|
-
params
|
|
235
|
-
|
|
233
|
+
params,
|
|
234
|
+
userId
|
|
235
|
+
)).rows[0] ?? null
|
|
236
236
|
|
|
237
237
|
if (!result) {
|
|
238
238
|
throw new Error('Board not found or access denied')
|
|
@@ -245,11 +245,11 @@ export class BoardsService {
|
|
|
245
245
|
* Delete a board with RLS
|
|
246
246
|
*/
|
|
247
247
|
static async delete(userId: string, id: string): Promise<boolean> {
|
|
248
|
-
const result = await mutateWithRLS<DbBoard>(
|
|
249
|
-
userId,
|
|
248
|
+
const result = (await mutateWithRLS<DbBoard>(
|
|
250
249
|
`DELETE FROM boards WHERE id = $1 RETURNING *`,
|
|
251
|
-
[id]
|
|
252
|
-
|
|
250
|
+
[id],
|
|
251
|
+
userId
|
|
252
|
+
)).rows[0] ?? null
|
|
253
253
|
|
|
254
254
|
return result !== null
|
|
255
255
|
}
|
|
@@ -105,9 +105,9 @@ export class CardsService {
|
|
|
105
105
|
*/
|
|
106
106
|
static async getById(id: string, userId: string): Promise<Card | null> {
|
|
107
107
|
const result = await queryOneWithRLS<DbCard>(
|
|
108
|
-
userId,
|
|
109
108
|
`SELECT * FROM cards WHERE id = $1`,
|
|
110
|
-
[id]
|
|
109
|
+
[id],
|
|
110
|
+
userId
|
|
111
111
|
)
|
|
112
112
|
|
|
113
113
|
return result ? mapDbCard(result) : null
|
|
@@ -162,9 +162,9 @@ export class CardsService {
|
|
|
162
162
|
|
|
163
163
|
// Get total count
|
|
164
164
|
const countResult = await queryOneWithRLS<{ count: string }>(
|
|
165
|
-
userId,
|
|
166
165
|
`SELECT COUNT(*) as count FROM cards ${whereClause}`,
|
|
167
|
-
params
|
|
166
|
+
params,
|
|
167
|
+
userId
|
|
168
168
|
)
|
|
169
169
|
const total = parseInt(countResult?.count || '0', 10)
|
|
170
170
|
|
|
@@ -176,9 +176,9 @@ export class CardsService {
|
|
|
176
176
|
|
|
177
177
|
params.push(limit, offset)
|
|
178
178
|
const cards = await queryWithRLS<DbCard>(
|
|
179
|
-
userId,
|
|
180
179
|
`SELECT * FROM cards ${whereClause} ORDER BY ${validOrderBy} ${validOrderDir} LIMIT $${paramIndex++} OFFSET $${paramIndex++}`,
|
|
181
|
-
params
|
|
180
|
+
params,
|
|
181
|
+
userId
|
|
182
182
|
)
|
|
183
183
|
|
|
184
184
|
return {
|
|
@@ -218,13 +218,13 @@ export class CardsService {
|
|
|
218
218
|
teamId,
|
|
219
219
|
} = data
|
|
220
220
|
|
|
221
|
-
const result = await mutateWithRLS<DbCard>(
|
|
222
|
-
userId,
|
|
221
|
+
const result = (await mutateWithRLS<DbCard>(
|
|
223
222
|
`INSERT INTO cards (title, description, list_id, board_id, position, due_date, assignee_id, labels, is_archived, user_id, team_id)
|
|
224
223
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
|
225
224
|
RETURNING *`,
|
|
226
|
-
[title, description, listId, boardId, position, dueDate, assigneeId, JSON.stringify(labels), isArchived, userId, teamId]
|
|
227
|
-
|
|
225
|
+
[title, description, listId, boardId, position, dueDate, assigneeId, JSON.stringify(labels), isArchived, userId, teamId],
|
|
226
|
+
userId
|
|
227
|
+
)).rows[0] ?? null
|
|
228
228
|
|
|
229
229
|
if (!result) {
|
|
230
230
|
throw new Error('Failed to create card')
|
|
@@ -293,11 +293,11 @@ export class CardsService {
|
|
|
293
293
|
updates.push(`updated_at = NOW()`)
|
|
294
294
|
params.push(id)
|
|
295
295
|
|
|
296
|
-
const result = await mutateWithRLS<DbCard>(
|
|
297
|
-
userId,
|
|
296
|
+
const result = (await mutateWithRLS<DbCard>(
|
|
298
297
|
`UPDATE cards SET ${updates.join(', ')} WHERE id = $${paramIndex} RETURNING *`,
|
|
299
|
-
params
|
|
300
|
-
|
|
298
|
+
params,
|
|
299
|
+
userId
|
|
300
|
+
)).rows[0] ?? null
|
|
301
301
|
|
|
302
302
|
if (!result) {
|
|
303
303
|
throw new Error('Card not found or access denied')
|
|
@@ -325,11 +325,11 @@ export class CardsService {
|
|
|
325
325
|
* Delete a card with RLS
|
|
326
326
|
*/
|
|
327
327
|
static async delete(userId: string, id: string): Promise<boolean> {
|
|
328
|
-
const result = await mutateWithRLS<DbCard>(
|
|
329
|
-
userId,
|
|
328
|
+
const result = (await mutateWithRLS<DbCard>(
|
|
330
329
|
`DELETE FROM cards WHERE id = $1 RETURNING *`,
|
|
331
|
-
[id]
|
|
332
|
-
|
|
330
|
+
[id],
|
|
331
|
+
userId
|
|
332
|
+
)).rows[0] ?? null
|
|
333
333
|
|
|
334
334
|
return result !== null
|
|
335
335
|
}
|
|
@@ -78,9 +78,9 @@ export class ListsService {
|
|
|
78
78
|
*/
|
|
79
79
|
static async getById(id: string, userId: string): Promise<List | null> {
|
|
80
80
|
const result = await queryOneWithRLS<DbList>(
|
|
81
|
-
userId,
|
|
82
81
|
`SELECT * FROM lists WHERE id = $1`,
|
|
83
|
-
[id]
|
|
82
|
+
[id],
|
|
83
|
+
userId
|
|
84
84
|
)
|
|
85
85
|
|
|
86
86
|
return result ? mapDbList(result) : null
|
|
@@ -123,9 +123,9 @@ export class ListsService {
|
|
|
123
123
|
|
|
124
124
|
// Get total count
|
|
125
125
|
const countResult = await queryOneWithRLS<{ count: string }>(
|
|
126
|
-
userId,
|
|
127
126
|
`SELECT COUNT(*) as count FROM lists ${whereClause}`,
|
|
128
|
-
params
|
|
127
|
+
params,
|
|
128
|
+
userId
|
|
129
129
|
)
|
|
130
130
|
const total = parseInt(countResult?.count || '0', 10)
|
|
131
131
|
|
|
@@ -137,9 +137,9 @@ export class ListsService {
|
|
|
137
137
|
|
|
138
138
|
params.push(limit, offset)
|
|
139
139
|
const lists = await queryWithRLS<DbList>(
|
|
140
|
-
userId,
|
|
141
140
|
`SELECT * FROM lists ${whereClause} ORDER BY ${validOrderBy} ${validOrderDir} LIMIT $${paramIndex++} OFFSET $${paramIndex++}`,
|
|
142
|
-
params
|
|
141
|
+
params,
|
|
142
|
+
userId
|
|
143
143
|
)
|
|
144
144
|
|
|
145
145
|
return {
|
|
@@ -174,13 +174,13 @@ export class ListsService {
|
|
|
174
174
|
teamId,
|
|
175
175
|
} = data
|
|
176
176
|
|
|
177
|
-
const result = await mutateWithRLS<DbList>(
|
|
178
|
-
userId,
|
|
177
|
+
const result = (await mutateWithRLS<DbList>(
|
|
179
178
|
`INSERT INTO lists (name, board_id, position, is_archived, user_id, team_id)
|
|
180
179
|
VALUES ($1, $2, $3, $4, $5, $6)
|
|
181
180
|
RETURNING *`,
|
|
182
|
-
[name, boardId, position, isArchived, userId, teamId]
|
|
183
|
-
|
|
181
|
+
[name, boardId, position, isArchived, userId, teamId],
|
|
182
|
+
userId
|
|
183
|
+
)).rows[0] ?? null
|
|
184
184
|
|
|
185
185
|
if (!result) {
|
|
186
186
|
throw new Error('Failed to create list')
|
|
@@ -224,11 +224,11 @@ export class ListsService {
|
|
|
224
224
|
updates.push(`updated_at = NOW()`)
|
|
225
225
|
params.push(id)
|
|
226
226
|
|
|
227
|
-
const result = await mutateWithRLS<DbList>(
|
|
228
|
-
userId,
|
|
227
|
+
const result = (await mutateWithRLS<DbList>(
|
|
229
228
|
`UPDATE lists SET ${updates.join(', ')} WHERE id = $${paramIndex} RETURNING *`,
|
|
230
|
-
params
|
|
231
|
-
|
|
229
|
+
params,
|
|
230
|
+
userId
|
|
231
|
+
)).rows[0] ?? null
|
|
232
232
|
|
|
233
233
|
if (!result) {
|
|
234
234
|
throw new Error('List not found or access denied')
|
|
@@ -241,11 +241,11 @@ export class ListsService {
|
|
|
241
241
|
* Delete a list with RLS
|
|
242
242
|
*/
|
|
243
243
|
static async delete(userId: string, id: string): Promise<boolean> {
|
|
244
|
-
const result = await mutateWithRLS<DbList>(
|
|
245
|
-
userId,
|
|
244
|
+
const result = (await mutateWithRLS<DbList>(
|
|
246
245
|
`DELETE FROM lists WHERE id = $1 RETURNING *`,
|
|
247
|
-
[id]
|
|
248
|
-
|
|
246
|
+
[id],
|
|
247
|
+
userId
|
|
248
|
+
)).rows[0] ?? null
|
|
249
249
|
|
|
250
250
|
return result !== null
|
|
251
251
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Block selectors, and a `sel` bound to them alone.
|
|
3
|
+
*
|
|
4
|
+
* Block components import `sel` from here, not from ./selectors: that file merges CORE_SELECTORS (every domain's
|
|
5
|
+
* map, ~10 kB gzip), and the loader that renders a page imports every block, so a block importing it puts the
|
|
6
|
+
* whole map on each public page. ./selectors re-exports BLOCK_SELECTORS, so Cypress still reaches the same paths.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createSelectorHelpers } from '@nextsparkjs/core/lib/selectors/selector-factory'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Block-specific selectors for the productivity theme.
|
|
13
|
+
* Each block has at minimum a 'container' selector.
|
|
14
|
+
* Dynamic selectors use {index} placeholder.
|
|
15
|
+
*/
|
|
16
|
+
export const BLOCK_SELECTORS = {
|
|
17
|
+
// Blocks the pages and blog content features copy into the project (blocks/hero, blocks/post-content)
|
|
18
|
+
hero: {
|
|
19
|
+
container: 'block-hero',
|
|
20
|
+
cta: 'hero-cta',
|
|
21
|
+
},
|
|
22
|
+
postContent: {
|
|
23
|
+
container: 'block-post-content',
|
|
24
|
+
divider: 'post-content-divider',
|
|
25
|
+
cta: 'post-content-cta',
|
|
26
|
+
},
|
|
27
|
+
} as const
|
|
28
|
+
|
|
29
|
+
export const { sel } = createSelectorHelpers({ blocks: BLOCK_SELECTORS })
|
|
@@ -10,20 +10,13 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { createSelectorHelpers, CORE_SELECTORS } from '@nextsparkjs/core/selectors'
|
|
13
|
+
import { BLOCK_SELECTORS } from './block-selectors'
|
|
13
14
|
|
|
14
15
|
// =============================================================================
|
|
15
16
|
// BLOCK SELECTORS
|
|
16
17
|
// =============================================================================
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
* Block-specific selectors for the productivity theme.
|
|
20
|
-
* Each block has at minimum a 'container' selector.
|
|
21
|
-
* Dynamic selectors use {index} placeholder.
|
|
22
|
-
*/
|
|
23
|
-
export const BLOCK_SELECTORS = {
|
|
24
|
-
// Productivity theme currently has no custom blocks
|
|
25
|
-
// Add block selectors here when blocks are created
|
|
26
|
-
} as const
|
|
19
|
+
export { BLOCK_SELECTORS }
|
|
27
20
|
|
|
28
21
|
// =============================================================================
|
|
29
22
|
// ENTITY SELECTORS
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextsparkjs/theme-productivity",
|
|
3
3
|
"version": "0.1.0-beta.192",
|
|
4
|
-
"private":
|
|
4
|
+
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./config/theme.config.ts",
|
|
7
7
|
"requiredPlugins": [],
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
"@nextsparkjs/core": ">=0.1.0-0",
|
|
18
18
|
"@nextsparkjs/testing": ">=0.1.0-0",
|
|
19
19
|
"lucide-react": "^0.539.0",
|
|
20
|
-
"next": "
|
|
21
|
-
"react": "^19.
|
|
22
|
-
"react-dom": "^19.
|
|
20
|
+
"next": "~16.3.6",
|
|
21
|
+
"react": "^19.2.0",
|
|
22
|
+
"react-dom": "^19.2.0",
|
|
23
23
|
"zod": "^4.0.0"
|
|
24
24
|
},
|
|
25
25
|
"nextspark": {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Block selectors, and a `sel` bound to them alone.
|
|
3
|
+
*
|
|
4
|
+
* Block components import `sel` from here, not from ./selectors: that file merges CORE_SELECTORS (every domain's
|
|
5
|
+
* map, ~10 kB gzip), and the loader that renders a page imports every block, so a block importing it puts the
|
|
6
|
+
* whole map on each public page. ./selectors re-exports BLOCK_SELECTORS, so Cypress still reaches the same paths.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createSelectorHelpers } from '@nextsparkjs/core/lib/selectors/selector-factory'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Block-specific selectors for the starter theme.
|
|
13
|
+
* Each block has at minimum a 'container' selector.
|
|
14
|
+
* Dynamic selectors use {index} placeholder.
|
|
15
|
+
*/
|
|
16
|
+
export const BLOCK_SELECTORS = {
|
|
17
|
+
hero: {
|
|
18
|
+
container: 'block-hero',
|
|
19
|
+
cta: 'hero-cta',
|
|
20
|
+
},
|
|
21
|
+
postContent: {
|
|
22
|
+
container: 'block-post-content',
|
|
23
|
+
divider: 'post-content-divider',
|
|
24
|
+
cta: 'post-content-cta',
|
|
25
|
+
},
|
|
26
|
+
} as const
|
|
27
|
+
|
|
28
|
+
export const { sel } = createSelectorHelpers({ blocks: BLOCK_SELECTORS })
|
|
@@ -10,22 +10,13 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { createSelectorHelpers, CORE_SELECTORS } from '@nextsparkjs/core/selectors'
|
|
13
|
+
import { BLOCK_SELECTORS } from './block-selectors'
|
|
13
14
|
|
|
14
15
|
// =============================================================================
|
|
15
16
|
// BLOCK SELECTORS
|
|
16
17
|
// =============================================================================
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
* Block-specific selectors for the starter theme.
|
|
20
|
-
* Each block has at minimum a 'container' selector.
|
|
21
|
-
* Dynamic selectors use {index} placeholder.
|
|
22
|
-
*/
|
|
23
|
-
export const BLOCK_SELECTORS = {
|
|
24
|
-
hero: {
|
|
25
|
-
container: 'block-hero',
|
|
26
|
-
cta: 'hero-cta',
|
|
27
|
-
},
|
|
28
|
-
} as const
|
|
19
|
+
export { BLOCK_SELECTORS }
|
|
29
20
|
|
|
30
21
|
// =============================================================================
|
|
31
22
|
// THEME SELECTORS (CORE + BLOCKS)
|