@falcondev-oss/nuxt-layers-base 0.1.0 → 0.2.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 (165) hide show
  1. package/LICENSE +21 -0
  2. package/app/assets/css/utilities.css +3 -0
  3. package/app/components/Define.vue +13 -0
  4. package/app/components/layout/LayoutDashboard.vue +1 -1
  5. package/app/components/u/UField.vue +17 -6
  6. package/app/components/u/UForm.vue +90 -0
  7. package/app/components/u/UInputDurationMinutes.vue +1 -1
  8. package/app/composables/useTableColumns.tsx +1 -1
  9. package/app/composables/useToast.ts +3 -3
  10. package/app/utils/debug.ts +48 -0
  11. package/app/utils/files.ts +22 -0
  12. package/app/utils/plugins.ts +45 -6
  13. package/package.json +19 -3
  14. package/server/plugins/error.ts +20 -0
  15. package/server/utils/error.ts +24 -0
  16. package/shared/types/helpers.ts +27 -0
  17. package/shared/utils/helpers.ts +3 -0
  18. package/.nuxt/app.config.mjs +0 -317
  19. package/.nuxt/components.d.ts +0 -332
  20. package/.nuxt/imports.d.ts +0 -61
  21. package/.nuxt/manifest/meta/24fb5e89-93fb-44cb-bbff-2a13f165c1e8.json +0 -1
  22. package/.nuxt/nuxt-icon-client-bundle.mjs +0 -1
  23. package/.nuxt/nuxt-icon-server-bundle.mjs +0 -14
  24. package/.nuxt/nuxt.d.ts +0 -24
  25. package/.nuxt/nuxt.node.d.ts +0 -14
  26. package/.nuxt/nuxt.shared.d.ts +0 -5
  27. package/.nuxt/schema/nuxt.schema.d.ts +0 -210
  28. package/.nuxt/schema/nuxt.schema.json +0 -263
  29. package/.nuxt/tsconfig.app.json +0 -217
  30. package/.nuxt/tsconfig.json +0 -219
  31. package/.nuxt/tsconfig.node.json +0 -114
  32. package/.nuxt/tsconfig.server.json +0 -140
  33. package/.nuxt/tsconfig.shared.json +0 -139
  34. package/.nuxt/types/app.config.d.ts +0 -331
  35. package/.nuxt/types/build.d.ts +0 -24
  36. package/.nuxt/types/builder-env.d.ts +0 -1
  37. package/.nuxt/types/components.d.ts +0 -337
  38. package/.nuxt/types/imports.d.ts +0 -906
  39. package/.nuxt/types/layouts.d.ts +0 -7
  40. package/.nuxt/types/middleware.d.ts +0 -7
  41. package/.nuxt/types/modules.d.ts +0 -159
  42. package/.nuxt/types/nitro-config.d.ts +0 -14
  43. package/.nuxt/types/nitro-imports.d.ts +0 -141
  44. package/.nuxt/types/nitro-middleware.d.ts +0 -11
  45. package/.nuxt/types/nitro-nuxt.d.ts +0 -61
  46. package/.nuxt/types/nitro-routes.d.ts +0 -17
  47. package/.nuxt/types/nitro.d.ts +0 -3
  48. package/.nuxt/types/plugins.d.ts +0 -35
  49. package/.nuxt/types/runtime-config.d.ts +0 -36
  50. package/.nuxt/types/ui.d.ts +0 -36
  51. package/.nuxt/types/vue-shim.d.ts +0 -0
  52. package/.nuxt/ui/accordion.ts +0 -20
  53. package/.nuxt/ui/alert.ts +0 -264
  54. package/.nuxt/ui/auth-form.ts +0 -20
  55. package/.nuxt/ui/avatar-group.ts +0 -52
  56. package/.nuxt/ui/avatar.ts +0 -54
  57. package/.nuxt/ui/badge.ts +0 -263
  58. package/.nuxt/ui/banner.ts +0 -108
  59. package/.nuxt/ui/blog-post.ts +0 -143
  60. package/.nuxt/ui/blog-posts.ts +0 -9
  61. package/.nuxt/ui/breadcrumb.ts +0 -45
  62. package/.nuxt/ui/button.ts +0 -378
  63. package/.nuxt/ui/calendar.ts +0 -315
  64. package/.nuxt/ui/card.ts +0 -34
  65. package/.nuxt/ui/carousel.ts +0 -38
  66. package/.nuxt/ui/changelog-version.ts +0 -45
  67. package/.nuxt/ui/changelog-versions.ts +0 -8
  68. package/.nuxt/ui/chat-message.ts +0 -136
  69. package/.nuxt/ui/chat-messages.ts +0 -14
  70. package/.nuxt/ui/chat-palette.ts +0 -8
  71. package/.nuxt/ui/chat-prompt-submit.ts +0 -5
  72. package/.nuxt/ui/chat-prompt.ts +0 -35
  73. package/.nuxt/ui/checkbox-group.ts +0 -207
  74. package/.nuxt/ui/checkbox.ts +0 -237
  75. package/.nuxt/ui/chip.ts +0 -96
  76. package/.nuxt/ui/collapsible.ts +0 -6
  77. package/.nuxt/ui/color-picker.ts +0 -47
  78. package/.nuxt/ui/command-palette.ts +0 -62
  79. package/.nuxt/ui/container.ts +0 -3
  80. package/.nuxt/ui/context-menu.ts +0 -219
  81. package/.nuxt/ui/dashboard-group.ts +0 -3
  82. package/.nuxt/ui/dashboard-navbar.ts +0 -21
  83. package/.nuxt/ui/dashboard-panel.ts +0 -17
  84. package/.nuxt/ui/dashboard-resize-handle.ts +0 -3
  85. package/.nuxt/ui/dashboard-search-button.ts +0 -15
  86. package/.nuxt/ui/dashboard-search.ts +0 -13
  87. package/.nuxt/ui/dashboard-sidebar-collapse.ts +0 -9
  88. package/.nuxt/ui/dashboard-sidebar-toggle.ts +0 -9
  89. package/.nuxt/ui/dashboard-sidebar.ts +0 -37
  90. package/.nuxt/ui/dashboard-toolbar.ts +0 -7
  91. package/.nuxt/ui/drawer.ts +0 -149
  92. package/.nuxt/ui/dropdown-menu.ts +0 -220
  93. package/.nuxt/ui/editor-drag-handle.ts +0 -6
  94. package/.nuxt/ui/editor-emoji-menu.ts +0 -35
  95. package/.nuxt/ui/editor-mention-menu.ts +0 -35
  96. package/.nuxt/ui/editor-suggestion-menu.ts +0 -35
  97. package/.nuxt/ui/editor-toolbar.ts +0 -21
  98. package/.nuxt/ui/editor.ts +0 -35
  99. package/.nuxt/ui/empty.ts +0 -83
  100. package/.nuxt/ui/error.ts +0 -9
  101. package/.nuxt/ui/field-group.ts +0 -16
  102. package/.nuxt/ui/file-upload.ts +0 -290
  103. package/.nuxt/ui/footer-columns.ts +0 -28
  104. package/.nuxt/ui/footer.ts +0 -11
  105. package/.nuxt/ui/form-field.ts +0 -62
  106. package/.nuxt/ui/form.ts +0 -3
  107. package/.nuxt/ui/header.ts +0 -25
  108. package/.nuxt/ui/index.ts +0 -109
  109. package/.nuxt/ui/input-date.ts +0 -337
  110. package/.nuxt/ui/input-menu.ts +0 -460
  111. package/.nuxt/ui/input-number.ts +0 -256
  112. package/.nuxt/ui/input-tags.ts +0 -310
  113. package/.nuxt/ui/input-time.ts +0 -336
  114. package/.nuxt/ui/input.ts +0 -289
  115. package/.nuxt/ui/kbd.ts +0 -195
  116. package/.nuxt/ui/link.ts +0 -22
  117. package/.nuxt/ui/main.ts +0 -3
  118. package/.nuxt/ui/marquee.ts +0 -66
  119. package/.nuxt/ui/modal.ts +0 -60
  120. package/.nuxt/ui/navigation-menu.ts +0 -512
  121. package/.nuxt/ui/page-anchors.ts +0 -30
  122. package/.nuxt/ui/page-aside.ts +0 -10
  123. package/.nuxt/ui/page-body.ts +0 -3
  124. package/.nuxt/ui/page-card.ts +0 -274
  125. package/.nuxt/ui/page-columns.ts +0 -3
  126. package/.nuxt/ui/page-cta.ts +0 -70
  127. package/.nuxt/ui/page-feature.ts +0 -34
  128. package/.nuxt/ui/page-grid.ts +0 -3
  129. package/.nuxt/ui/page-header.ts +0 -18
  130. package/.nuxt/ui/page-hero.ts +0 -44
  131. package/.nuxt/ui/page-links.ts +0 -25
  132. package/.nuxt/ui/page-list.ts +0 -8
  133. package/.nuxt/ui/page-logos.ts +0 -15
  134. package/.nuxt/ui/page-section.ts +0 -84
  135. package/.nuxt/ui/page.ts +0 -32
  136. package/.nuxt/ui/pagination.ts +0 -13
  137. package/.nuxt/ui/pin-input.ts +0 -171
  138. package/.nuxt/ui/popover.ts +0 -6
  139. package/.nuxt/ui/pricing-plan.ts +0 -101
  140. package/.nuxt/ui/pricing-plans.ts +0 -22
  141. package/.nuxt/ui/pricing-table.ts +0 -51
  142. package/.nuxt/ui/progress.ts +0 -297
  143. package/.nuxt/ui/radio-group.ts +0 -352
  144. package/.nuxt/ui/scroll-area.ts +0 -21
  145. package/.nuxt/ui/select-menu.ts +0 -361
  146. package/.nuxt/ui/select.ts +0 -348
  147. package/.nuxt/ui/separator.ts +0 -172
  148. package/.nuxt/ui/skeleton.ts +0 -3
  149. package/.nuxt/ui/slideover.ts +0 -132
  150. package/.nuxt/ui/slider.ts +0 -171
  151. package/.nuxt/ui/stepper.ts +0 -202
  152. package/.nuxt/ui/switch.ts +0 -132
  153. package/.nuxt/ui/table.ts +0 -162
  154. package/.nuxt/ui/tabs.ts +0 -258
  155. package/.nuxt/ui/textarea.ts +0 -294
  156. package/.nuxt/ui/timeline.ts +0 -321
  157. package/.nuxt/ui/toast.ts +0 -74
  158. package/.nuxt/ui/toaster.ts +0 -91
  159. package/.nuxt/ui/tooltip.ts +0 -9
  160. package/.nuxt/ui/tree.ts +0 -168
  161. package/.nuxt/ui/user.ts +0 -101
  162. package/.nuxt/ui-image-component.ts +0 -1
  163. package/.nuxt/ui.css +0 -154
  164. package/app/components/Var.vue +0 -13
  165. package/pnpm-workspace.yaml +0 -5
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 falconDev OSS
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ @utility z-full {
2
+ z-index: 2147483647;
3
+ }
@@ -0,0 +1,13 @@
1
+ <script setup lang="ts" generic="T extends object">
2
+ defineProps<{
3
+ value: T
4
+ }>()
5
+
6
+ defineSlots<{
7
+ default: (props: T) => any
8
+ }>()
9
+ </script>
10
+
11
+ <template>
12
+ <slot v-bind="value" />
13
+ </template>
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import type { ButtonProps, NavigationMenuItem } from '@nuxt/ui'
2
+ import type { NavigationMenuItem } from '@nuxt/ui'
3
3
 
4
4
  defineProps<{
5
5
  sidebar?: {
@@ -1,8 +1,9 @@
1
1
  <script setup lang="ts" generic="T">
2
2
  import type { FormField } from '@falcondev-oss/form-core'
3
- import type { FormFieldProps } from '@nuxt/ui'
3
+ import type { FormFieldProps, FormFieldSlots } from '@nuxt/ui'
4
4
  import type { ModelModifiers } from '@nuxt/ui/runtime/types/input.js'
5
5
  import { useForwardProps } from 'reka-ui'
6
+ import { omit } from 'remeda'
6
7
 
7
8
  type FieldSlotProps<T> = {
8
9
  'modelValue': T
@@ -18,15 +19,16 @@ const props = defineProps<
18
19
  field: FormField<T>
19
20
  }
20
21
  >()
21
- defineSlots<{
22
- default: (props: Omit<FieldSlotProps<T>, 'modelModifiers'>) => any
23
- }>()
22
+ const slots = defineSlots<
23
+ {
24
+ default: (props: Omit<FieldSlotProps<T>, 'modelModifiers'>) => any
25
+ } & Omit<FormFieldSlots, 'default'>
26
+ >()
24
27
 
25
28
  const forwardedProps = useForwardProps(props)
26
29
 
27
30
  const formFieldProps = computed(() => {
28
31
  const { field, ...rest } = forwardedProps.value
29
-
30
32
  return rest
31
33
  })
32
34
 
@@ -50,6 +52,15 @@ const slotProps = computed(
50
52
  v-bind="formFieldProps"
51
53
  :error="forwardedProps.field.errors && forwardedProps.field.errors.join('\n')"
52
54
  >
53
- <slot v-bind="slotProps" />
55
+ <slot v-bind="slotProps">
56
+ <DevOnly>
57
+ <p class="font-black text-red-500">UField missing slot</p>
58
+ </DevOnly>
59
+ </slot>
60
+
61
+ <template v-for="(_, name) in omit(slots, ['default'])" #[name]="slotData">
62
+ <!-- @vue-ignore -->
63
+ <slot :name="name" v-bind="slotData || {}" />
64
+ </template>
54
65
  </UFormField>
55
66
  </template>
@@ -0,0 +1,90 @@
1
+ <script setup lang="ts">
2
+ import type { Toast } from '#ui/composables'
3
+ import type { FormHandle } from '@falcondev-oss/form-core'
4
+ import type { ButtonProps } from '@nuxt/ui'
5
+
6
+ const props = withDefaults(
7
+ defineProps<{
8
+ submitLabel?: string
9
+ submitButtonProps?: ButtonProps
10
+ actions?: ButtonProps[]
11
+ form: FormHandle
12
+ disableSubmitIfUnchanged?: boolean
13
+ successToast?: Partial<Toast>
14
+ preventPageLeave?: boolean
15
+ }>(),
16
+ {
17
+ disableSubmitIfUnchanged: true,
18
+ preventPageLeave: true,
19
+ },
20
+ )
21
+
22
+ defineSlots<{
23
+ default: any
24
+ }>()
25
+
26
+ usePreventPageLeave(() => props.preventPageLeave && props.form.isChanged && !props.form.isLoading)
27
+
28
+ const toast = useToast()
29
+ let unhook: (() => void) | null = null
30
+ watch(
31
+ () => props.form,
32
+ (form) => {
33
+ unhook?.()
34
+ unhook = form.hooks.addHooks({
35
+ afterSubmit(result) {
36
+ if (!result.success || !props.successToast) return
37
+
38
+ toast.add({
39
+ preset: 'success',
40
+ ...props.successToast,
41
+ })
42
+ },
43
+ })
44
+ },
45
+ {
46
+ immediate: true,
47
+ },
48
+ )
49
+
50
+ const actionsWithSubmit = computed(() => {
51
+ const submit = {
52
+ ...props.submitButtonProps,
53
+ variant: 'solid',
54
+ label: props.submitButtonProps?.label ?? props.submitLabel ?? 'Submit',
55
+ disabled: props.disableSubmitIfUnchanged
56
+ ? !props.form.isChanged || props.form.isLoading
57
+ : props.form.isLoading,
58
+ loading: props.form.isLoading,
59
+ onClick: async () => {
60
+ await props.form.submit()
61
+ },
62
+ } satisfies ButtonProps
63
+ if (!props.actions) return [submit]
64
+
65
+ return [...props.actions, submit]
66
+ })
67
+
68
+ const rootErrors = computed(() => props.form.errors?.filter((error) => error.path?.length === 0))
69
+ </script>
70
+
71
+ <template>
72
+ <form class="w-full" @submit.prevent="() => form.submit()">
73
+ <slot />
74
+ <div class="col-span-full flex w-full flex-col gap-4">
75
+ <ul v-if="rootErrors?.length" class="text-error text-sm">
76
+ <li v-for="error of rootErrors" :key="`${error.path}:${error.message}`">
77
+ {{ error.path }}:{{ error.message }}
78
+ </li>
79
+ </ul>
80
+ <div class="flex items-center justify-end gap-4">
81
+ <UActions
82
+ :defaults="{
83
+ variant: 'subtle',
84
+ }"
85
+ :actions="actionsWithSubmit"
86
+ />
87
+ </div>
88
+ </div>
89
+ </form>
90
+ </template>
@@ -83,6 +83,6 @@ const maskOptions: MaskOptions = {
83
83
  lazy: true,
84
84
  }"
85
85
  placeholder="HH:mm"
86
- trailing-icon="ph:timer"
86
+ trailing-icon="lucide:timer"
87
87
  />
88
88
  </template>
@@ -46,7 +46,7 @@ export function useTableColumns<T extends MaybeRef<Record<string, any>[] | undef
46
46
  ]
47
47
  if (actions.onDelete)
48
48
  rowActions.push({
49
- icon: 'ph:trash',
49
+ icon: 'lucide:trash',
50
50
  color: 'error',
51
51
  loadingAuto: true,
52
52
  onClick: async () => {
@@ -4,15 +4,15 @@ import { useToast as useNuxtUiToast } from '#ui/composables'
4
4
  const presets = {
5
5
  success: {
6
6
  color: 'success',
7
- icon: 'ph:check-circle',
7
+ icon: 'lucide:circle-check',
8
8
  },
9
9
  error: {
10
10
  color: 'error',
11
- icon: 'ph:x-circle',
11
+ icon: 'lucide:circle-x',
12
12
  },
13
13
  warning: {
14
14
  color: 'warning',
15
- icon: 'ph:warning-circle',
15
+ icon: 'lucide:circle-alert',
16
16
  },
17
17
  } as const satisfies Record<string, Partial<Toast>>
18
18
 
@@ -0,0 +1,48 @@
1
+ function mulberry32(seed: number) {
2
+ return function () {
3
+ let t = (seed += 0x6d_2b_79_f5)
4
+ t = Math.imul(t ^ (t >>> 15), t | 1)
5
+ t ^= t + Math.imul(t ^ (t >>> 7), t | 61)
6
+ return ((t ^ (t >>> 14)) >>> 0) / 4_294_967_296
7
+ }
8
+ }
9
+
10
+ export function debug(label: string, ...ref: MaybeRefOrGetter<unknown>[]) {
11
+ let error: Error | undefined
12
+ try {
13
+ // eslint-disable-next-line unicorn/error-message
14
+ throw new Error()
15
+ } catch (err: unknown) {
16
+ if (!(err instanceof Error)) return
17
+ err.name = 'LookAtThisCallstackError'
18
+ err.stack = err.stack
19
+ ?.split('\n')
20
+ .filter((_, i) => [0, 2].includes(i))
21
+ .join('\n')
22
+ error = err
23
+ }
24
+
25
+ const random = mulberry32([...label].reduce((acc, c) => acc + c.codePointAt(0)!, 0))()
26
+
27
+ watch(
28
+ () => ref.map(toValue),
29
+ (value) => {
30
+ // eslint-disable-next-line no-console
31
+ console.groupCollapsed(
32
+ `%c ${label} `,
33
+ `font-weight: normal !important; background: hsl(${Math.floor(
34
+ random * 360,
35
+ )}, 70%, 70%); color: #111;`,
36
+ ...value,
37
+ )
38
+ console.debug(error)
39
+ // eslint-disable-next-line no-console
40
+ console.groupEnd()
41
+ },
42
+ {
43
+ immediate: true,
44
+ flush: 'sync',
45
+ deep: true,
46
+ },
47
+ )
48
+ }
@@ -0,0 +1,22 @@
1
+ export function downloadStringAsFile({
2
+ content,
3
+ fileName,
4
+ contentType,
5
+ }: {
6
+ content: string | BlobPart
7
+ fileName: string
8
+ contentType: string
9
+ }) {
10
+ const blob = new Blob([content], { type: `${contentType};charset=utf-8` })
11
+ const url = URL.createObjectURL(blob)
12
+
13
+ const a = document.createElement('a')
14
+ a.href = url
15
+ a.download = fileName
16
+ document.body.append(a)
17
+
18
+ a.click()
19
+ a.remove()
20
+
21
+ URL.revokeObjectURL(url)
22
+ }
@@ -5,27 +5,69 @@ import { createTRPCVueQueryClient } from '@falcondev-oss/trpc-vue-query'
5
5
  import {
6
6
  dehydrate,
7
7
  hydrate,
8
+ MutationCache,
8
9
  QueryClient,
9
10
  useQueryClient,
10
11
  VueQueryPlugin,
11
12
  } from '@tanstack/vue-query'
12
- import { httpSubscriptionLink, splitLink } from '@trpc/client'
13
+ import { httpSubscriptionLink, isTRPCClientError, splitLink, TRPCClientError } from '@trpc/client'
13
14
  import defu from 'defu'
14
15
  import { useState } from 'nuxt/app'
15
16
  import superjson from 'superjson'
16
17
  import { httpBatchLink, httpLink } from 'trpc-nuxt/client'
17
18
 
18
19
  interface VueQueryNuxtPluginOptions {
19
- queryClientOptions: QueryClientConfig
20
+ queryClientOptions?: QueryClientConfig
20
21
  vuePluginOptions?: VueQueryPluginOptions
21
22
  }
22
23
  export function vueQueryPlugin(opts?: VueQueryNuxtPluginOptions) {
23
24
  return {
24
25
  name: 'vue-query',
25
26
  setup(nuxt) {
27
+ const toast = useToast()
26
28
  const vueQueryState = useState<DehydratedState | null>('vue-query')
27
29
 
28
- const queryClient = new QueryClient(defu(opts?.queryClientOptions, {}))
30
+ const queryClient = new QueryClient(
31
+ defu<QueryClientConfig, QueryClientConfig[]>(opts?.queryClientOptions, {
32
+ defaultOptions: {
33
+ queries: {
34
+ experimental_prefetchInRender: true,
35
+ retry(failureCount, error) {
36
+ if (
37
+ isTRPCClientError<AnyTRPCRouter>(error) &&
38
+ error.data &&
39
+ // eslint-disable-next-line ts/no-unsafe-member-access
40
+ error.data.httpStatus >= 400 &&
41
+ // eslint-disable-next-line ts/no-unsafe-member-access
42
+ error.data.httpStatus < 500
43
+ )
44
+ return false
45
+ return failureCount < 3
46
+ },
47
+ },
48
+ },
49
+ mutationCache: new MutationCache({
50
+ onError(err) {
51
+ console.error(err)
52
+
53
+ if (err instanceof TRPCClientError) {
54
+ toast.add({
55
+ preset: 'error',
56
+ title: 'Request Error',
57
+ description: err.message,
58
+ duration: 5000,
59
+ })
60
+ }
61
+
62
+ toast.add({
63
+ preset: 'error',
64
+ title: 'An unknown error occurred',
65
+ duration: 5000,
66
+ })
67
+ },
68
+ }),
69
+ }),
70
+ )
29
71
  const options: VueQueryPluginOptions = { queryClient, ...opts?.vuePluginOptions }
30
72
 
31
73
  nuxt.vueApp.use(VueQueryPlugin, options)
@@ -55,7 +97,6 @@ export function trpcPlugin<Router extends AnyTRPCRouter>(opts: TrpcNuxtPluginOpt
55
97
  dependsOn: ['vue-query'] as any,
56
98
  setup() {
57
99
  const queryClient = useQueryClient()
58
- const headers = useRequestHeaders()
59
100
 
60
101
  const trpc = createTRPCVueQueryClient<Router>({
61
102
  queryClient,
@@ -72,13 +113,11 @@ export function trpcPlugin<Router extends AnyTRPCRouter>(opts: TrpcNuxtPluginOpt
72
113
  true: httpLink({
73
114
  transformer: superjson,
74
115
  url: opts.url,
75
- headers,
76
116
  }),
77
117
  false: httpBatchLink({
78
118
  transformer: superjson,
79
119
  url: opts.url,
80
120
  maxURLLength: 2000,
81
- headers,
82
121
  }),
83
122
  }),
84
123
  }),
package/package.json CHANGED
@@ -1,13 +1,23 @@
1
1
  {
2
2
  "name": "@falcondev-oss/nuxt-layers-base",
3
3
  "type": "module",
4
- "version": "0.1.0",
4
+ "version": "0.2.2",
5
+ "description": "Nuxt layer with lots of useful helpers and @nuxt/ui components",
6
+ "license": "MIT",
7
+ "repository": "github:falcondev-oss/nuxt-layers",
8
+ "bugs": {
9
+ "url": "https://github.com/falcondev-oss/nuxt-layers/issues"
10
+ },
5
11
  "main": "./nuxt.config.ts",
12
+ "engines": {
13
+ "node": "24",
14
+ "pnpm": "10"
15
+ },
6
16
  "dependencies": {
7
17
  "@falcondev-oss/form-core": "^0.18.5",
8
18
  "@falcondev-oss/form-vue": "^0.18.5",
9
19
  "@falcondev-oss/trpc-vue-query": "^0.5.2",
10
- "@iconify-json/ph": "^1.2.2",
20
+ "@iconify-json/lucide": "^1.2.2",
11
21
  "@internationalized/date": "^3.10.1",
12
22
  "@nuxt/icon": "^2.2.0",
13
23
  "@nuxt/ui": "4.3.0",
@@ -20,6 +30,7 @@
20
30
  "@vueuse/nuxt": "^14.1.0",
21
31
  "@vueuse/router": "^14.1.0",
22
32
  "arkregex": "^0.0.5",
33
+ "consola": "^3.4.2",
23
34
  "defu": "^6.1.4",
24
35
  "maska": "^3.2.0",
25
36
  "reka-ui": "^2.7.0",
@@ -37,10 +48,15 @@
37
48
  "typescript": "^5.9.3",
38
49
  "vue": "^3.5.26",
39
50
  "vue-router": "^4.6.4",
51
+ "vue-tsc": "^3.2.2",
40
52
  "zod": "^4.3.5"
41
53
  },
42
54
  "scripts": {
43
55
  "dev": "nuxi dev .playground",
44
- "dev:prepare": "nuxt prepare .playground"
56
+ "dev:prepare": "nuxt prepare .playground",
57
+ "type-check": "vue-tsc --noEmit",
58
+ "lint": "eslint --cache . && prettier --check --cache .",
59
+ "lint:ci": "eslint --cache --cache-strategy content . && prettier --check --cache --cache-strategy content .",
60
+ "lint:fix": "eslint --fix --cache . && prettier --write --cache ."
45
61
  }
46
62
  }
@@ -0,0 +1,20 @@
1
+ import type { H3Error } from 'h3'
2
+ import { consola } from 'consola'
3
+
4
+ const nitroLogger = consola.withTag('nitro')
5
+
6
+ export default defineNitroPlugin((nitroApp) => {
7
+ nitroApp.hooks.hook('error', (error, { event }) => {
8
+ filterStackLines(error)
9
+
10
+ if (!event) {
11
+ nitroLogger.error(error)
12
+ return
13
+ }
14
+
15
+ const logger = nitroLogger.withTag(event.method).withTag(event.path)
16
+ const _error = error as H3Error
17
+
18
+ logger.error(_error.statusCode, error)
19
+ })
20
+ })
@@ -0,0 +1,24 @@
1
+ const ignoreStackLinesRegEx = /\(<anonymous>\)|node_modules|node:internal/
2
+ const indexRegEx = /index \d+/
3
+
4
+ export function filterStackLines(error: Error) {
5
+ if (error.cause instanceof Error && error.cause.message === error.message) {
6
+ delete error.cause
7
+ }
8
+
9
+ error.stack = error.stack
10
+ ?.split(/\n\s*at /)
11
+ .filter((line, index, stack) => {
12
+ if (ignoreStackLinesRegEx.test(line)) return false
13
+
14
+ if (indexRegEx.test(line)) {
15
+ const previousItem = stack[index + 1]
16
+ if (!previousItem) return false
17
+ if (ignoreStackLinesRegEx.test(previousItem) || index === stack.length - 1) return false
18
+ }
19
+
20
+ return true
21
+ })
22
+ .join('\nat ')
23
+ .trim()
24
+ }
@@ -0,0 +1,27 @@
1
+ import type { OverrideProperties } from 'type-fest'
2
+
3
+ export type Falsy = false | null | undefined | 0 | ''
4
+
5
+ type TypedBroadcastChannelEventMap<T> = OverrideProperties<
6
+ BroadcastChannelEventMap,
7
+ {
8
+ message: MessageEvent<T>
9
+ messageerror: MessageEvent<T>
10
+ }
11
+ >
12
+
13
+ export interface TypedBroadcastChannel<T> extends BroadcastChannel {
14
+ onmessage: ((this: BroadcastChannel, ev: MessageEvent<T>) => any) | null
15
+ onmessageerror: ((this: BroadcastChannel, ev: MessageEvent<T>) => any) | null
16
+ postMessage: (message: T) => void
17
+ addEventListener: <K extends keyof TypedBroadcastChannelEventMap<T>>(
18
+ type: K,
19
+ listener: (this: BroadcastChannel, ev: TypedBroadcastChannelEventMap<T>[K]) => any,
20
+ options?: boolean | AddEventListenerOptions,
21
+ ) => void
22
+ removeEventListener: <K extends keyof TypedBroadcastChannelEventMap<T>>(
23
+ type: K,
24
+ listener: (this: BroadcastChannel, ev: TypedBroadcastChannelEventMap<T>[K]) => any,
25
+ options?: boolean | EventListenerOptions,
26
+ ) => void
27
+ }
@@ -0,0 +1,3 @@
1
+ export function as<T>(input: unknown) {
2
+ return input as T
3
+ }