@nixxie-cms/core 1.0.0 → 1.0.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 (187) hide show
  1. package/README.md +2 -2
  2. package/admin-ui/components/dist/nixxie-cms-core-admin-ui-components.cjs.js +4 -4
  3. package/admin-ui/components/dist/nixxie-cms-core-admin-ui-components.esm.js +4 -4
  4. package/admin-ui/context/dist/nixxie-cms-core-admin-ui-context.cjs.js +2 -2
  5. package/admin-ui/context/dist/nixxie-cms-core-admin-ui-context.esm.js +2 -2
  6. package/context/dist/nixxie-cms-core-context.cjs.js +2 -2
  7. package/context/dist/nixxie-cms-core-context.esm.js +2 -2
  8. package/dist/{CreateItemDialog-33335548.esm.js → CreateItemDialog-7008b050.esm.js} +1 -1
  9. package/dist/{CreateItemDialog-56cf59b7.cjs.js → CreateItemDialog-a0cab315.cjs.js} +1 -1
  10. package/dist/{PageContainer-7db73317.esm.js → PageContainer-5ae731cc.esm.js} +25 -18
  11. package/dist/{PageContainer-27c27f10.cjs.js → PageContainer-abd7159f.cjs.js} +25 -18
  12. package/dist/{admin-meta-graphql-6f7f5331.esm.js → admin-meta-graphql-0e6e606e.esm.js} +1 -1
  13. package/dist/{admin-meta-graphql-c8f926e9.cjs.js → admin-meta-graphql-306c224a.cjs.js} +1 -1
  14. package/dist/{context-3132c3ed.esm.js → context-af9957ed.esm.js} +2 -2
  15. package/dist/{context-e7a45152.cjs.js → context-b5204629.cjs.js} +2 -2
  16. package/dist/declarations/src/admin-ui/components/Navigation.d.ts.map +1 -1
  17. package/dist/declarations/src/admin-ui/components/PageContainer.d.ts.map +1 -1
  18. package/dist/declarations/src/helpers.d.ts.map +1 -1
  19. package/dist/declarations/src/index.d.ts +1 -0
  20. package/dist/declarations/src/index.d.ts.map +1 -1
  21. package/dist/declarations/src/internal-unstable/admin-ui/id-field-view.d.ts.map +1 -0
  22. package/dist/declarations/src/internal-unstable/admin-ui/pages/App/index.d.ts.map +1 -0
  23. package/dist/declarations/src/internal-unstable/admin-ui/pages/CreateItemPage/index.d.ts.map +1 -0
  24. package/dist/declarations/src/internal-unstable/admin-ui/pages/HomePage/index.d.ts.map +1 -0
  25. package/dist/declarations/src/internal-unstable/admin-ui/pages/ItemPage/index.d.ts.map +1 -0
  26. package/dist/declarations/src/internal-unstable/admin-ui/pages/ListPage/index.d.ts.map +1 -0
  27. package/dist/declarations/src/internal-unstable/admin-ui/pages/NoAccessPage/index.d.ts.map +1 -0
  28. package/dist/declarations/src/internal-unstable/artifacts.d.ts.map +1 -0
  29. package/dist/declarations/src/lib/core/initialise-lists.d.ts +1 -1
  30. package/dist/declarations/src/schema.d.ts.map +1 -1
  31. package/dist/declarations/src/types/config/index.d.ts +60 -1
  32. package/dist/declarations/src/types/config/index.d.ts.map +1 -1
  33. package/dist/declarations/src/types/config/lists.d.ts +4 -4
  34. package/dist/declarations/src/types/context.d.ts +150 -0
  35. package/dist/declarations/src/types/context.d.ts.map +1 -1
  36. package/dist/declarations/src/types/next-fields.d.ts +1 -1
  37. package/dist/{express-e9ed9a7d.cjs.js → express-455ae20c.cjs.js} +1 -1
  38. package/dist/{express-6743b918.esm.js → express-7559ca2d.esm.js} +1 -1
  39. package/dist/{index-ac01583b.cjs.js → index-89635494.cjs.js} +4 -4
  40. package/dist/{index-24b78415.esm.js → index-baa799e0.esm.js} +4 -4
  41. package/dist/nixxie-cms-core.cjs.js +104 -77
  42. package/dist/nixxie-cms-core.esm.js +104 -77
  43. package/dist/{non-null-graphql-5315718c.esm.js → non-null-graphql-a84ed64d.esm.js} +1 -1
  44. package/dist/{non-null-graphql-17b83ddc.cjs.js → non-null-graphql-add6bb3d.cjs.js} +1 -1
  45. package/dist/{resolve-hooks-66fe8a8e.cjs.js → resolve-hooks-165a9ce2.cjs.js} +1 -1
  46. package/dist/{resolve-hooks-17aafd37.esm.js → resolve-hooks-6813a045.esm.js} +2 -2
  47. package/dist/{system-dfec2f0a.esm.js → system-03e49e4f.esm.js} +8 -4
  48. package/dist/{system-48c5f6df.cjs.js → system-a321642d.cjs.js} +8 -4
  49. package/dist/{useFilter-0b5a1ee6.esm.js → useFilter-9b6db1f9.esm.js} +1 -1
  50. package/dist/{useFilter-1a4e6900.cjs.js → useFilter-acc9d413.cjs.js} +1 -1
  51. package/fields/dist/nixxie-cms-core-fields.cjs.js +16 -16
  52. package/fields/dist/nixxie-cms-core-fields.esm.js +17 -17
  53. package/fields/types/bytes/dist/nixxie-cms-core-fields-types-bytes.cjs.js +3 -3
  54. package/fields/types/bytes/dist/nixxie-cms-core-fields-types-bytes.esm.js +3 -3
  55. package/fields/types/bytes/views/dist/nixxie-cms-core-fields-types-bytes-views.cjs.js +1 -1
  56. package/fields/types/bytes/views/dist/nixxie-cms-core-fields-types-bytes-views.esm.js +1 -1
  57. package/fields/types/password/dist/nixxie-cms-core-fields-types-password.cjs.js +3 -3
  58. package/fields/types/password/dist/nixxie-cms-core-fields-types-password.esm.js +3 -3
  59. package/fields/types/relationship/views/dist/nixxie-cms-core-fields-types-relationship-views.cjs.js +4 -4
  60. package/fields/types/relationship/views/dist/nixxie-cms-core-fields-types-relationship-views.esm.js +4 -4
  61. package/fields/types/select/views/dist/nixxie-cms-core-fields-types-select-views.cjs.js +1 -1
  62. package/fields/types/select/views/dist/nixxie-cms-core-fields-types-select-views.esm.js +1 -1
  63. package/fields/types/text/views/dist/nixxie-cms-core-fields-types-text-views.cjs.js +1 -1
  64. package/fields/types/text/views/dist/nixxie-cms-core-fields-types-text-views.esm.js +1 -1
  65. package/internal-unstable/admin-ui/id-field-view/dist/nixxie-cms-core-internal-unstable-admin-ui-id-field-view.cjs.d.ts +2 -0
  66. package/internal-unstable/admin-ui/id-field-view/dist/nixxie-cms-core-internal-unstable-admin-ui-id-field-view.cjs.js +244 -0
  67. package/internal-unstable/admin-ui/id-field-view/dist/nixxie-cms-core-internal-unstable-admin-ui-id-field-view.esm.js +235 -0
  68. package/internal-unstable/admin-ui/id-field-view/package.json +4 -0
  69. package/internal-unstable/admin-ui/next-config/package.json +4 -0
  70. package/internal-unstable/admin-ui/pages/App/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-App.cjs.d.ts +2 -0
  71. package/internal-unstable/admin-ui/pages/App/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-App.cjs.js +59 -0
  72. package/internal-unstable/admin-ui/pages/App/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-App.esm.js +55 -0
  73. package/internal-unstable/admin-ui/pages/App/package.json +4 -0
  74. package/internal-unstable/admin-ui/pages/CreateItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-CreateItemPage.cjs.d.ts +2 -0
  75. package/internal-unstable/admin-ui/pages/CreateItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-CreateItemPage.cjs.js +116 -0
  76. package/internal-unstable/admin-ui/pages/CreateItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-CreateItemPage.esm.js +112 -0
  77. package/internal-unstable/admin-ui/pages/CreateItemPage/package.json +4 -0
  78. package/internal-unstable/admin-ui/pages/HomePage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-HomePage.cjs.d.ts +2 -0
  79. package/internal-unstable/admin-ui/pages/HomePage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-HomePage.cjs.js +336 -0
  80. package/internal-unstable/admin-ui/pages/HomePage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-HomePage.esm.js +332 -0
  81. package/internal-unstable/admin-ui/pages/HomePage/package.json +4 -0
  82. package/internal-unstable/admin-ui/pages/ItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ItemPage.cjs.d.ts +2 -0
  83. package/internal-unstable/admin-ui/pages/ItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ItemPage.cjs.js +463 -0
  84. package/internal-unstable/admin-ui/pages/ItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ItemPage.esm.js +455 -0
  85. package/internal-unstable/admin-ui/pages/ItemPage/package.json +4 -0
  86. package/internal-unstable/admin-ui/pages/ListPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ListPage.cjs.d.ts +2 -0
  87. package/internal-unstable/admin-ui/pages/ListPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ListPage.cjs.js +1195 -0
  88. package/internal-unstable/admin-ui/pages/ListPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ListPage.esm.js +1187 -0
  89. package/internal-unstable/admin-ui/pages/ListPage/package.json +4 -0
  90. package/internal-unstable/admin-ui/pages/NoAccessPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-NoAccessPage.cjs.d.ts +2 -0
  91. package/internal-unstable/admin-ui/pages/NoAccessPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-NoAccessPage.cjs.js +40 -0
  92. package/internal-unstable/admin-ui/pages/NoAccessPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-NoAccessPage.esm.js +35 -0
  93. package/internal-unstable/admin-ui/pages/NoAccessPage/package.json +4 -0
  94. package/internal-unstable/artifacts/dist/nixxie-cms-core-internal-unstable-artifacts.cjs.d.ts +2 -0
  95. package/internal-unstable/artifacts/dist/nixxie-cms-core-internal-unstable-artifacts.cjs.js +51 -0
  96. package/internal-unstable/artifacts/dist/nixxie-cms-core-internal-unstable-artifacts.esm.js +38 -0
  97. package/internal-unstable/artifacts/package.json +4 -0
  98. package/package.json +44 -44
  99. package/scripts/cli/dist/nixxie-cms-core-scripts-cli.cjs.js +44 -15
  100. package/scripts/cli/dist/nixxie-cms-core-scripts-cli.esm.js +44 -15
  101. package/scripts/dist/nixxie-cms-core-scripts.cjs.js +3 -3
  102. package/scripts/dist/nixxie-cms-core-scripts.esm.js +3 -3
  103. package/src/admin-ui/admin-meta-graphql.ts +168 -168
  104. package/src/admin-ui/components/CommandPalette.tsx +433 -431
  105. package/src/admin-ui/components/Navigation.tsx +389 -385
  106. package/src/admin-ui/components/PageContainer.tsx +311 -310
  107. package/src/admin-ui/components/WelcomeDialog.tsx +1 -1
  108. package/src/admin-ui/context.tsx +338 -338
  109. package/src/admin-ui/templates/app.ts +60 -60
  110. package/src/admin-ui/templates/create-item.ts +5 -5
  111. package/src/admin-ui/templates/home.ts +2 -2
  112. package/src/admin-ui/templates/item.tsx +5 -5
  113. package/src/admin-ui/templates/list.tsx +5 -5
  114. package/src/admin-ui/templates/next-config.ts +29 -0
  115. package/src/admin-ui/templates/no-access.ts +7 -7
  116. package/src/fields/types/bigInt/index.ts +181 -181
  117. package/src/fields/types/bytes/index.ts +275 -275
  118. package/src/fields/types/calendarDay/index.ts +194 -194
  119. package/src/fields/types/checkbox/index.ts +76 -76
  120. package/src/fields/types/decimal/index.ts +182 -182
  121. package/src/fields/types/file/index.ts +168 -168
  122. package/src/fields/types/float/index.ts +133 -133
  123. package/src/fields/types/image/index.ts +244 -244
  124. package/src/fields/types/integer/index.ts +156 -156
  125. package/src/fields/types/json/index.ts +77 -77
  126. package/src/fields/types/multiselect/index.ts +212 -212
  127. package/src/fields/types/password/index.ts +241 -241
  128. package/src/fields/types/relationship/index.ts +381 -381
  129. package/src/fields/types/relationship/views/RelationshipTable.tsx +190 -190
  130. package/src/fields/types/select/index.ts +226 -226
  131. package/src/fields/types/text/index.ts +207 -207
  132. package/src/fields/types/timestamp/index.ts +116 -116
  133. package/src/fields/types/virtual/index.ts +108 -108
  134. package/src/helpers.ts +342 -316
  135. package/src/index.ts +4 -0
  136. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/id-field-view.tsx +167 -167
  137. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/App/index.tsx +22 -22
  138. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/CreateItemPage/index.tsx +71 -71
  139. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/HomePage/index.tsx +333 -333
  140. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ItemPage/common.tsx +358 -358
  141. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ItemPage/index.tsx +483 -483
  142. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/FilterAdd.tsx +221 -221
  143. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/PaginationControls.tsx +170 -170
  144. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/Tag.tsx +72 -72
  145. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/index.tsx +1006 -1006
  146. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/NoAccessPage/index.tsx +24 -24
  147. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/artifacts.ts +5 -5
  148. package/src/lib/context/createContext.ts +165 -161
  149. package/src/lib/core/initialise-lists.ts +1097 -1097
  150. package/src/lib/id-field.ts +214 -214
  151. package/src/lib/telemetry.ts +342 -342
  152. package/src/schema.ts +237 -233
  153. package/src/scripts/telemetry.ts +1 -1
  154. package/src/types/config/index.ts +400 -333
  155. package/src/types/config/lists.ts +4 -4
  156. package/src/types/context.ts +700 -530
  157. package/src/types/next-fields.ts +499 -499
  158. package/src/types/telemetry.ts +51 -51
  159. package/tests/telemetry.test.ts +361 -361
  160. package/CHANGELOG.md +0 -3158
  161. package/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view/package.json +0 -4
  162. package/___internal-do-not-use-will-break-in-patch/admin-ui/next-config/package.json +0 -4
  163. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/package.json +0 -4
  164. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/package.json +0 -4
  165. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/package.json +0 -4
  166. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/package.json +0 -4
  167. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/package.json +0 -4
  168. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/package.json +0 -4
  169. package/___internal-do-not-use-will-break-in-patch/artifacts/package.json +0 -4
  170. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view.d.ts.map +0 -1
  171. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/index.d.ts.map +0 -1
  172. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/index.d.ts.map +0 -1
  173. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/index.d.ts.map +0 -1
  174. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.d.ts.map +0 -1
  175. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.d.ts.map +0 -1
  176. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/index.d.ts.map +0 -1
  177. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/artifacts.d.ts.map +0 -1
  178. /package/dist/{common-1a350e11.cjs.js → common-5933f758.cjs.js} +0 -0
  179. /package/dist/{common-29fc82e6.esm.js → common-ea5c441a.esm.js} +0 -0
  180. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/id-field-view.d.ts +0 -0
  181. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/App/index.d.ts +0 -0
  182. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/CreateItemPage/index.d.ts +0 -0
  183. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/HomePage/index.d.ts +0 -0
  184. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ItemPage/index.d.ts +0 -0
  185. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/index.d.ts +0 -0
  186. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/NoAccessPage/index.d.ts +0 -0
  187. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/artifacts.d.ts +0 -0
@@ -1,207 +1,207 @@
1
- import type { SimpleFieldTypeInfo } from '../../../types'
2
- import {
3
- type BaseListTypeInfo,
4
- type CommonFieldConfig,
5
- type FieldTypeFunc,
6
- fieldType,
7
- orderDirectionEnum,
8
- } from '../../../types'
9
- import { g } from '../../..'
10
- import { makeValidateHook, defaultIsRequired } from '../../non-null-graphql'
11
- import { filters } from '../../filters'
12
-
13
- export type TextFieldConfig<ListTypeInfo extends BaseListTypeInfo> = CommonFieldConfig<
14
- ListTypeInfo,
15
- SimpleFieldTypeInfo<'String'>
16
- > & {
17
- isIndexed?: boolean | 'unique'
18
- ui?: {
19
- displayMode?: 'input' | 'textarea'
20
- }
21
- validation?: {
22
- /**
23
- * Makes the field disallow null values and require a string at least 1 character long
24
- */
25
- isRequired?: boolean
26
- match?: { regex: RegExp; explanation?: string }
27
- length?: { min?: number; max?: number }
28
- }
29
- defaultValue?: string | null
30
- db?: {
31
- isNullable?: boolean
32
- map?: string
33
- extendPrismaSchema?: (field: string) => string
34
- /**
35
- * The underlying database type.
36
- * Only some of the types are supported on PostgreSQL and MySQL.
37
- * The native type is not customisable on SQLite.
38
- * See Prisma's documentation for more information about the supported types.
39
- *
40
- * https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#string
41
- */
42
- nativeType?:
43
- | 'Text' // PostgreSQL and MySQL
44
- | `VarChar(${number})`
45
- | `Char(${number})`
46
- | `Bit(${number})` // PostgreSQL
47
- | 'VarBit'
48
- | 'Uuid'
49
- | 'Xml'
50
- | 'Inet'
51
- | 'Citext'
52
- | 'TinyText' // MySQL
53
- | 'MediumText'
54
- | 'LargeText'
55
- }
56
- }
57
-
58
- export type TextFieldMeta = {
59
- displayMode: 'input' | 'textarea'
60
- shouldUseModeInsensitive: boolean
61
- isNullable: boolean
62
- validation: {
63
- match: { regex: { source: string; flags: string }; explanation: string | null } | null
64
- length: { min: number | null; max: number | null }
65
- }
66
- defaultValue: string | null
67
- }
68
-
69
- export function text<ListTypeInfo extends BaseListTypeInfo>(
70
- config: TextFieldConfig<ListTypeInfo> = {}
71
- ): FieldTypeFunc<ListTypeInfo> {
72
- const { defaultValue: defaultValue_, isIndexed, validation = {} } = config
73
-
74
- config.db ??= {}
75
- config.db.isNullable ??= false // TODO: sigh, remove in breaking change?
76
-
77
- const isRequired = validation.isRequired ?? false
78
- const match = validation.match
79
- const min = validation.isRequired ? (validation.length?.min ?? 1) : validation.length?.min
80
- const max = validation.length?.max
81
-
82
- return meta => {
83
- if (min !== undefined && (!Number.isInteger(min) || min < 0)) {
84
- throw new Error(
85
- `${meta.listKey}.${meta.fieldKey} specifies validation.length.min: ${min} but it must be a positive integer`
86
- )
87
- }
88
- if (max !== undefined && (!Number.isInteger(max) || max < 0)) {
89
- throw new Error(
90
- `${meta.listKey}.${meta.fieldKey} specifies validation.length.max: ${max} but it must be a positive integer`
91
- )
92
- }
93
- if (isRequired && min !== undefined && min === 0) {
94
- throw new Error(
95
- `${meta.listKey}.${meta.fieldKey} specifies validation.isRequired: true and validation.length.min: 0, this is not allowed because validation.isRequired implies at least a min length of 1`
96
- )
97
- }
98
- if (isRequired && max !== undefined && max === 0) {
99
- throw new Error(
100
- `${meta.listKey}.${meta.fieldKey} specifies validation.isRequired: true and validation.length.max: 0, this is not allowed because validation.isRequired implies at least a max length of 1`
101
- )
102
- }
103
- if (min !== undefined && max !== undefined && min > max) {
104
- throw new Error(
105
- `${meta.listKey}.${meta.fieldKey} specifies a validation.length.max that is less than the validation.length.min, and therefore has no valid options`
106
- )
107
- }
108
-
109
- // defaulted to false as a zero length string is preferred to null
110
- const isNullable = config.db?.isNullable ?? false
111
- const defaultValue = isNullable ? (defaultValue_ ?? null) : (defaultValue_ ?? '')
112
- const hasAdditionalValidation = match || min !== undefined || max !== undefined
113
- const { mode, validate } = makeValidateHook(
114
- meta,
115
- config,
116
- hasAdditionalValidation
117
- ? ({ resolvedData, operation, addValidationError }) => {
118
- if (operation === 'delete') return
119
-
120
- const value = resolvedData[meta.fieldKey]
121
- if (value != null) {
122
- if (min !== undefined && value.length < min) {
123
- if (min === 1) {
124
- addValidationError(`value must not be empty`)
125
- } else {
126
- addValidationError(`value must be at least ${min} characters long`)
127
- }
128
- }
129
- if (max !== undefined && value.length > max) {
130
- addValidationError(`value must be no longer than ${max} characters`)
131
- }
132
- if (match && !match.regex.test(value)) {
133
- addValidationError(match.explanation ?? `value must match ${match.regex}`)
134
- }
135
- }
136
- }
137
- : undefined
138
- )
139
-
140
- return fieldType({
141
- kind: 'scalar',
142
- mode,
143
- scalar: 'String',
144
- default: defaultValue === null ? undefined : { kind: 'literal', value: defaultValue },
145
- index: isIndexed === true ? 'index' : isIndexed || undefined,
146
- map: config.db?.map,
147
- nativeType: config.db?.nativeType,
148
- extendPrismaSchema: config.db?.extendPrismaSchema,
149
- })({
150
- ...config,
151
- ...defaultIsRequired(config, isRequired),
152
- hooks: {
153
- ...config.hooks,
154
- validate,
155
- },
156
- input: {
157
- uniqueWhere: isIndexed === 'unique' ? { arg: g.arg({ type: g.String }) } : undefined,
158
- where: {
159
- arg: g.arg({
160
- type: filters[meta.provider].String[mode],
161
- }),
162
- resolve: mode === 'required' ? undefined : filters.resolveString,
163
- },
164
- create: {
165
- arg: g.arg({
166
- type: g.String,
167
- defaultValue: typeof defaultValue === 'string' ? defaultValue : undefined,
168
- }),
169
- resolve(val) {
170
- if (val !== undefined) return val
171
- return defaultValue ?? null
172
- },
173
- },
174
- update: { arg: g.arg({ type: g.String }) },
175
- orderBy: { arg: g.arg({ type: orderDirectionEnum }) },
176
- },
177
- output: g.field({
178
- type: g.String,
179
- }),
180
- __ksTelemetryFieldTypeName: '@nixxie-cms/text',
181
- views: '@nixxie-cms/core/fields/types/text/views',
182
- getAdminMeta(): TextFieldMeta {
183
- return {
184
- displayMode: config.ui?.displayMode ?? 'input',
185
- shouldUseModeInsensitive: meta.provider === 'postgresql',
186
- validation: {
187
- match: match
188
- ? {
189
- regex: {
190
- source: match.regex.source,
191
- flags: match.regex.flags,
192
- },
193
- explanation: match.explanation ?? `value must match ${match.regex}`,
194
- }
195
- : null,
196
- length: {
197
- max: max ?? null,
198
- min: min ?? null,
199
- },
200
- },
201
- defaultValue: defaultValue ?? (isNullable ? null : ''),
202
- isNullable,
203
- }
204
- },
205
- })
206
- }
207
- }
1
+ import type { SimpleFieldTypeInfo } from '../../../types'
2
+ import {
3
+ type BaseListTypeInfo,
4
+ type CommonFieldConfig,
5
+ type FieldTypeFunc,
6
+ fieldType,
7
+ orderDirectionEnum,
8
+ } from '../../../types'
9
+ import { g } from '../../..'
10
+ import { makeValidateHook, defaultIsRequired } from '../../non-null-graphql'
11
+ import { filters } from '../../filters'
12
+
13
+ export type TextFieldConfig<ListTypeInfo extends BaseListTypeInfo> = CommonFieldConfig<
14
+ ListTypeInfo,
15
+ SimpleFieldTypeInfo<'String'>
16
+ > & {
17
+ isIndexed?: boolean | 'unique'
18
+ ui?: {
19
+ displayMode?: 'input' | 'textarea'
20
+ }
21
+ validation?: {
22
+ /**
23
+ * Makes the field disallow null values and require a string at least 1 character long
24
+ */
25
+ isRequired?: boolean
26
+ match?: { regex: RegExp; explanation?: string }
27
+ length?: { min?: number; max?: number }
28
+ }
29
+ defaultValue?: string | null
30
+ db?: {
31
+ isNullable?: boolean
32
+ map?: string
33
+ extendPrismaSchema?: (field: string) => string
34
+ /**
35
+ * The underlying database type.
36
+ * Only some of the types are supported on PostgreSQL and MySQL.
37
+ * The native type is not customisable on SQLite.
38
+ * See Prisma's documentation for more information about the supported types.
39
+ *
40
+ * https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#string
41
+ */
42
+ nativeType?:
43
+ | 'Text' // PostgreSQL and MySQL
44
+ | `VarChar(${number})`
45
+ | `Char(${number})`
46
+ | `Bit(${number})` // PostgreSQL
47
+ | 'VarBit'
48
+ | 'Uuid'
49
+ | 'Xml'
50
+ | 'Inet'
51
+ | 'Citext'
52
+ | 'TinyText' // MySQL
53
+ | 'MediumText'
54
+ | 'LargeText'
55
+ }
56
+ }
57
+
58
+ export type TextFieldMeta = {
59
+ displayMode: 'input' | 'textarea'
60
+ shouldUseModeInsensitive: boolean
61
+ isNullable: boolean
62
+ validation: {
63
+ match: { regex: { source: string; flags: string }; explanation: string | null } | null
64
+ length: { min: number | null; max: number | null }
65
+ }
66
+ defaultValue: string | null
67
+ }
68
+
69
+ export function text<ListTypeInfo extends BaseListTypeInfo>(
70
+ config: TextFieldConfig<ListTypeInfo> = {}
71
+ ): FieldTypeFunc<ListTypeInfo> {
72
+ const { defaultValue: defaultValue_, isIndexed, validation = {} } = config
73
+
74
+ config.db ??= {}
75
+ config.db.isNullable ??= false // TODO: sigh, remove in breaking change?
76
+
77
+ const isRequired = validation.isRequired ?? false
78
+ const match = validation.match
79
+ const min = validation.isRequired ? (validation.length?.min ?? 1) : validation.length?.min
80
+ const max = validation.length?.max
81
+
82
+ return meta => {
83
+ if (min !== undefined && (!Number.isInteger(min) || min < 0)) {
84
+ throw new Error(
85
+ `${meta.listKey}.${meta.fieldKey} specifies validation.length.min: ${min} but it must be a positive integer`
86
+ )
87
+ }
88
+ if (max !== undefined && (!Number.isInteger(max) || max < 0)) {
89
+ throw new Error(
90
+ `${meta.listKey}.${meta.fieldKey} specifies validation.length.max: ${max} but it must be a positive integer`
91
+ )
92
+ }
93
+ if (isRequired && min !== undefined && min === 0) {
94
+ throw new Error(
95
+ `${meta.listKey}.${meta.fieldKey} specifies validation.isRequired: true and validation.length.min: 0, this is not allowed because validation.isRequired implies at least a min length of 1`
96
+ )
97
+ }
98
+ if (isRequired && max !== undefined && max === 0) {
99
+ throw new Error(
100
+ `${meta.listKey}.${meta.fieldKey} specifies validation.isRequired: true and validation.length.max: 0, this is not allowed because validation.isRequired implies at least a max length of 1`
101
+ )
102
+ }
103
+ if (min !== undefined && max !== undefined && min > max) {
104
+ throw new Error(
105
+ `${meta.listKey}.${meta.fieldKey} specifies a validation.length.max that is less than the validation.length.min, and therefore has no valid options`
106
+ )
107
+ }
108
+
109
+ // defaulted to false as a zero length string is preferred to null
110
+ const isNullable = config.db?.isNullable ?? false
111
+ const defaultValue = isNullable ? (defaultValue_ ?? null) : (defaultValue_ ?? '')
112
+ const hasAdditionalValidation = match || min !== undefined || max !== undefined
113
+ const { mode, validate } = makeValidateHook(
114
+ meta,
115
+ config,
116
+ hasAdditionalValidation
117
+ ? ({ resolvedData, operation, addValidationError }) => {
118
+ if (operation === 'delete') return
119
+
120
+ const value = resolvedData[meta.fieldKey]
121
+ if (value != null) {
122
+ if (min !== undefined && value.length < min) {
123
+ if (min === 1) {
124
+ addValidationError(`value must not be empty`)
125
+ } else {
126
+ addValidationError(`value must be at least ${min} characters long`)
127
+ }
128
+ }
129
+ if (max !== undefined && value.length > max) {
130
+ addValidationError(`value must be no longer than ${max} characters`)
131
+ }
132
+ if (match && !match.regex.test(value)) {
133
+ addValidationError(match.explanation ?? `value must match ${match.regex}`)
134
+ }
135
+ }
136
+ }
137
+ : undefined
138
+ )
139
+
140
+ return fieldType({
141
+ kind: 'scalar',
142
+ mode,
143
+ scalar: 'String',
144
+ default: defaultValue === null ? undefined : { kind: 'literal', value: defaultValue },
145
+ index: isIndexed === true ? 'index' : isIndexed || undefined,
146
+ map: config.db?.map,
147
+ nativeType: config.db?.nativeType,
148
+ extendPrismaSchema: config.db?.extendPrismaSchema,
149
+ })({
150
+ ...config,
151
+ ...defaultIsRequired(config, isRequired),
152
+ hooks: {
153
+ ...config.hooks,
154
+ validate,
155
+ },
156
+ input: {
157
+ uniqueWhere: isIndexed === 'unique' ? { arg: g.arg({ type: g.String }) } : undefined,
158
+ where: {
159
+ arg: g.arg({
160
+ type: filters[meta.provider].String[mode],
161
+ }),
162
+ resolve: mode === 'required' ? undefined : filters.resolveString,
163
+ },
164
+ create: {
165
+ arg: g.arg({
166
+ type: g.String,
167
+ defaultValue: typeof defaultValue === 'string' ? defaultValue : undefined,
168
+ }),
169
+ resolve(val) {
170
+ if (val !== undefined) return val
171
+ return defaultValue ?? null
172
+ },
173
+ },
174
+ update: { arg: g.arg({ type: g.String }) },
175
+ orderBy: { arg: g.arg({ type: orderDirectionEnum }) },
176
+ },
177
+ output: g.field({
178
+ type: g.String,
179
+ }),
180
+ __nxTelemetryFieldTypeName: '@nixxie-cms/text',
181
+ views: '@nixxie-cms/core/fields/types/text/views',
182
+ getAdminMeta(): TextFieldMeta {
183
+ return {
184
+ displayMode: config.ui?.displayMode ?? 'input',
185
+ shouldUseModeInsensitive: meta.provider === 'postgresql',
186
+ validation: {
187
+ match: match
188
+ ? {
189
+ regex: {
190
+ source: match.regex.source,
191
+ flags: match.regex.flags,
192
+ },
193
+ explanation: match.explanation ?? `value must match ${match.regex}`,
194
+ }
195
+ : null,
196
+ length: {
197
+ max: max ?? null,
198
+ min: min ?? null,
199
+ },
200
+ },
201
+ defaultValue: defaultValue ?? (isNullable ? null : ''),
202
+ isNullable,
203
+ }
204
+ },
205
+ })
206
+ }
207
+ }
@@ -1,116 +1,116 @@
1
- import type { SimpleFieldTypeInfo } from '../../../types'
2
- import {
3
- type BaseListTypeInfo,
4
- type FieldTypeFunc,
5
- type CommonFieldConfig,
6
- fieldType,
7
- orderDirectionEnum,
8
- } from '../../../types'
9
- import { g } from '../../..'
10
- import { filters } from '../../filters'
11
- import { makeValidateHook, defaultIsRequired } from '../../non-null-graphql'
12
- import { type TimestampFieldMeta } from './views'
13
-
14
- export type TimestampFieldConfig<ListTypeInfo extends BaseListTypeInfo> = CommonFieldConfig<
15
- ListTypeInfo,
16
- SimpleFieldTypeInfo<'DateTime' | 'String'> // TODO: make more exact
17
- > & {
18
- isIndexed?: boolean | 'unique'
19
- validation?: {
20
- isRequired?: boolean
21
- }
22
- defaultValue?: string | { kind: 'now' }
23
- db?: {
24
- // this is @updatedAt in Prisma
25
- updatedAt?: boolean
26
- isNullable?: boolean
27
- map?: string
28
- extendPrismaSchema?: (field: string) => string
29
- }
30
- }
31
-
32
- export function timestamp<ListTypeInfo extends BaseListTypeInfo>(
33
- config: TimestampFieldConfig<ListTypeInfo> = {}
34
- ): FieldTypeFunc<ListTypeInfo> {
35
- const { isIndexed, defaultValue, validation } = config
36
-
37
- return meta => {
38
- if (typeof defaultValue === 'string') {
39
- try {
40
- g.DateTime.parseValue(defaultValue)
41
- } catch (err) {
42
- throw new Error(
43
- `${meta.listKey}.${meta.fieldKey}.defaultValue is required to be an ISO8601 date-time string such as ${new Date().toISOString()}`
44
- )
45
- }
46
- }
47
-
48
- const parsedDefaultValue =
49
- typeof defaultValue === 'string'
50
- ? (g.DateTime.parseValue(defaultValue) as Date)
51
- : defaultValue
52
- const { mode, validate } = makeValidateHook(meta, config)
53
-
54
- return fieldType({
55
- kind: 'scalar',
56
- mode,
57
- scalar: 'DateTime',
58
- index: isIndexed === true ? 'index' : isIndexed || undefined,
59
- default:
60
- typeof defaultValue === 'string'
61
- ? {
62
- kind: 'literal',
63
- value: defaultValue,
64
- }
65
- : defaultValue === undefined
66
- ? undefined
67
- : { kind: 'now' },
68
- updatedAt: config.db?.updatedAt,
69
- map: config.db?.map,
70
- extendPrismaSchema: config.db?.extendPrismaSchema,
71
- })({
72
- ...config,
73
- ...defaultIsRequired(config, validation?.isRequired ?? false),
74
- hooks: {
75
- ...config.hooks,
76
- validate,
77
- },
78
- input: {
79
- uniqueWhere: isIndexed === 'unique' ? { arg: g.arg({ type: g.DateTime }) } : undefined,
80
- where: {
81
- arg: g.arg({ type: filters[meta.provider].DateTime[mode] }),
82
- resolve: mode === 'optional' ? filters.resolveCommon : undefined,
83
- },
84
- create: {
85
- arg: g.arg({
86
- type: g.DateTime,
87
- // TODO: add support for defaultValue of { kind: 'now' } in the GraphQL API
88
- defaultValue: parsedDefaultValue instanceof Date ? parsedDefaultValue : undefined,
89
- }),
90
- resolve(val) {
91
- if (val === undefined) {
92
- if (parsedDefaultValue === undefined && config.db?.updatedAt) return undefined
93
- if (parsedDefaultValue instanceof Date || parsedDefaultValue === undefined) {
94
- return parsedDefaultValue ?? null
95
- }
96
-
97
- return new Date()
98
- }
99
- return val
100
- },
101
- },
102
- update: { arg: g.arg({ type: g.DateTime }) },
103
- orderBy: { arg: g.arg({ type: orderDirectionEnum }) },
104
- },
105
- output: g.field({ type: g.DateTime }),
106
- __ksTelemetryFieldTypeName: '@nixxie-cms/timestamp',
107
- views: '@nixxie-cms/core/fields/types/timestamp/views',
108
- getAdminMeta(): TimestampFieldMeta {
109
- return {
110
- defaultValue: defaultValue ?? null,
111
- updatedAt: config.db?.updatedAt ?? false,
112
- }
113
- },
114
- })
115
- }
116
- }
1
+ import type { SimpleFieldTypeInfo } from '../../../types'
2
+ import {
3
+ type BaseListTypeInfo,
4
+ type FieldTypeFunc,
5
+ type CommonFieldConfig,
6
+ fieldType,
7
+ orderDirectionEnum,
8
+ } from '../../../types'
9
+ import { g } from '../../..'
10
+ import { filters } from '../../filters'
11
+ import { makeValidateHook, defaultIsRequired } from '../../non-null-graphql'
12
+ import { type TimestampFieldMeta } from './views'
13
+
14
+ export type TimestampFieldConfig<ListTypeInfo extends BaseListTypeInfo> = CommonFieldConfig<
15
+ ListTypeInfo,
16
+ SimpleFieldTypeInfo<'DateTime' | 'String'> // TODO: make more exact
17
+ > & {
18
+ isIndexed?: boolean | 'unique'
19
+ validation?: {
20
+ isRequired?: boolean
21
+ }
22
+ defaultValue?: string | { kind: 'now' }
23
+ db?: {
24
+ // this is @updatedAt in Prisma
25
+ updatedAt?: boolean
26
+ isNullable?: boolean
27
+ map?: string
28
+ extendPrismaSchema?: (field: string) => string
29
+ }
30
+ }
31
+
32
+ export function timestamp<ListTypeInfo extends BaseListTypeInfo>(
33
+ config: TimestampFieldConfig<ListTypeInfo> = {}
34
+ ): FieldTypeFunc<ListTypeInfo> {
35
+ const { isIndexed, defaultValue, validation } = config
36
+
37
+ return meta => {
38
+ if (typeof defaultValue === 'string') {
39
+ try {
40
+ g.DateTime.parseValue(defaultValue)
41
+ } catch (err) {
42
+ throw new Error(
43
+ `${meta.listKey}.${meta.fieldKey}.defaultValue is required to be an ISO8601 date-time string such as ${new Date().toISOString()}`
44
+ )
45
+ }
46
+ }
47
+
48
+ const parsedDefaultValue =
49
+ typeof defaultValue === 'string'
50
+ ? (g.DateTime.parseValue(defaultValue) as Date)
51
+ : defaultValue
52
+ const { mode, validate } = makeValidateHook(meta, config)
53
+
54
+ return fieldType({
55
+ kind: 'scalar',
56
+ mode,
57
+ scalar: 'DateTime',
58
+ index: isIndexed === true ? 'index' : isIndexed || undefined,
59
+ default:
60
+ typeof defaultValue === 'string'
61
+ ? {
62
+ kind: 'literal',
63
+ value: defaultValue,
64
+ }
65
+ : defaultValue === undefined
66
+ ? undefined
67
+ : { kind: 'now' },
68
+ updatedAt: config.db?.updatedAt,
69
+ map: config.db?.map,
70
+ extendPrismaSchema: config.db?.extendPrismaSchema,
71
+ })({
72
+ ...config,
73
+ ...defaultIsRequired(config, validation?.isRequired ?? false),
74
+ hooks: {
75
+ ...config.hooks,
76
+ validate,
77
+ },
78
+ input: {
79
+ uniqueWhere: isIndexed === 'unique' ? { arg: g.arg({ type: g.DateTime }) } : undefined,
80
+ where: {
81
+ arg: g.arg({ type: filters[meta.provider].DateTime[mode] }),
82
+ resolve: mode === 'optional' ? filters.resolveCommon : undefined,
83
+ },
84
+ create: {
85
+ arg: g.arg({
86
+ type: g.DateTime,
87
+ // TODO: add support for defaultValue of { kind: 'now' } in the GraphQL API
88
+ defaultValue: parsedDefaultValue instanceof Date ? parsedDefaultValue : undefined,
89
+ }),
90
+ resolve(val) {
91
+ if (val === undefined) {
92
+ if (parsedDefaultValue === undefined && config.db?.updatedAt) return undefined
93
+ if (parsedDefaultValue instanceof Date || parsedDefaultValue === undefined) {
94
+ return parsedDefaultValue ?? null
95
+ }
96
+
97
+ return new Date()
98
+ }
99
+ return val
100
+ },
101
+ },
102
+ update: { arg: g.arg({ type: g.DateTime }) },
103
+ orderBy: { arg: g.arg({ type: orderDirectionEnum }) },
104
+ },
105
+ output: g.field({ type: g.DateTime }),
106
+ __nxTelemetryFieldTypeName: '@nixxie-cms/timestamp',
107
+ views: '@nixxie-cms/core/fields/types/timestamp/views',
108
+ getAdminMeta(): TimestampFieldMeta {
109
+ return {
110
+ defaultValue: defaultValue ?? null,
111
+ updatedAt: config.db?.updatedAt ?? false,
112
+ }
113
+ },
114
+ })
115
+ }
116
+ }