@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,342 +1,342 @@
1
- import { platform } from 'node:os'
2
- import https from 'node:https'
3
-
4
- import ci from 'ci-info'
5
- import Conf from 'conf'
6
- import { bold, blue as b, yellow as y, red as r, green as g, grey } from 'chalk'
7
- import type { Device, Project, TelemetryVersion1, TelemetryVersion2 } from '../types/telemetry'
8
- import type { DatabaseProvider } from '../types'
9
- import type { InitialisedList } from './core/initialise-lists'
10
-
11
- const defaultTelemetryEndpoint = 'https://telemetry.nixxiecms.com/3/'
12
-
13
- function log(message: unknown) {
14
- if (process.env.KEYSTONE_TELEMETRY_DEBUG === '1') {
15
- console.log(`${message}`)
16
- }
17
- }
18
-
19
- type Telemetry = TelemetryVersion2
20
- type TelemetryOK = Exclude<Telemetry, false | undefined>
21
- type Configuration = ReturnType<typeof getTelemetryConfig>['userConfig']
22
-
23
- function getTelemetryConfig() {
24
- const userConfig = new Conf<{
25
- telemetry?: TelemetryVersion2
26
- }>({
27
- projectName: 'nixxiecms',
28
- projectSuffix: '',
29
- projectVersion: '3.0.0',
30
- migrations: {
31
- '^2.0.0': store => {
32
- const existing = store.get('telemetry') as TelemetryVersion1
33
- if (!existing) return // skip non-configured or known opt-outs
34
-
35
- const replacement: TelemetryVersion2 = {
36
- informedAt: null, // re-inform
37
- device: {
38
- lastSentDate: existing.device.lastSentDate ?? null,
39
- },
40
- projects: {}, // see below
41
- }
42
-
43
- // copy existing project.lastSentDate's
44
- for (const [projectPath, project] of Object.entries(existing.projects)) {
45
- if (projectPath === 'default') continue // informedAt moved to device.lastSentDate
46
-
47
- // dont copy garbage
48
- if (typeof project !== 'object') continue
49
- if (typeof project.lastSentDate !== 'string') continue
50
- if (new Date(project.lastSentDate).toString() === 'Invalid Date') continue
51
-
52
- // retain lastSentDate
53
- replacement.projects[projectPath] = {
54
- lastSentDate: project.lastSentDate,
55
- }
56
- }
57
-
58
- store.set('telemetry', replacement satisfies TelemetryVersion2)
59
- },
60
- '^3.0.0': store => {
61
- const existing = store.get('telemetry') as TelemetryVersion2
62
- if (!existing) return // skip non-configured or known opt-outs
63
-
64
- store.set('telemetry', {
65
- ...existing,
66
- informedAt: null, // re-inform
67
- } satisfies Telemetry)
68
- },
69
- },
70
- })
71
-
72
- return {
73
- telemetry: userConfig.get('telemetry'),
74
- userConfig,
75
- }
76
- }
77
-
78
- function getDefault(telemetry: Telemetry) {
79
- if (telemetry) return telemetry
80
- return {
81
- informedAt: null,
82
- device: {
83
- lastSentDate: null,
84
- },
85
- projects: {},
86
- } satisfies Telemetry // help Typescript infer the type
87
- }
88
-
89
- const todaysDate = new Date().toISOString().slice(0, 10)
90
-
91
- function collectFieldCount(lists: Record<string, InitialisedList>) {
92
- const fields: Project['fields'] = { unknown: 0 }
93
-
94
- for (const list of Object.values(lists)) {
95
- for (const [fieldPath, field] of Object.entries(list.fields)) {
96
- const fieldType = field.__ksTelemetryFieldTypeName
97
- if (!fieldType) {
98
- // skip id fields
99
- if (fieldPath.endsWith('id')) continue
100
- fields.unknown++
101
- continue
102
- }
103
-
104
- fields[fieldType] ||= 0
105
- fields[fieldType] += 1
106
- }
107
- }
108
-
109
- return fields
110
- }
111
-
112
- async function collectPackageVersions() {
113
- const packages: Project['packages'] = {
114
- '@nixxie-cms/core': '0.0.0', // "unknown"
115
- }
116
-
117
- for (const packageName of [
118
- '@nixxie-cms/core',
119
- '@nixxie-cms/auth',
120
- '@nixxie-cms/fields-document',
121
- '@nixxie-cms/cloudinary',
122
- '@nixxie-cms/session-store-redis', // we hope usage to drops to zero
123
- '@opensaas/nixxie-nextjs-auth',
124
- ]) {
125
- try {
126
- const packageJson = require(`${packageName}/package.json`)
127
- // const packageJson = await import(`${packageName}/package.json`, { assert: { type: 'json' } }) // TODO: broken in jest
128
- packages[packageName] = packageJson.version
129
- } catch (err) {
130
- // do nothing, the package is probably not installed
131
- }
132
- }
133
-
134
- return packages
135
- }
136
-
137
- function printNext(telemetry: Telemetry) {
138
- if (!telemetry) {
139
- console.log(`Telemetry data will ${r`not`} be sent by this system user`)
140
- return
141
- }
142
- console.log(`Telemetry data will be sent the next time you run ${g`"nixxie dev"`}`)
143
- }
144
-
145
- function printTelemetryStatus(telemetry: Telemetry, updated = false) {
146
- const auxverb = updated ? 'has been' : 'is'
147
-
148
- if (telemetry === undefined) {
149
- console.log(`Nixxie telemetry ${auxverb} ${y`uninitialized`}`)
150
- console.log()
151
- printNext(telemetry)
152
- return
153
- }
154
-
155
- if (telemetry === false) {
156
- console.log(`Nixxie telemetry ${auxverb} ${r`disabled`}`)
157
- console.log()
158
- printNext(telemetry)
159
- return
160
- }
161
-
162
- console.log(`Nixxie telemetry ${auxverb} ${g`enabled`}`)
163
- console.log()
164
-
165
- console.log(` Device telemetry was last sent on ${telemetry.device.lastSentDate}`)
166
- for (const [projectPath, project] of Object.entries(telemetry.projects)) {
167
- console.log(
168
- ` Project telemetry for "${y(projectPath)}" was last sent on ${project?.lastSentDate}`
169
- )
170
- }
171
-
172
- console.log()
173
- printNext(telemetry)
174
- }
175
-
176
- function inform(telemetry: TelemetryOK, userConfig: Configuration) {
177
- console.log() // gap to help visiblity
178
- console.log(`${bold('Nixxie Telemetry')}`)
179
- console.log(`${y`Nixxie collects anonymous data when you run`} ${g`"nixxie dev"`}`)
180
- console.log(
181
- `You can use ${g`"nixxie telemetry --help"`} to update your preferences at any time`
182
- )
183
- if (telemetry.informedAt === null) {
184
- console.log()
185
- console.log(`No telemetry data has been sent as part of this notice`)
186
- }
187
- console.log()
188
- printNext(telemetry)
189
- console.log() // gap to help visiblity
190
- console.log(
191
- `For more information, including how to opt-out see ${grey`https://nixxiecms.com/telemetry`} (updated ${b`2024-08-20`})`
192
- )
193
-
194
- // update the informedAt
195
- telemetry.informedAt = new Date().toJSON()
196
- userConfig.set('telemetry', telemetry)
197
- }
198
-
199
- async function sendEvent(eventType: 'project', eventData: Project): Promise<void>
200
- async function sendEvent(eventType: 'device', eventData: Device): Promise<void>
201
- async function sendEvent(eventType: 'project' | 'device', eventData: Project | Device) {
202
- const endpoint = process.env.KEYSTONE_TELEMETRY_ENDPOINT || defaultTelemetryEndpoint
203
- await new Promise<void>(resolve => {
204
- const req = https.request(
205
- `${endpoint}${eventType}`,
206
- {
207
- method: 'POST',
208
- headers: {
209
- 'Content-Type': 'application/json',
210
- },
211
- },
212
- () => resolve()
213
- )
214
-
215
- req.once('error', err => {
216
- log(err?.message ?? err)
217
- resolve()
218
- })
219
- req.end(JSON.stringify(eventData))
220
- })
221
-
222
- log(`sent ${eventType} report`)
223
- }
224
-
225
- async function sendProjectTelemetryEvent(
226
- cwd: string,
227
- lists: Record<string, InitialisedList>,
228
- dbProviderName: DatabaseProvider,
229
- telemetry: TelemetryOK,
230
- userConfig: Configuration
231
- ) {
232
- const project = telemetry.projects[cwd] ?? { lastSentDate: null }
233
- const { lastSentDate } = project
234
- if (lastSentDate && lastSentDate === todaysDate) {
235
- log('project telemetry already sent today')
236
- return
237
- }
238
-
239
- await sendEvent('project', {
240
- lastSentDate,
241
- packages: await collectPackageVersions(),
242
- database: dbProviderName,
243
- lists: Object.keys(lists).length,
244
- fields: collectFieldCount(lists),
245
- })
246
-
247
- // update the project lastSentDate
248
- telemetry.projects[cwd] = { lastSentDate: todaysDate }
249
- userConfig.set('telemetry', telemetry)
250
- }
251
-
252
- async function sendDeviceTelemetryEvent(telemetry: TelemetryOK, userConfig: Configuration) {
253
- const { lastSentDate } = telemetry.device
254
- if (lastSentDate && lastSentDate === todaysDate) {
255
- log('device telemetry already sent today')
256
- return
257
- }
258
-
259
- await sendEvent('device', {
260
- lastSentDate,
261
- os: platform(),
262
- node: process.versions.node.split('.')[0],
263
- })
264
-
265
- // update the device lastSentDate
266
- telemetry.device = { lastSentDate: todaysDate }
267
- userConfig.set('telemetry', telemetry)
268
- }
269
-
270
- export async function runTelemetry(
271
- cwd: string,
272
- lists: Record<string, InitialisedList>,
273
- dbProviderName: DatabaseProvider
274
- ) {
275
- try {
276
- if (ci.isCI) {
277
- console.log(`Nixxie Telemetry is ${r`disabled`} (running in CI)`)
278
- return
279
- }
280
-
281
- const { telemetry, userConfig } = getTelemetryConfig()
282
- if (telemetry === false) {
283
- console.log(`Nixxie Telemetry is ${r`disabled`} (via opt-out)`)
284
- return
285
- }
286
-
287
- if (process.env.NIXXIE_TELEMETRY_DISABLED === '1') {
288
- console.log(`Nixxie Telemetry is ${r`disabled`} (NIXXIE_TELEMETRY_DISABLED is set)`)
289
- return
290
- }
291
-
292
- if (process.env.DO_NOT_TRACK === '1') {
293
- console.log(`Nixxie Telemetry is ${r`disabled`} (DO_NOT_TRACK is set)`)
294
- return
295
- }
296
-
297
- if (process.env.NODE_ENV === 'production') {
298
- console.log(`Nixxie Telemetry is ${r`disabled`} (NODE_ENV is production)`)
299
- return
300
- }
301
-
302
- // don't send telemetry before we inform the user, allowing opt-out
303
- const telemetryDefaulted = getDefault(telemetry)
304
- if (!telemetryDefaulted.informedAt) return inform(telemetryDefaulted, userConfig)
305
-
306
- console.log(`Nixxie Telemetry is ${g`enabled`}`)
307
-
308
- await sendProjectTelemetryEvent(cwd, lists, dbProviderName, telemetryDefaulted, userConfig)
309
- await sendDeviceTelemetryEvent(telemetryDefaulted, userConfig)
310
- } catch (err: any) {
311
- log(err?.message ?? err)
312
- }
313
- }
314
- export function statusTelemetry(updated = false) {
315
- const { telemetry } = getTelemetryConfig()
316
- printTelemetryStatus(telemetry, updated)
317
- }
318
-
319
- export function informTelemetry() {
320
- const { userConfig } = getTelemetryConfig()
321
- inform(getDefault(false), userConfig)
322
- }
323
-
324
- export function enableTelemetry() {
325
- const { telemetry, userConfig } = getTelemetryConfig()
326
- if (!telemetry) {
327
- userConfig.set('telemetry', getDefault(telemetry))
328
- }
329
- statusTelemetry(true)
330
- }
331
-
332
- export function disableTelemetry() {
333
- const { userConfig } = getTelemetryConfig()
334
- userConfig.set('telemetry', false)
335
- statusTelemetry(true)
336
- }
337
-
338
- export function resetTelemetry() {
339
- const { userConfig } = getTelemetryConfig()
340
- userConfig.delete('telemetry')
341
- statusTelemetry(true)
342
- }
1
+ import { platform } from 'node:os'
2
+ import https from 'node:https'
3
+
4
+ import ci from 'ci-info'
5
+ import Conf from 'conf'
6
+ import { bold, blue as b, yellow as y, red as r, green as g, grey } from 'chalk'
7
+ import type { Device, Project, TelemetryVersion1, TelemetryVersion2 } from '../types/telemetry'
8
+ import type { DatabaseProvider } from '../types'
9
+ import type { InitialisedList } from './core/initialise-lists'
10
+
11
+ const defaultTelemetryEndpoint = 'https://telemetry.nixxieinternational.com/3/'
12
+
13
+ function log(message: unknown) {
14
+ if (process.env.NIXXIE_TELEMETRY_DEBUG === '1') {
15
+ console.log(`${message}`)
16
+ }
17
+ }
18
+
19
+ type Telemetry = TelemetryVersion2
20
+ type TelemetryOK = Exclude<Telemetry, false | undefined>
21
+ type Configuration = ReturnType<typeof getTelemetryConfig>['userConfig']
22
+
23
+ function getTelemetryConfig() {
24
+ const userConfig = new Conf<{
25
+ telemetry?: TelemetryVersion2
26
+ }>({
27
+ projectName: 'nixxiecms',
28
+ projectSuffix: '',
29
+ projectVersion: '3.0.0',
30
+ migrations: {
31
+ '^2.0.0': store => {
32
+ const existing = store.get('telemetry') as TelemetryVersion1
33
+ if (!existing) return // skip non-configured or known opt-outs
34
+
35
+ const replacement: TelemetryVersion2 = {
36
+ informedAt: null, // re-inform
37
+ device: {
38
+ lastSentDate: existing.device.lastSentDate ?? null,
39
+ },
40
+ projects: {}, // see below
41
+ }
42
+
43
+ // copy existing project.lastSentDate's
44
+ for (const [projectPath, project] of Object.entries(existing.projects)) {
45
+ if (projectPath === 'default') continue // informedAt moved to device.lastSentDate
46
+
47
+ // dont copy garbage
48
+ if (typeof project !== 'object') continue
49
+ if (typeof project.lastSentDate !== 'string') continue
50
+ if (new Date(project.lastSentDate).toString() === 'Invalid Date') continue
51
+
52
+ // retain lastSentDate
53
+ replacement.projects[projectPath] = {
54
+ lastSentDate: project.lastSentDate,
55
+ }
56
+ }
57
+
58
+ store.set('telemetry', replacement satisfies TelemetryVersion2)
59
+ },
60
+ '^3.0.0': store => {
61
+ const existing = store.get('telemetry') as TelemetryVersion2
62
+ if (!existing) return // skip non-configured or known opt-outs
63
+
64
+ store.set('telemetry', {
65
+ ...existing,
66
+ informedAt: null, // re-inform
67
+ } satisfies Telemetry)
68
+ },
69
+ },
70
+ })
71
+
72
+ return {
73
+ telemetry: userConfig.get('telemetry'),
74
+ userConfig,
75
+ }
76
+ }
77
+
78
+ function getDefault(telemetry: Telemetry) {
79
+ if (telemetry) return telemetry
80
+ return {
81
+ informedAt: null,
82
+ device: {
83
+ lastSentDate: null,
84
+ },
85
+ projects: {},
86
+ } satisfies Telemetry // help Typescript infer the type
87
+ }
88
+
89
+ const todaysDate = new Date().toISOString().slice(0, 10)
90
+
91
+ function collectFieldCount(lists: Record<string, InitialisedList>) {
92
+ const fields: Project['fields'] = { unknown: 0 }
93
+
94
+ for (const list of Object.values(lists)) {
95
+ for (const [fieldPath, field] of Object.entries(list.fields)) {
96
+ const fieldType = field.__nxTelemetryFieldTypeName
97
+ if (!fieldType) {
98
+ // skip id fields
99
+ if (fieldPath.endsWith('id')) continue
100
+ fields.unknown++
101
+ continue
102
+ }
103
+
104
+ fields[fieldType] ||= 0
105
+ fields[fieldType] += 1
106
+ }
107
+ }
108
+
109
+ return fields
110
+ }
111
+
112
+ async function collectPackageVersions() {
113
+ const packages: Project['packages'] = {
114
+ '@nixxie-cms/core': '0.0.0', // "unknown"
115
+ }
116
+
117
+ for (const packageName of [
118
+ '@nixxie-cms/core',
119
+ '@nixxie-cms/auth',
120
+ '@nixxie-cms/fields-document',
121
+ '@nixxie-cms/cloudinary',
122
+ '@nixxie-cms/session-store-redis', // we hope usage to drops to zero
123
+ '@opensaas/nixxie-nextjs-auth',
124
+ ]) {
125
+ try {
126
+ const packageJson = require(`${packageName}/package.json`)
127
+ // const packageJson = await import(`${packageName}/package.json`, { assert: { type: 'json' } }) // TODO: broken in jest
128
+ packages[packageName] = packageJson.version
129
+ } catch (err) {
130
+ // do nothing, the package is probably not installed
131
+ }
132
+ }
133
+
134
+ return packages
135
+ }
136
+
137
+ function printNext(telemetry: Telemetry) {
138
+ if (!telemetry) {
139
+ console.log(`Telemetry data will ${r`not`} be sent by this system user`)
140
+ return
141
+ }
142
+ console.log(`Telemetry data will be sent the next time you run ${g`"nixxie dev"`}`)
143
+ }
144
+
145
+ function printTelemetryStatus(telemetry: Telemetry, updated = false) {
146
+ const auxverb = updated ? 'has been' : 'is'
147
+
148
+ if (telemetry === undefined) {
149
+ console.log(`Nixxie telemetry ${auxverb} ${y`uninitialized`}`)
150
+ console.log()
151
+ printNext(telemetry)
152
+ return
153
+ }
154
+
155
+ if (telemetry === false) {
156
+ console.log(`Nixxie telemetry ${auxverb} ${r`disabled`}`)
157
+ console.log()
158
+ printNext(telemetry)
159
+ return
160
+ }
161
+
162
+ console.log(`Nixxie telemetry ${auxverb} ${g`enabled`}`)
163
+ console.log()
164
+
165
+ console.log(` Device telemetry was last sent on ${telemetry.device.lastSentDate}`)
166
+ for (const [projectPath, project] of Object.entries(telemetry.projects)) {
167
+ console.log(
168
+ ` Project telemetry for "${y(projectPath)}" was last sent on ${project?.lastSentDate}`
169
+ )
170
+ }
171
+
172
+ console.log()
173
+ printNext(telemetry)
174
+ }
175
+
176
+ function inform(telemetry: TelemetryOK, userConfig: Configuration) {
177
+ console.log() // gap to help visiblity
178
+ console.log(`${bold('Nixxie Telemetry')}`)
179
+ console.log(`${y`Nixxie collects anonymous data when you run`} ${g`"nixxie dev"`}`)
180
+ console.log(
181
+ `You can use ${g`"nixxie telemetry --help"`} to update your preferences at any time`
182
+ )
183
+ if (telemetry.informedAt === null) {
184
+ console.log()
185
+ console.log(`No telemetry data has been sent as part of this notice`)
186
+ }
187
+ console.log()
188
+ printNext(telemetry)
189
+ console.log() // gap to help visiblity
190
+ console.log(
191
+ `For more information, including how to opt-out see ${grey`https://nixxieinternational.com/telemetry`} (updated ${b`2024-08-20`})`
192
+ )
193
+
194
+ // update the informedAt
195
+ telemetry.informedAt = new Date().toJSON()
196
+ userConfig.set('telemetry', telemetry)
197
+ }
198
+
199
+ async function sendEvent(eventType: 'project', eventData: Project): Promise<void>
200
+ async function sendEvent(eventType: 'device', eventData: Device): Promise<void>
201
+ async function sendEvent(eventType: 'project' | 'device', eventData: Project | Device) {
202
+ const endpoint = process.env.NIXXIE_TELEMETRY_ENDPOINT || defaultTelemetryEndpoint
203
+ await new Promise<void>(resolve => {
204
+ const req = https.request(
205
+ `${endpoint}${eventType}`,
206
+ {
207
+ method: 'POST',
208
+ headers: {
209
+ 'Content-Type': 'application/json',
210
+ },
211
+ },
212
+ () => resolve()
213
+ )
214
+
215
+ req.once('error', err => {
216
+ log(err?.message ?? err)
217
+ resolve()
218
+ })
219
+ req.end(JSON.stringify(eventData))
220
+ })
221
+
222
+ log(`sent ${eventType} report`)
223
+ }
224
+
225
+ async function sendProjectTelemetryEvent(
226
+ cwd: string,
227
+ lists: Record<string, InitialisedList>,
228
+ dbProviderName: DatabaseProvider,
229
+ telemetry: TelemetryOK,
230
+ userConfig: Configuration
231
+ ) {
232
+ const project = telemetry.projects[cwd] ?? { lastSentDate: null }
233
+ const { lastSentDate } = project
234
+ if (lastSentDate && lastSentDate === todaysDate) {
235
+ log('project telemetry already sent today')
236
+ return
237
+ }
238
+
239
+ await sendEvent('project', {
240
+ lastSentDate,
241
+ packages: await collectPackageVersions(),
242
+ database: dbProviderName,
243
+ lists: Object.keys(lists).length,
244
+ fields: collectFieldCount(lists),
245
+ })
246
+
247
+ // update the project lastSentDate
248
+ telemetry.projects[cwd] = { lastSentDate: todaysDate }
249
+ userConfig.set('telemetry', telemetry)
250
+ }
251
+
252
+ async function sendDeviceTelemetryEvent(telemetry: TelemetryOK, userConfig: Configuration) {
253
+ const { lastSentDate } = telemetry.device
254
+ if (lastSentDate && lastSentDate === todaysDate) {
255
+ log('device telemetry already sent today')
256
+ return
257
+ }
258
+
259
+ await sendEvent('device', {
260
+ lastSentDate,
261
+ os: platform(),
262
+ node: process.versions.node.split('.')[0],
263
+ })
264
+
265
+ // update the device lastSentDate
266
+ telemetry.device = { lastSentDate: todaysDate }
267
+ userConfig.set('telemetry', telemetry)
268
+ }
269
+
270
+ export async function runTelemetry(
271
+ cwd: string,
272
+ lists: Record<string, InitialisedList>,
273
+ dbProviderName: DatabaseProvider
274
+ ) {
275
+ try {
276
+ if (ci.isCI) {
277
+ console.log(`Nixxie Telemetry is ${r`disabled`} (running in CI)`)
278
+ return
279
+ }
280
+
281
+ const { telemetry, userConfig } = getTelemetryConfig()
282
+ if (telemetry === false) {
283
+ console.log(`Nixxie Telemetry is ${r`disabled`} (via opt-out)`)
284
+ return
285
+ }
286
+
287
+ if (process.env.NIXXIE_TELEMETRY_DISABLED === '1') {
288
+ console.log(`Nixxie Telemetry is ${r`disabled`} (NIXXIE_TELEMETRY_DISABLED is set)`)
289
+ return
290
+ }
291
+
292
+ if (process.env.DO_NOT_TRACK === '1') {
293
+ console.log(`Nixxie Telemetry is ${r`disabled`} (DO_NOT_TRACK is set)`)
294
+ return
295
+ }
296
+
297
+ if (process.env.NODE_ENV === 'production') {
298
+ console.log(`Nixxie Telemetry is ${r`disabled`} (NODE_ENV is production)`)
299
+ return
300
+ }
301
+
302
+ // don't send telemetry before we inform the user, allowing opt-out
303
+ const telemetryDefaulted = getDefault(telemetry)
304
+ if (!telemetryDefaulted.informedAt) return inform(telemetryDefaulted, userConfig)
305
+
306
+ console.log(`Nixxie Telemetry is ${g`enabled`}`)
307
+
308
+ await sendProjectTelemetryEvent(cwd, lists, dbProviderName, telemetryDefaulted, userConfig)
309
+ await sendDeviceTelemetryEvent(telemetryDefaulted, userConfig)
310
+ } catch (err: any) {
311
+ log(err?.message ?? err)
312
+ }
313
+ }
314
+ export function statusTelemetry(updated = false) {
315
+ const { telemetry } = getTelemetryConfig()
316
+ printTelemetryStatus(telemetry, updated)
317
+ }
318
+
319
+ export function informTelemetry() {
320
+ const { userConfig } = getTelemetryConfig()
321
+ inform(getDefault(false), userConfig)
322
+ }
323
+
324
+ export function enableTelemetry() {
325
+ const { telemetry, userConfig } = getTelemetryConfig()
326
+ if (!telemetry) {
327
+ userConfig.set('telemetry', getDefault(telemetry))
328
+ }
329
+ statusTelemetry(true)
330
+ }
331
+
332
+ export function disableTelemetry() {
333
+ const { userConfig } = getTelemetryConfig()
334
+ userConfig.set('telemetry', false)
335
+ statusTelemetry(true)
336
+ }
337
+
338
+ export function resetTelemetry() {
339
+ const { userConfig } = getTelemetryConfig()
340
+ userConfig.delete('telemetry')
341
+ statusTelemetry(true)
342
+ }