@nixxie-cms/core 1.0.0 → 1.0.1

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 (186) 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 +15 -15
  100. package/scripts/cli/dist/nixxie-cms-core-scripts-cli.esm.js +15 -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/no-access.ts +7 -7
  115. package/src/fields/types/bigInt/index.ts +181 -181
  116. package/src/fields/types/bytes/index.ts +275 -275
  117. package/src/fields/types/calendarDay/index.ts +194 -194
  118. package/src/fields/types/checkbox/index.ts +76 -76
  119. package/src/fields/types/decimal/index.ts +182 -182
  120. package/src/fields/types/file/index.ts +168 -168
  121. package/src/fields/types/float/index.ts +133 -133
  122. package/src/fields/types/image/index.ts +244 -244
  123. package/src/fields/types/integer/index.ts +156 -156
  124. package/src/fields/types/json/index.ts +77 -77
  125. package/src/fields/types/multiselect/index.ts +212 -212
  126. package/src/fields/types/password/index.ts +241 -241
  127. package/src/fields/types/relationship/index.ts +381 -381
  128. package/src/fields/types/relationship/views/RelationshipTable.tsx +190 -190
  129. package/src/fields/types/select/index.ts +226 -226
  130. package/src/fields/types/text/index.ts +207 -207
  131. package/src/fields/types/timestamp/index.ts +116 -116
  132. package/src/fields/types/virtual/index.ts +108 -108
  133. package/src/helpers.ts +342 -316
  134. package/src/index.ts +4 -0
  135. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/id-field-view.tsx +167 -167
  136. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/App/index.tsx +22 -22
  137. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/CreateItemPage/index.tsx +71 -71
  138. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/HomePage/index.tsx +333 -333
  139. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ItemPage/common.tsx +358 -358
  140. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ItemPage/index.tsx +483 -483
  141. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/FilterAdd.tsx +221 -221
  142. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/PaginationControls.tsx +170 -170
  143. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/Tag.tsx +72 -72
  144. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/index.tsx +1006 -1006
  145. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/NoAccessPage/index.tsx +24 -24
  146. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/artifacts.ts +5 -5
  147. package/src/lib/context/createContext.ts +165 -161
  148. package/src/lib/core/initialise-lists.ts +1097 -1097
  149. package/src/lib/id-field.ts +214 -214
  150. package/src/lib/telemetry.ts +342 -342
  151. package/src/schema.ts +237 -233
  152. package/src/scripts/telemetry.ts +1 -1
  153. package/src/types/config/index.ts +400 -333
  154. package/src/types/config/lists.ts +4 -4
  155. package/src/types/context.ts +700 -530
  156. package/src/types/next-fields.ts +499 -499
  157. package/src/types/telemetry.ts +51 -51
  158. package/tests/telemetry.test.ts +361 -361
  159. package/CHANGELOG.md +0 -3158
  160. package/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view/package.json +0 -4
  161. package/___internal-do-not-use-will-break-in-patch/admin-ui/next-config/package.json +0 -4
  162. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/package.json +0 -4
  163. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/package.json +0 -4
  164. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/package.json +0 -4
  165. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/package.json +0 -4
  166. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/package.json +0 -4
  167. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/package.json +0 -4
  168. package/___internal-do-not-use-will-break-in-patch/artifacts/package.json +0 -4
  169. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view.d.ts.map +0 -1
  170. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/index.d.ts.map +0 -1
  171. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/index.d.ts.map +0 -1
  172. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/index.d.ts.map +0 -1
  173. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.d.ts.map +0 -1
  174. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.d.ts.map +0 -1
  175. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/index.d.ts.map +0 -1
  176. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/artifacts.d.ts.map +0 -1
  177. /package/dist/{common-1a350e11.cjs.js → common-5933f758.cjs.js} +0 -0
  178. /package/dist/{common-29fc82e6.esm.js → common-ea5c441a.esm.js} +0 -0
  179. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/id-field-view.d.ts +0 -0
  180. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/App/index.d.ts +0 -0
  181. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/CreateItemPage/index.d.ts +0 -0
  182. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/HomePage/index.d.ts +0 -0
  183. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ItemPage/index.d.ts +0 -0
  184. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/index.d.ts +0 -0
  185. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/NoAccessPage/index.d.ts +0 -0
  186. /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
+ }