@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,361 +1,361 @@
1
- import https from 'node:https'
2
- import Conf from 'conf'
3
-
4
- import path from 'path'
5
- import type { InitialisedList } from '../src/lib/core/initialise-lists'
6
- import { runTelemetry, disableTelemetry } from '../src/lib/telemetry'
7
-
8
- const mockProjectRoot = path.resolve(__dirname, '..', '..', '..')
9
- const mockProjectDir = path.join(mockProjectRoot, './tests/test-projects/basic')
10
- const mockPackageVersions = {
11
- '@nixxie-cms/core': '14.1.0',
12
- '@nixxie-cms/auth': '9.0.1',
13
- '@nixxie-cms/fields-document': '18.0.2',
14
- '@nixxie-cms/cloudinary': '0.0.1',
15
- }
16
-
17
- jest.mock(
18
- '@nixxie-cms/core/package.json',
19
- () => {
20
- return { version: mockPackageVersions['@nixxie-cms/core'] }
21
- },
22
- { virtual: true }
23
- )
24
- jest.mock(
25
- '@nixxie-cms/auth/package.json',
26
- () => {
27
- return { version: mockPackageVersions['@nixxie-cms/auth'] }
28
- },
29
- { virtual: true }
30
- )
31
- jest.mock(
32
- '@nixxie-cms/fields-document/package.json',
33
- () => {
34
- return { version: mockPackageVersions['@nixxie-cms/fields-document'] }
35
- },
36
- { virtual: true }
37
- )
38
- jest.mock(
39
- '@nixxie-cms/cloudinary/package.json',
40
- () => {
41
- return { version: mockPackageVersions['@nixxie-cms/cloudinary'] }
42
- },
43
- { virtual: true }
44
- )
45
-
46
- let mockTelemetryConfig: any = undefined
47
-
48
- jest.mock('conf', () => {
49
- const getMockTelemetryConfig = jest.fn(() => {
50
- if (mockTelemetryConfig === 'THROW') throw new Error('JSON.parse error')
51
- return mockTelemetryConfig
52
- })
53
-
54
- return function Conf() {
55
- return {
56
- get: getMockTelemetryConfig,
57
- set: (key: string, newState: any) => {
58
- if (key !== 'telemetry') throw new Error(`Unexpected conf key ${key}`)
59
- mockTelemetryConfig = newState
60
- },
61
- delete: () => {
62
- mockTelemetryConfig = undefined
63
- },
64
- }
65
- }
66
- })
67
-
68
- jest.mock('node:https', () => {
69
- const once = jest.fn()
70
- const end = jest.fn()
71
- const request = jest.fn().mockImplementation((_, __, f) => {
72
- setTimeout(() => f(), 100)
73
- return { once, end }
74
- })
75
- // added for reach by toHaveBeenCalledWith
76
- ;(request as any).once = once
77
- ;(request as any).end = end
78
- return { request }
79
- })
80
-
81
- jest.mock('node:os', () => {
82
- return {
83
- ...jest.requireActual('node:os'),
84
- platform: () => 'nixxie-os',
85
- }
86
- })
87
-
88
- // required as CI is set for tests
89
- jest.mock('ci-info', () => {
90
- return { isCI: false }
91
- })
92
-
93
- const lists: Record<string, InitialisedList> = {
94
- Thing: {
95
- fields: {
96
- // @ts-expect-error
97
- id: {
98
- __ksTelemetryFieldTypeName: 'id',
99
- },
100
- // @ts-expect-error
101
- name: {
102
- __ksTelemetryFieldTypeName: 'id',
103
- },
104
- // @ts-expect-error
105
- thing: {
106
- __ksTelemetryFieldTypeName: 'id',
107
- },
108
- },
109
- },
110
- Stuff: {
111
- fields: {
112
- // @ts-expect-error
113
- id: {
114
- __ksTelemetryFieldTypeName: 'id',
115
- },
116
- // @ts-expect-error
117
- name: {
118
- __ksTelemetryFieldTypeName: 'id',
119
- },
120
- },
121
- },
122
- }
123
-
124
- describe('Telemetry tests', () => {
125
- beforeEach(() => {
126
- jest.clearAllMocks()
127
- mockTelemetryConfig = undefined // reset state
128
- })
129
-
130
- const today = new Date().toJSON().slice(0, 10)
131
- const mockYesterday = '2023-01-01'
132
- const mockTelemetryConfigInitialised = {
133
- informedAt: `${mockYesterday}T01:11:11.111Z`,
134
- device: { lastSentDate: mockYesterday },
135
- projects: {
136
- [mockProjectDir]: {
137
- lastSentDate: mockYesterday,
138
- },
139
- },
140
- }
141
-
142
- function expectDidSend(lastSentDate: string | null) {
143
- expect(https.request).toHaveBeenCalledWith(
144
- `https://telemetry.nixxiecms.com/3/project`,
145
- {
146
- method: 'POST',
147
- headers: {
148
- 'Content-Type': 'application/json',
149
- },
150
- },
151
- expect.any(Function)
152
- )
153
- expect((https.request as any).end).toHaveBeenCalledWith(
154
- JSON.stringify({
155
- lastSentDate,
156
- packages: mockPackageVersions,
157
- database: 'sqlite',
158
- lists: 2,
159
- fields: {
160
- unknown: 0,
161
- id: 5,
162
- },
163
- })
164
- )
165
-
166
- expect(https.request).toHaveBeenCalledWith(
167
- `https://telemetry.nixxiecms.com/3/device`,
168
- {
169
- method: 'POST',
170
- headers: {
171
- 'Content-Type': 'application/json',
172
- },
173
- },
174
- expect.any(Function)
175
- )
176
- expect((https.request as any).end).toHaveBeenCalledWith(
177
- JSON.stringify({
178
- lastSentDate,
179
- os: 'nixxie-os',
180
- node: process.versions.node.split('.')[0],
181
- })
182
- )
183
- }
184
-
185
- test('Telemetry writes out an empty configuration, and sends nothing on first run', async () => {
186
- await runTelemetry(mockProjectDir, lists, 'sqlite') // inform
187
-
188
- expect(new Conf().get).toHaveBeenCalledTimes(1)
189
- expect(https.request).toHaveBeenCalledTimes(0)
190
- expect(mockTelemetryConfig).toStrictEqual({
191
- informedAt: expect.stringMatching(new RegExp(`^${today}`)),
192
- device: { lastSentDate: null },
193
- projects: {},
194
- })
195
- })
196
-
197
- test('Telemetry is sent after inform', async () => {
198
- await runTelemetry(mockProjectDir, lists, 'sqlite') // inform
199
- await runTelemetry(mockProjectDir, lists, 'sqlite') // send
200
-
201
- expectDidSend(null)
202
- expect(new Conf().get).toHaveBeenCalledTimes(2)
203
- expect(https.request).toHaveBeenCalledTimes(2) // would be 4 if sent twice
204
- expect(mockTelemetryConfig).toStrictEqual({
205
- informedAt: expect.stringMatching(new RegExp(`^${today}`)),
206
- device: { lastSentDate: today },
207
- projects: {
208
- [mockProjectDir]: { lastSentDate: today },
209
- },
210
- })
211
- })
212
-
213
- test('Telemetry is not sent twice in one day', async () => {
214
- await runTelemetry(mockProjectDir, lists, 'sqlite') // inform
215
- await runTelemetry(mockProjectDir, lists, 'sqlite') // send
216
- await runTelemetry(mockProjectDir, lists, 'sqlite') // send, same day
217
-
218
- expectDidSend(null)
219
- expect(new Conf().get).toHaveBeenCalledTimes(3)
220
- expect(https.request).toHaveBeenCalledTimes(2) // would be 4 if sent twice
221
- })
222
-
223
- test('Telemetry sends a lastSentDate on the next run, a different day', async () => {
224
- mockTelemetryConfig = mockTelemetryConfigInitialised
225
-
226
- await runTelemetry(mockProjectDir, lists, 'sqlite') // send, different day
227
-
228
- expectDidSend(mockYesterday)
229
- expect(new Conf().get).toHaveBeenCalledTimes(1)
230
- expect(https.request).toHaveBeenCalledTimes(2)
231
- expect(mockTelemetryConfig).toStrictEqual({
232
- informedAt: expect.stringMatching(new RegExp(`^${mockYesterday}`)),
233
- device: { lastSentDate: today },
234
- projects: {
235
- [mockProjectDir]: { lastSentDate: today },
236
- },
237
- })
238
- })
239
-
240
- test(`Telemetry is reset when using "nixxie telemetry disable"`, () => {
241
- disableTelemetry()
242
-
243
- expect(mockTelemetryConfig).toBe(false)
244
- })
245
-
246
- test(`Telemetry is not sent if telemetry configuration is disabled`, async () => {
247
- mockTelemetryConfig = false
248
-
249
- await runTelemetry(mockProjectDir, lists, 'sqlite') // inform
250
- await runTelemetry(mockProjectDir, lists, 'sqlite') // send
251
- await runTelemetry(mockProjectDir, lists, 'sqlite') // send, same day
252
-
253
- expect(new Conf().get).toHaveBeenCalledTimes(3)
254
- expect(https.request).toHaveBeenCalledTimes(0)
255
- expect(mockTelemetryConfig).toBe(false)
256
- })
257
-
258
- test(`Telemetry is unchanged if configuration is malformed`, async () => {
259
- mockTelemetryConfig = 'THROW'
260
-
261
- await runTelemetry(mockProjectDir, lists, 'sqlite') // inform
262
- await runTelemetry(mockProjectDir, lists, 'sqlite') // send
263
-
264
- expect(new Conf().get).toHaveBeenCalledTimes(2)
265
- expect(https.request).toHaveBeenCalledTimes(0)
266
- expect(mockTelemetryConfig).toStrictEqual('THROW') // nothing changes
267
- })
268
-
269
- // easy opt-out tests
270
- for (const [key, value] of Object.entries({
271
- NODE_ENV: 'production',
272
- NIXXIE_TELEMETRY_DISABLED: '1',
273
- })) {
274
- describe(`when process.env.${key} is set to ${value}`, () => {
275
- const envBefore = process.env[key]
276
-
277
- beforeEach(() => {
278
- process.env[key] = value
279
- })
280
-
281
- afterEach(() => {
282
- process.env[key] = envBefore
283
- })
284
-
285
- test(`when telemetry initialised, we do nothing`, async () => {
286
- mockTelemetryConfig = mockTelemetryConfigInitialised
287
-
288
- await runTelemetry(mockProjectDir, lists, 'sqlite') // try send again
289
-
290
- expect(new Conf().get).toHaveBeenCalledTimes(1)
291
- expect(https.request).toHaveBeenCalledTimes(0)
292
- expect(mockTelemetryConfig).toBe(mockTelemetryConfigInitialised) // unchanged
293
- })
294
-
295
- test(`when telemetry uninitialised, we do nothing`, async () => {
296
- expect(mockTelemetryConfig).toBe(undefined)
297
-
298
- await runTelemetry(mockProjectDir, lists, 'sqlite') // try inform
299
- await runTelemetry(mockProjectDir, lists, 'sqlite') // try send
300
-
301
- expect(new Conf().get).toHaveBeenCalledTimes(2)
302
- expect(https.request).toHaveBeenCalledTimes(0)
303
- expect(mockTelemetryConfig).toBe(undefined) // unchanged
304
- })
305
- })
306
- }
307
-
308
- describe('when something throws internally', () => {
309
- let runTelemetryThrows: any
310
- beforeEach(() => {
311
- // this is a nightmare, don't touch it
312
- jest.resetAllMocks()
313
- jest.resetModules()
314
- runTelemetryThrows = require('../src/lib/telemetry').runTelemetry
315
- })
316
-
317
- test(`nothing actually throws`, async () => {
318
- mockTelemetryConfig = mockTelemetryConfigInitialised
319
-
320
- await runTelemetryThrows(mockProjectDir, lists, 'sqlite') // send
321
-
322
- // expect(new Conf().get).toHaveBeenCalledTimes(1) // nightmare
323
- expect(https.request).toHaveBeenCalledTimes(0)
324
- expect(mockTelemetryConfig).toBe(mockTelemetryConfigInitialised) // unchanged
325
- })
326
- })
327
-
328
- describe('when running in CI', () => {
329
- let runTelemetryCI: any
330
- beforeEach(() => {
331
- // this is a nightmare, don't touch it
332
- jest.resetAllMocks()
333
- jest.resetModules()
334
- jest.mock('ci-info', () => {
335
- return { isCI: true }
336
- })
337
- runTelemetryCI = require('../src/lib/telemetry').runTelemetry
338
- })
339
-
340
- test(`when initialised, nothing is sent`, async () => {
341
- mockTelemetryConfig = mockTelemetryConfigInitialised
342
-
343
- await runTelemetryCI(mockProjectDir, lists, 'sqlite') // try send again
344
-
345
- expect(new Conf().get).toHaveBeenCalledTimes(0)
346
- expect(https.request).toHaveBeenCalledTimes(0)
347
- expect(mockTelemetryConfig).toBe(mockTelemetryConfigInitialised) // unchanged
348
- })
349
-
350
- test(`if not initialised, we do nothing`, async () => {
351
- mockTelemetryConfig = undefined
352
-
353
- await runTelemetryCI(mockProjectDir, lists, 'sqlite') // try inform
354
- await runTelemetryCI(mockProjectDir, lists, 'sqlite') // try send
355
-
356
- expect(new Conf().get).toHaveBeenCalledTimes(0)
357
- expect(https.request).toHaveBeenCalledTimes(0)
358
- expect(mockTelemetryConfig).toBe(undefined) // nothing changed
359
- })
360
- })
361
- })
1
+ import https from 'node:https'
2
+ import Conf from 'conf'
3
+
4
+ import path from 'path'
5
+ import type { InitialisedList } from '../src/lib/core/initialise-lists'
6
+ import { runTelemetry, disableTelemetry } from '../src/lib/telemetry'
7
+
8
+ const mockProjectRoot = path.resolve(__dirname, '..', '..', '..')
9
+ const mockProjectDir = path.join(mockProjectRoot, './tests/test-projects/basic')
10
+ const mockPackageVersions = {
11
+ '@nixxie-cms/core': '14.1.0',
12
+ '@nixxie-cms/auth': '9.0.1',
13
+ '@nixxie-cms/fields-document': '18.0.2',
14
+ '@nixxie-cms/cloudinary': '0.0.1',
15
+ }
16
+
17
+ jest.mock(
18
+ '@nixxie-cms/core/package.json',
19
+ () => {
20
+ return { version: mockPackageVersions['@nixxie-cms/core'] }
21
+ },
22
+ { virtual: true }
23
+ )
24
+ jest.mock(
25
+ '@nixxie-cms/auth/package.json',
26
+ () => {
27
+ return { version: mockPackageVersions['@nixxie-cms/auth'] }
28
+ },
29
+ { virtual: true }
30
+ )
31
+ jest.mock(
32
+ '@nixxie-cms/fields-document/package.json',
33
+ () => {
34
+ return { version: mockPackageVersions['@nixxie-cms/fields-document'] }
35
+ },
36
+ { virtual: true }
37
+ )
38
+ jest.mock(
39
+ '@nixxie-cms/cloudinary/package.json',
40
+ () => {
41
+ return { version: mockPackageVersions['@nixxie-cms/cloudinary'] }
42
+ },
43
+ { virtual: true }
44
+ )
45
+
46
+ let mockTelemetryConfig: any = undefined
47
+
48
+ jest.mock('conf', () => {
49
+ const getMockTelemetryConfig = jest.fn(() => {
50
+ if (mockTelemetryConfig === 'THROW') throw new Error('JSON.parse error')
51
+ return mockTelemetryConfig
52
+ })
53
+
54
+ return function Conf() {
55
+ return {
56
+ get: getMockTelemetryConfig,
57
+ set: (key: string, newState: any) => {
58
+ if (key !== 'telemetry') throw new Error(`Unexpected conf key ${key}`)
59
+ mockTelemetryConfig = newState
60
+ },
61
+ delete: () => {
62
+ mockTelemetryConfig = undefined
63
+ },
64
+ }
65
+ }
66
+ })
67
+
68
+ jest.mock('node:https', () => {
69
+ const once = jest.fn()
70
+ const end = jest.fn()
71
+ const request = jest.fn().mockImplementation((_, __, f) => {
72
+ setTimeout(() => f(), 100)
73
+ return { once, end }
74
+ })
75
+ // added for reach by toHaveBeenCalledWith
76
+ ;(request as any).once = once
77
+ ;(request as any).end = end
78
+ return { request }
79
+ })
80
+
81
+ jest.mock('node:os', () => {
82
+ return {
83
+ ...jest.requireActual('node:os'),
84
+ platform: () => 'nixxie-os',
85
+ }
86
+ })
87
+
88
+ // required as CI is set for tests
89
+ jest.mock('ci-info', () => {
90
+ return { isCI: false }
91
+ })
92
+
93
+ const lists: Record<string, InitialisedList> = {
94
+ Thing: {
95
+ fields: {
96
+ // @ts-expect-error
97
+ id: {
98
+ __nxTelemetryFieldTypeName: 'id',
99
+ },
100
+ // @ts-expect-error
101
+ name: {
102
+ __nxTelemetryFieldTypeName: 'id',
103
+ },
104
+ // @ts-expect-error
105
+ thing: {
106
+ __nxTelemetryFieldTypeName: 'id',
107
+ },
108
+ },
109
+ },
110
+ Stuff: {
111
+ fields: {
112
+ // @ts-expect-error
113
+ id: {
114
+ __nxTelemetryFieldTypeName: 'id',
115
+ },
116
+ // @ts-expect-error
117
+ name: {
118
+ __nxTelemetryFieldTypeName: 'id',
119
+ },
120
+ },
121
+ },
122
+ }
123
+
124
+ describe('Telemetry tests', () => {
125
+ beforeEach(() => {
126
+ jest.clearAllMocks()
127
+ mockTelemetryConfig = undefined // reset state
128
+ })
129
+
130
+ const today = new Date().toJSON().slice(0, 10)
131
+ const mockYesterday = '2023-01-01'
132
+ const mockTelemetryConfigInitialised = {
133
+ informedAt: `${mockYesterday}T01:11:11.111Z`,
134
+ device: { lastSentDate: mockYesterday },
135
+ projects: {
136
+ [mockProjectDir]: {
137
+ lastSentDate: mockYesterday,
138
+ },
139
+ },
140
+ }
141
+
142
+ function expectDidSend(lastSentDate: string | null) {
143
+ expect(https.request).toHaveBeenCalledWith(
144
+ `https://telemetry.nixxieinternational.com/3/project`,
145
+ {
146
+ method: 'POST',
147
+ headers: {
148
+ 'Content-Type': 'application/json',
149
+ },
150
+ },
151
+ expect.any(Function)
152
+ )
153
+ expect((https.request as any).end).toHaveBeenCalledWith(
154
+ JSON.stringify({
155
+ lastSentDate,
156
+ packages: mockPackageVersions,
157
+ database: 'sqlite',
158
+ lists: 2,
159
+ fields: {
160
+ unknown: 0,
161
+ id: 5,
162
+ },
163
+ })
164
+ )
165
+
166
+ expect(https.request).toHaveBeenCalledWith(
167
+ `https://telemetry.nixxieinternational.com/3/device`,
168
+ {
169
+ method: 'POST',
170
+ headers: {
171
+ 'Content-Type': 'application/json',
172
+ },
173
+ },
174
+ expect.any(Function)
175
+ )
176
+ expect((https.request as any).end).toHaveBeenCalledWith(
177
+ JSON.stringify({
178
+ lastSentDate,
179
+ os: 'nixxie-os',
180
+ node: process.versions.node.split('.')[0],
181
+ })
182
+ )
183
+ }
184
+
185
+ test('Telemetry writes out an empty configuration, and sends nothing on first run', async () => {
186
+ await runTelemetry(mockProjectDir, lists, 'sqlite') // inform
187
+
188
+ expect(new Conf().get).toHaveBeenCalledTimes(1)
189
+ expect(https.request).toHaveBeenCalledTimes(0)
190
+ expect(mockTelemetryConfig).toStrictEqual({
191
+ informedAt: expect.stringMatching(new RegExp(`^${today}`)),
192
+ device: { lastSentDate: null },
193
+ projects: {},
194
+ })
195
+ })
196
+
197
+ test('Telemetry is sent after inform', async () => {
198
+ await runTelemetry(mockProjectDir, lists, 'sqlite') // inform
199
+ await runTelemetry(mockProjectDir, lists, 'sqlite') // send
200
+
201
+ expectDidSend(null)
202
+ expect(new Conf().get).toHaveBeenCalledTimes(2)
203
+ expect(https.request).toHaveBeenCalledTimes(2) // would be 4 if sent twice
204
+ expect(mockTelemetryConfig).toStrictEqual({
205
+ informedAt: expect.stringMatching(new RegExp(`^${today}`)),
206
+ device: { lastSentDate: today },
207
+ projects: {
208
+ [mockProjectDir]: { lastSentDate: today },
209
+ },
210
+ })
211
+ })
212
+
213
+ test('Telemetry is not sent twice in one day', async () => {
214
+ await runTelemetry(mockProjectDir, lists, 'sqlite') // inform
215
+ await runTelemetry(mockProjectDir, lists, 'sqlite') // send
216
+ await runTelemetry(mockProjectDir, lists, 'sqlite') // send, same day
217
+
218
+ expectDidSend(null)
219
+ expect(new Conf().get).toHaveBeenCalledTimes(3)
220
+ expect(https.request).toHaveBeenCalledTimes(2) // would be 4 if sent twice
221
+ })
222
+
223
+ test('Telemetry sends a lastSentDate on the next run, a different day', async () => {
224
+ mockTelemetryConfig = mockTelemetryConfigInitialised
225
+
226
+ await runTelemetry(mockProjectDir, lists, 'sqlite') // send, different day
227
+
228
+ expectDidSend(mockYesterday)
229
+ expect(new Conf().get).toHaveBeenCalledTimes(1)
230
+ expect(https.request).toHaveBeenCalledTimes(2)
231
+ expect(mockTelemetryConfig).toStrictEqual({
232
+ informedAt: expect.stringMatching(new RegExp(`^${mockYesterday}`)),
233
+ device: { lastSentDate: today },
234
+ projects: {
235
+ [mockProjectDir]: { lastSentDate: today },
236
+ },
237
+ })
238
+ })
239
+
240
+ test(`Telemetry is reset when using "nixxie telemetry disable"`, () => {
241
+ disableTelemetry()
242
+
243
+ expect(mockTelemetryConfig).toBe(false)
244
+ })
245
+
246
+ test(`Telemetry is not sent if telemetry configuration is disabled`, async () => {
247
+ mockTelemetryConfig = false
248
+
249
+ await runTelemetry(mockProjectDir, lists, 'sqlite') // inform
250
+ await runTelemetry(mockProjectDir, lists, 'sqlite') // send
251
+ await runTelemetry(mockProjectDir, lists, 'sqlite') // send, same day
252
+
253
+ expect(new Conf().get).toHaveBeenCalledTimes(3)
254
+ expect(https.request).toHaveBeenCalledTimes(0)
255
+ expect(mockTelemetryConfig).toBe(false)
256
+ })
257
+
258
+ test(`Telemetry is unchanged if configuration is malformed`, async () => {
259
+ mockTelemetryConfig = 'THROW'
260
+
261
+ await runTelemetry(mockProjectDir, lists, 'sqlite') // inform
262
+ await runTelemetry(mockProjectDir, lists, 'sqlite') // send
263
+
264
+ expect(new Conf().get).toHaveBeenCalledTimes(2)
265
+ expect(https.request).toHaveBeenCalledTimes(0)
266
+ expect(mockTelemetryConfig).toStrictEqual('THROW') // nothing changes
267
+ })
268
+
269
+ // easy opt-out tests
270
+ for (const [key, value] of Object.entries({
271
+ NODE_ENV: 'production',
272
+ NIXXIE_TELEMETRY_DISABLED: '1',
273
+ })) {
274
+ describe(`when process.env.${key} is set to ${value}`, () => {
275
+ const envBefore = process.env[key]
276
+
277
+ beforeEach(() => {
278
+ process.env[key] = value
279
+ })
280
+
281
+ afterEach(() => {
282
+ process.env[key] = envBefore
283
+ })
284
+
285
+ test(`when telemetry initialised, we do nothing`, async () => {
286
+ mockTelemetryConfig = mockTelemetryConfigInitialised
287
+
288
+ await runTelemetry(mockProjectDir, lists, 'sqlite') // try send again
289
+
290
+ expect(new Conf().get).toHaveBeenCalledTimes(1)
291
+ expect(https.request).toHaveBeenCalledTimes(0)
292
+ expect(mockTelemetryConfig).toBe(mockTelemetryConfigInitialised) // unchanged
293
+ })
294
+
295
+ test(`when telemetry uninitialised, we do nothing`, async () => {
296
+ expect(mockTelemetryConfig).toBe(undefined)
297
+
298
+ await runTelemetry(mockProjectDir, lists, 'sqlite') // try inform
299
+ await runTelemetry(mockProjectDir, lists, 'sqlite') // try send
300
+
301
+ expect(new Conf().get).toHaveBeenCalledTimes(2)
302
+ expect(https.request).toHaveBeenCalledTimes(0)
303
+ expect(mockTelemetryConfig).toBe(undefined) // unchanged
304
+ })
305
+ })
306
+ }
307
+
308
+ describe('when something throws internally', () => {
309
+ let runTelemetryThrows: any
310
+ beforeEach(() => {
311
+ // this is a nightmare, don't touch it
312
+ jest.resetAllMocks()
313
+ jest.resetModules()
314
+ runTelemetryThrows = require('../src/lib/telemetry').runTelemetry
315
+ })
316
+
317
+ test(`nothing actually throws`, async () => {
318
+ mockTelemetryConfig = mockTelemetryConfigInitialised
319
+
320
+ await runTelemetryThrows(mockProjectDir, lists, 'sqlite') // send
321
+
322
+ // expect(new Conf().get).toHaveBeenCalledTimes(1) // nightmare
323
+ expect(https.request).toHaveBeenCalledTimes(0)
324
+ expect(mockTelemetryConfig).toBe(mockTelemetryConfigInitialised) // unchanged
325
+ })
326
+ })
327
+
328
+ describe('when running in CI', () => {
329
+ let runTelemetryCI: any
330
+ beforeEach(() => {
331
+ // this is a nightmare, don't touch it
332
+ jest.resetAllMocks()
333
+ jest.resetModules()
334
+ jest.mock('ci-info', () => {
335
+ return { isCI: true }
336
+ })
337
+ runTelemetryCI = require('../src/lib/telemetry').runTelemetry
338
+ })
339
+
340
+ test(`when initialised, nothing is sent`, async () => {
341
+ mockTelemetryConfig = mockTelemetryConfigInitialised
342
+
343
+ await runTelemetryCI(mockProjectDir, lists, 'sqlite') // try send again
344
+
345
+ expect(new Conf().get).toHaveBeenCalledTimes(0)
346
+ expect(https.request).toHaveBeenCalledTimes(0)
347
+ expect(mockTelemetryConfig).toBe(mockTelemetryConfigInitialised) // unchanged
348
+ })
349
+
350
+ test(`if not initialised, we do nothing`, async () => {
351
+ mockTelemetryConfig = undefined
352
+
353
+ await runTelemetryCI(mockProjectDir, lists, 'sqlite') // try inform
354
+ await runTelemetryCI(mockProjectDir, lists, 'sqlite') // try send
355
+
356
+ expect(new Conf().get).toHaveBeenCalledTimes(0)
357
+ expect(https.request).toHaveBeenCalledTimes(0)
358
+ expect(mockTelemetryConfig).toBe(undefined) // nothing changed
359
+ })
360
+ })
361
+ })