nucleus-core-ts 0.10.147 → 0.10.151

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 (204) hide show
  1. package/LICENSE +48 -48
  2. package/dist/.build-ok +1 -1
  3. package/dist/fe/components/AuthorizationPage/labels.js +13 -13
  4. package/dist/fe/components/Captcha/labels.js +17 -17
  5. package/dist/fe/components/ChatPanel/helpers.js +17 -17
  6. package/dist/fe/components/ChatPanel/labels.js +16 -16
  7. package/dist/fe/components/DataTable/labels.js +16 -16
  8. package/dist/fe/components/DevicesPage/components/DeviceCard.js +15 -15
  9. package/dist/fe/components/DevicesPage/components/DevicesPage.js +9 -9
  10. package/dist/fe/components/DevicesPage/labels.js +12 -12
  11. package/dist/fe/components/ForgotPasswordPage/labels.js +8 -8
  12. package/dist/fe/components/FormBuilder/components/FormField.js +5 -5
  13. package/dist/fe/components/FormBuilder/utils/fieldMapping.js +9 -9
  14. package/dist/fe/components/IntegrationsPage/components/ConnectionAuthFields.js +8 -8
  15. package/dist/fe/components/IntegrationsPage/components/ConnectionBasicFields.js +3 -3
  16. package/dist/fe/components/IntegrationsPage/components/ConnectionExport.js +23 -23
  17. package/dist/fe/components/IntegrationsPage/components/ConnectionForm.js +22 -22
  18. package/dist/fe/components/IntegrationsPage/components/ConnectionList.js +7 -7
  19. package/dist/fe/components/IntegrationsPage/components/ConnectionOauthFields.js +6 -6
  20. package/dist/fe/components/IntegrationsPage/components/ConnectionSettingsTab.js +24 -24
  21. package/dist/fe/components/IntegrationsPage/components/ConnectionSwitcher.js +19 -19
  22. package/dist/fe/components/IntegrationsPage/components/ConnectionTabs.js +15 -15
  23. package/dist/fe/components/IntegrationsPage/components/ConnectionTest.js +21 -21
  24. package/dist/fe/components/IntegrationsPage/components/ConnectionTransfer.js +18 -18
  25. package/dist/fe/components/IntegrationsPage/components/CredentialFields.js +19 -19
  26. package/dist/fe/components/IntegrationsPage/components/CredentialSlotRow.js +8 -8
  27. package/dist/fe/components/IntegrationsPage/components/EndpointForm.js +7 -7
  28. package/dist/fe/components/IntegrationsPage/components/EndpointFormFields.js +12 -12
  29. package/dist/fe/components/IntegrationsPage/components/EndpointList.js +7 -7
  30. package/dist/fe/components/IntegrationsPage/components/EndpointSample.js +36 -36
  31. package/dist/fe/components/IntegrationsPage/components/EndpointsTab.js +29 -29
  32. package/dist/fe/components/IntegrationsPage/components/FieldMappingRow.js +7 -7
  33. package/dist/fe/components/IntegrationsPage/components/FieldMappingRows.js +6 -6
  34. package/dist/fe/components/IntegrationsPage/components/IntegrationsPage.js +60 -60
  35. package/dist/fe/components/IntegrationsPage/components/MappingAccountFields.js +15 -15
  36. package/dist/fe/components/IntegrationsPage/components/MappingEditor.js +9 -9
  37. package/dist/fe/components/IntegrationsPage/components/MappingList.js +23 -23
  38. package/dist/fe/components/IntegrationsPage/components/MappingPasswordField.js +12 -12
  39. package/dist/fe/components/IntegrationsPage/components/MappingScheduleFields.js +23 -23
  40. package/dist/fe/components/IntegrationsPage/components/MappingWriteModeFields.js +31 -31
  41. package/dist/fe/components/IntegrationsPage/components/MappingsTab.js +56 -56
  42. package/dist/fe/components/IntegrationsPage/components/PaginationFields.js +11 -11
  43. package/dist/fe/components/IntegrationsPage/components/ParamBindingRows.js +15 -15
  44. package/dist/fe/components/IntegrationsPage/components/Primitives.js +28 -28
  45. package/dist/fe/components/IntegrationsPage/components/ReferenceCheckRows.js +9 -9
  46. package/dist/fe/components/IntegrationsPage/components/RunConfirmStep.js +6 -6
  47. package/dist/fe/components/IntegrationsPage/components/RunHistory.js +6 -6
  48. package/dist/fe/components/IntegrationsPage/components/RunHistoryRow.js +9 -9
  49. package/dist/fe/components/IntegrationsPage/components/RunPanel.js +40 -40
  50. package/dist/fe/components/IntegrationsPage/components/RunPasswordField.js +18 -18
  51. package/dist/fe/components/IntegrationsPage/components/RunPlanIssues.js +6 -6
  52. package/dist/fe/components/IntegrationsPage/components/RunPlanReferences.js +12 -12
  53. package/dist/fe/components/IntegrationsPage/components/RunPlanSuggestions.js +11 -11
  54. package/dist/fe/components/IntegrationsPage/components/RunPlanSummary.js +6 -6
  55. package/dist/fe/components/IntegrationsPage/components/RunProgressBar.js +6 -6
  56. package/dist/fe/components/IntegrationsPage/components/RunRevertConflicts.js +6 -6
  57. package/dist/fe/components/IntegrationsPage/components/Skeletons.js +7 -7
  58. package/dist/fe/components/IntegrationsPage/components/authOptions.js +4 -4
  59. package/dist/fe/components/IntegrationsPage/components/connectionDraft.js +27 -27
  60. package/dist/fe/components/IntegrationsPage/components/credentialSlots.js +25 -25
  61. package/dist/fe/components/IntegrationsPage/components/deleteIsConfirmed.js +9 -9
  62. package/dist/fe/components/IntegrationsPage/components/fieldMappingOptions.js +4 -4
  63. package/dist/fe/components/IntegrationsPage/components/formSupport.js +34 -34
  64. package/dist/fe/components/IntegrationsPage/components/jsonArray.js +14 -14
  65. package/dist/fe/components/IntegrationsPage/components/jsonObjectField.js +15 -15
  66. package/dist/fe/components/IntegrationsPage/components/mappingDraft.js +10 -10
  67. package/dist/fe/components/IntegrationsPage/components/mappingStaleness.js +22 -22
  68. package/dist/fe/components/IntegrationsPage/components/nextRuns.js +8 -8
  69. package/dist/fe/components/IntegrationsPage/components/passwordIsNeeded.js +13 -13
  70. package/dist/fe/components/IntegrationsPage/components/pathParams.js +6 -6
  71. package/dist/fe/components/IntegrationsPage/components/runFormat.js +18 -18
  72. package/dist/fe/components/IntegrationsPage/components/settleOwnership.js +18 -18
  73. package/dist/fe/components/IntegrationsPage/components/useInfiniteList.js +8 -8
  74. package/dist/fe/components/IntegrationsPage/store/index.js +20 -20
  75. package/dist/fe/components/IntegrationsPage/store/upsertInto.js +12 -12
  76. package/dist/fe/components/IntegrationsPage/text/context.js +6 -6
  77. package/dist/fe/components/IntegrationsPage/text/index.js +18 -18
  78. package/dist/fe/components/IntegrationsPage/theme/index.js +29 -29
  79. package/dist/fe/components/IntegrationsPage/types/records.js +10 -10
  80. package/dist/fe/components/IntegrationsPage/types/results.js +3 -3
  81. package/dist/fe/components/NotificationCenter/labels.js +17 -17
  82. package/dist/fe/components/ProfilePage/labels.js +10 -10
  83. package/dist/fe/components/ResetPasswordPage/labels.js +4 -4
  84. package/dist/fe/components/SetPasswordPage/labels.js +11 -11
  85. package/dist/fe/components/UsersPage/labels.js +14 -14
  86. package/dist/fe/utils/columnUtils.js +24 -24
  87. package/dist/fe/utils/searchFold.js +36 -36
  88. package/dist/index.js +6 -6
  89. package/dist/server.js +6 -6
  90. package/dist/src/Client/Proxy/authz.js +4 -4
  91. package/dist/src/Client/Proxy/httpProxy.js +136 -136
  92. package/dist/src/Client/Proxy/largeBody.js +29 -29
  93. package/dist/src/Client/Proxy/utils.js +32 -32
  94. package/dist/src/Client/Proxy/wsProxy.js +59 -59
  95. package/dist/src/Managers/Redis/index.d.ts +14 -0
  96. package/dist/src/Nucleus/routes/auth/admin/impersonationStore.d.ts +3 -4
  97. package/dist/src/Nucleus/routes/auth/refresh/issuedPair.d.ts +67 -0
  98. package/dist/src/Nucleus/routes/auth/refresh/recordIssued.d.ts +15 -6
  99. package/dist/src/Nucleus/routes/auth/refresh/refreshChain.d.ts +56 -0
  100. package/dist/src/Services/Auth/SessionStore/utils.d.ts +2 -0
  101. package/dist/src/Shared/cron.js +71 -71
  102. package/dist/src/Shared/redactSecrets.js +156 -156
  103. package/dist/src/Shared/redaction/bare.js +61 -61
  104. package/dist/src/Shared/redaction/floor.js +48 -48
  105. package/dist/src/Shared/redaction/freeText.js +70 -70
  106. package/dist/src/Shared/redaction/json.js +30 -30
  107. package/dist/src/Shared/redaction/lists.js +23 -23
  108. package/dist/src/Shared/redaction/markers.js +28 -28
  109. package/dist/src/Shared/redaction/names.js +49 -49
  110. package/dist/src/Shared/redaction/pairs.js +54 -54
  111. package/dist/src/Shared/redaction/secretString.js +29 -29
  112. package/dist/src/Shared/redaction/structured.js +52 -52
  113. package/dist/src/Shared/redaction/walk.js +25 -25
  114. package/infra/scripts/generate-project.ts +766 -766
  115. package/infra/templates/README.md +57 -57
  116. package/infra/templates/backend/.dockerignore +9 -9
  117. package/infra/templates/backend/.env.example +15 -15
  118. package/infra/templates/backend/README.md +28 -28
  119. package/infra/templates/backend/azure-pipelines.yml +135 -135
  120. package/infra/templates/backend/k8s/Dockerfile +31 -31
  121. package/infra/templates/backend/k8s/configmap.yaml +26 -26
  122. package/infra/templates/backend/k8s/deployment.yaml +85 -85
  123. package/infra/templates/backend/k8s/pvc.yaml +12 -12
  124. package/infra/templates/backend/k8s/service.yaml +13 -13
  125. package/infra/templates/backend/tsconfig.json +22 -22
  126. package/infra/templates/frontend/.dockerignore +10 -10
  127. package/infra/templates/frontend/.env.example +8 -8
  128. package/infra/templates/frontend/.env.local.example +10 -10
  129. package/infra/templates/frontend/README.md +69 -69
  130. package/infra/templates/frontend/app/[tablename]/page.tsx +37 -37
  131. package/infra/templates/frontend/app/_components/AuthWrapper/index.tsx +63 -63
  132. package/infra/templates/frontend/app/authorization/page.tsx +43 -43
  133. package/infra/templates/frontend/app/change-password/page.tsx +23 -23
  134. package/infra/templates/frontend/app/devices/page.tsx +127 -127
  135. package/infra/templates/frontend/app/forgot-password/page.tsx +20 -20
  136. package/infra/templates/frontend/app/globals.css +28 -28
  137. package/infra/templates/frontend/app/layout.tsx +35 -35
  138. package/infra/templates/frontend/app/login/page.tsx +33 -33
  139. package/infra/templates/frontend/app/page.tsx +565 -565
  140. package/infra/templates/frontend/app/profile/page.tsx +92 -92
  141. package/infra/templates/frontend/app/register/page.tsx +27 -27
  142. package/infra/templates/frontend/app/reset-password/page.tsx +60 -60
  143. package/infra/templates/frontend/app/set-password/page.tsx +43 -43
  144. package/infra/templates/frontend/app/ui-docs/page.tsx +52 -52
  145. package/infra/templates/frontend/app/users/page.tsx +52 -52
  146. package/infra/templates/frontend/app/verify-email/page.tsx +41 -41
  147. package/infra/templates/frontend/app/verify-magic-link/page.tsx +46 -46
  148. package/infra/templates/frontend/azure-pipelines.yml +137 -137
  149. package/infra/templates/frontend/code-and-design-principles.md +438 -438
  150. package/infra/templates/frontend/k8s/Dockerfile +50 -50
  151. package/infra/templates/frontend/k8s/configmap.yaml +18 -18
  152. package/infra/templates/frontend/k8s/deployment.yaml +72 -72
  153. package/infra/templates/frontend/k8s/ingress.yaml +36 -36
  154. package/infra/templates/frontend/k8s/service.yaml +14 -14
  155. package/infra/templates/frontend/lib/api/endpoints.ts +37 -37
  156. package/infra/templates/frontend/lib/api/factory.ts +44 -44
  157. package/infra/templates/frontend/lib/api/hook.ts +10 -10
  158. package/infra/templates/frontend/next.config.ts +19 -19
  159. package/infra/templates/frontend/package.json +34 -34
  160. package/infra/templates/frontend/postcss.config.mjs +5 -5
  161. package/infra/templates/frontend/server.ts +114 -114
  162. package/infra/templates/frontend/tsconfig.json +23 -23
  163. package/package.json +1 -1
  164. package/public/components/CTA.tsx +25 -25
  165. package/public/components/Capabilities.tsx +67 -67
  166. package/public/components/Features.tsx +107 -107
  167. package/public/components/Footer.tsx +58 -58
  168. package/public/components/Hero.tsx +51 -51
  169. package/public/components/Managers.tsx +55 -55
  170. package/public/components/Nav.tsx +91 -91
  171. package/public/components/Stack.tsx +36 -36
  172. package/public/components/docs/Docs.tsx +60 -60
  173. package/public/components/docs/DocsContent.tsx +176 -176
  174. package/public/components/docs/DocsRightSidebar.tsx +53 -53
  175. package/public/components/docs/DocsSidebar.tsx +54 -54
  176. package/public/components/docs/content/authentication.ts +836 -836
  177. package/public/components/docs/content/authorization.ts +268 -268
  178. package/public/components/docs/content/backupRestore.ts +173 -173
  179. package/public/components/docs/content/clientModule.ts +287 -287
  180. package/public/components/docs/content/entityCrud.ts +682 -682
  181. package/public/components/docs/content/monitoring.ts +313 -313
  182. package/public/components/docs/content/multiTenant.ts +269 -269
  183. package/public/components/docs/content/oauthApiKeys.ts +325 -325
  184. package/public/components/docs/content/pubsub.ts +131 -131
  185. package/public/components/docs/content/storageCdn.ts +171 -171
  186. package/public/components/docs/content/verification.ts +289 -289
  187. package/public/components/docs/docsData.ts +113 -113
  188. package/public/components/docs/index.ts +6 -6
  189. package/public/components/index.ts +9 -9
  190. package/public/docs.css +629 -629
  191. package/public/index.html +81 -81
  192. package/public/index.tsx +42 -42
  193. package/public/store.ts +76 -76
  194. package/public/styles.css +858 -858
  195. package/schemas/config.nucleus.json +2651 -2651
  196. package/scripts/audit-purge-noise.ts +120 -120
  197. package/scripts/build.ts +582 -582
  198. package/scripts/generate-system-tables-types.ts +18 -18
  199. package/scripts/generate-types-schema.test.ts +73 -73
  200. package/scripts/generate-types-schema.ts +1284 -1284
  201. package/scripts/packagedScripts.test.ts +87 -87
  202. package/scripts/publish.ts +276 -276
  203. package/scripts/skillCitations.test.ts +107 -107
  204. package/scripts/verify-publishable.ts +40 -40
package/LICENSE CHANGED
@@ -1,48 +1,48 @@
1
- Nucleus Core - Proprietary Software License
2
-
3
- Copyright (c) 2024-2026 Hidayet Can Özcan <hidayetcan@gmail.com>
4
- All Rights Reserved.
5
-
6
- TERMS AND CONDITIONS
7
-
8
- 1. GRANT OF LICENSE
9
- This software and associated documentation files (the "Software") are
10
- licensed, not sold. Subject to the terms of this license, you are granted
11
- a non-exclusive, non-transferable, limited license to use the Software
12
- solely for your internal business purposes.
13
-
14
- 2. RESTRICTIONS
15
- You may NOT:
16
- - Copy, modify, or distribute the Software
17
- - Reverse engineer, decompile, or disassemble the Software
18
- - Sublicense, rent, lease, or lend the Software
19
- - Use the Software to create derivative works
20
- - Remove or alter any proprietary notices or labels on the Software
21
- - Share, publish, or make the Software available to third parties
22
-
23
- 3. INTELLECTUAL PROPERTY
24
- The Software is protected by copyright and other intellectual property
25
- laws. The author retains all right, title, and interest in and to the
26
- Software, including all intellectual property rights.
27
-
28
- 4. NO WARRANTY
29
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
30
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
32
-
33
- 5. LIMITATION OF LIABILITY
34
- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
36
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
37
- DEALINGS IN THE SOFTWARE.
38
-
39
- 6. TERMINATION
40
- This license is effective until terminated. It will terminate automatically
41
- if you fail to comply with any term of this license. Upon termination,
42
- you must destroy all copies of the Software.
43
-
44
- 7. GOVERNING LAW
45
- This license shall be governed by and construed in accordance with the
46
- laws of Turkey.
47
-
48
- For licensing inquiries, please contact: hidayetcan@gmail.com
1
+ Nucleus Core - Proprietary Software License
2
+
3
+ Copyright (c) 2024-2026 Hidayet Can Özcan <hidayetcan@gmail.com>
4
+ All Rights Reserved.
5
+
6
+ TERMS AND CONDITIONS
7
+
8
+ 1. GRANT OF LICENSE
9
+ This software and associated documentation files (the "Software") are
10
+ licensed, not sold. Subject to the terms of this license, you are granted
11
+ a non-exclusive, non-transferable, limited license to use the Software
12
+ solely for your internal business purposes.
13
+
14
+ 2. RESTRICTIONS
15
+ You may NOT:
16
+ - Copy, modify, or distribute the Software
17
+ - Reverse engineer, decompile, or disassemble the Software
18
+ - Sublicense, rent, lease, or lend the Software
19
+ - Use the Software to create derivative works
20
+ - Remove or alter any proprietary notices or labels on the Software
21
+ - Share, publish, or make the Software available to third parties
22
+
23
+ 3. INTELLECTUAL PROPERTY
24
+ The Software is protected by copyright and other intellectual property
25
+ laws. The author retains all right, title, and interest in and to the
26
+ Software, including all intellectual property rights.
27
+
28
+ 4. NO WARRANTY
29
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
30
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
32
+
33
+ 5. LIMITATION OF LIABILITY
34
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
36
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
37
+ DEALINGS IN THE SOFTWARE.
38
+
39
+ 6. TERMINATION
40
+ This license is effective until terminated. It will terminate automatically
41
+ if you fail to comply with any term of this license. Upon termination,
42
+ you must destroy all copies of the Software.
43
+
44
+ 7. GOVERNING LAW
45
+ This license shall be governed by and construed in accordance with the
46
+ laws of Turkey.
47
+
48
+ For licensing inquiries, please contact: hidayetcan@gmail.com
package/dist/.build-ok CHANGED
@@ -1 +1 @@
1
- 0.10.147
1
+ 0.10.151
@@ -1,16 +1,16 @@
1
- /**
2
- * Every word the authorization screens say, so a portal can say them in its
3
- * own language.
4
- *
5
- * This is the screen an administrator opens to decide who may do what, and
6
- * until now it said "Roles", "Show assigned only", "No claims match your
7
- * filters" and "Are you sure you want to delete this role?" in English no
8
- * matter what language the rest of the portal spoke. `title` was already a
9
- * prop — which is the tell: an installation could translate the heading and
10
- * nothing underneath it.
11
- *
12
- * Defaults stay English, so an installation that passes no labels is
13
- * completely unaffected.
1
+ /**
2
+ * Every word the authorization screens say, so a portal can say them in its
3
+ * own language.
4
+ *
5
+ * This is the screen an administrator opens to decide who may do what, and
6
+ * until now it said "Roles", "Show assigned only", "No claims match your
7
+ * filters" and "Are you sure you want to delete this role?" in English no
8
+ * matter what language the rest of the portal spoke. `title` was already a
9
+ * prop — which is the tell: an installation could translate the heading and
10
+ * nothing underneath it.
11
+ *
12
+ * Defaults stay English, so an installation that passes no labels is
13
+ * completely unaffected.
14
14
  */ export const DEFAULT_AUTHORIZATION_LABELS = {
15
15
  locale: 'en-US',
16
16
  title: 'Authorization Management',
@@ -1,20 +1,20 @@
1
- /**
2
- * Every word the security check says.
3
- *
4
- * This is the most-read component in the kit and the one nobody thought to
5
- * translate: it sits on the sign-in form, so on an installation of 879 people
6
- * it is shown several hundred times a morning. A portal could pass `label` and
7
- * change the heading — and the box under the heading still said "Enter the
8
- * result", "New challenge", "Expires in 1:30" and, when somebody was slow,
9
- * "Captcha expired. Please refresh." Four sentences of English on the first
10
- * screen of a portal that is otherwise entirely in its own language.
11
- *
12
- * The placeholders are per challenge type because the instruction is different
13
- * for each: a sum wants its result, an image wants the letters in it, and the
14
- * puzzle wants an order. `expiresIn` takes the formatted clock as `{time}` so a
15
- * translation can put it where its own grammar wants it.
16
- *
17
- * Defaults stay English, so an installation that passes nothing is unchanged.
1
+ /**
2
+ * Every word the security check says.
3
+ *
4
+ * This is the most-read component in the kit and the one nobody thought to
5
+ * translate: it sits on the sign-in form, so on an installation of 879 people
6
+ * it is shown several hundred times a morning. A portal could pass `label` and
7
+ * change the heading — and the box under the heading still said "Enter the
8
+ * result", "New challenge", "Expires in 1:30" and, when somebody was slow,
9
+ * "Captcha expired. Please refresh." Four sentences of English on the first
10
+ * screen of a portal that is otherwise entirely in its own language.
11
+ *
12
+ * The placeholders are per challenge type because the instruction is different
13
+ * for each: a sum wants its result, an image wants the letters in it, and the
14
+ * puzzle wants an order. `expiresIn` takes the formatted clock as `{time}` so a
15
+ * translation can put it where its own grammar wants it.
16
+ *
17
+ * Defaults stay English, so an installation that passes nothing is unchanged.
18
18
  */ export const DEFAULT_CAPTCHA_LABELS = {
19
19
  heading: 'Security Check',
20
20
  clickRefresh: 'Click refresh to load captcha',
@@ -14,16 +14,16 @@ export function initialsOf(name) {
14
14
  const initials = parts.map((p)=>p[0]?.toUpperCase() ?? '').join('');
15
15
  return initials || '?';
16
16
  }
17
- /**
18
- * The age of a message, in the panel's own words.
19
- *
20
- * The units used to be English letters written into the source (`5m`, `3h`,
21
- * `2d`), which no installation could change, and the fallback past a week was a
22
- * bare `toLocaleDateString()` — no locale, so the string came out in the
23
- * SERVER's locale during the server render and the BROWSER's after hydration.
24
- * The same row rendered twice, differently, and React tore. Both halves now
25
- * come from the labels: the units as functions of the number, the date under
26
- * the named `locale`.
17
+ /**
18
+ * The age of a message, in the panel's own words.
19
+ *
20
+ * The units used to be English letters written into the source (`5m`, `3h`,
21
+ * `2d`), which no installation could change, and the fallback past a week was a
22
+ * bare `toLocaleDateString()` — no locale, so the string came out in the
23
+ * SERVER's locale during the server render and the BROWSER's after hydration.
24
+ * The same row rendered twice, differently, and React tore. Both halves now
25
+ * come from the labels: the units as functions of the number, the date under
26
+ * the named `locale`.
27
27
  */ export function formatRelativeTime(iso, labels) {
28
28
  if (!iso) return '';
29
29
  const date = new Date(iso);
@@ -37,13 +37,13 @@ export function initialsOf(name) {
37
37
  if (days < 7) return labels.daysAgo(days);
38
38
  return date.toLocaleDateString(labels.locale);
39
39
  }
40
- /**
41
- * The clock beneath a message.
42
- *
43
- * `hour12` is pinned as well as the locale: left to the environment, a locale
44
- * that prints "2:32 PM" on one machine prints "14:32" on the other, which is
45
- * the same hydration tear by a different route. A 24-hour clock is the one both
46
- * ends can agree on without asking anybody.
40
+ /**
41
+ * The clock beneath a message.
42
+ *
43
+ * `hour12` is pinned as well as the locale: left to the environment, a locale
44
+ * that prints "2:32 PM" on one machine prints "14:32" on the other, which is
45
+ * the same hydration tear by a different route. A 24-hour clock is the one both
46
+ * ends can agree on without asking anybody.
47
47
  */ export function formatClockTime(iso, labels) {
48
48
  return new Date(iso).toLocaleTimeString(labels.locale, {
49
49
  hour: '2-digit',
@@ -1,19 +1,19 @@
1
- /**
2
- * Every word the chat says, so a portal can say them in its own language.
3
- *
4
- * The panel wrote them in English inside the components, and the one label the
5
- * consumer COULD pass — `title` — was the tell: an intranet in Turkish set the
6
- * heading to "Sohbetler" and the panel underneath it still said "No
7
- * conversations yet" and "Select a conversation to start chatting". Two
8
- * sentences of English on the one screen in the product where people talk to
9
- * each other.
10
- *
11
- * Defaults stay English, so nothing that does not pass labels changes.
12
- *
13
- * Anything that interpolates a value is a FUNCTION of that value, never a
14
- * translated fragment glued to an untranslated one: "3 participants" is
15
- * "3 katılımcı" in Turkish but "typing" moves to the end of its sentence, and
16
- * a concatenation would produce a sentence in neither language.
1
+ /**
2
+ * Every word the chat says, so a portal can say them in its own language.
3
+ *
4
+ * The panel wrote them in English inside the components, and the one label the
5
+ * consumer COULD pass — `title` — was the tell: an intranet in Turkish set the
6
+ * heading to "Sohbetler" and the panel underneath it still said "No
7
+ * conversations yet" and "Select a conversation to start chatting". Two
8
+ * sentences of English on the one screen in the product where people talk to
9
+ * each other.
10
+ *
11
+ * Defaults stay English, so nothing that does not pass labels changes.
12
+ *
13
+ * Anything that interpolates a value is a FUNCTION of that value, never a
14
+ * translated fragment glued to an untranslated one: "3 participants" is
15
+ * "3 katılımcı" in Turkish but "typing" moves to the end of its sentence, and
16
+ * a concatenation would produce a sentence in neither language.
17
17
  */ export const DEFAULT_CHAT_LABELS = {
18
18
  loadingConversations: 'Loading conversations...',
19
19
  noConversations: 'No conversations yet',
@@ -1,19 +1,19 @@
1
- /**
2
- * Every word this table says on its own, so a portal can say them in its own
3
- * language.
4
- *
5
- * The DataTable is the one component in the kit that almost every screen of an
6
- * installation is built out of — every list of employees, documents, requests
7
- * and announcements is this table. Column headers and cell contents already
8
- * come from the caller, which hid the problem: the words the table supplies
9
- * *itself* were welded into the components. A Turkish intranet could name its
10
- * columns "Ad", "Birim", "Tarih" and still show "No data available" when the
11
- * list was empty, "Loading..." while it filled, "Save"/"Cancel" on every
12
- * inline edit, and "3 item selected" over a selection toolbar whose own buttons
13
- * were Turkish. Half a screen in one language and half in another.
14
- *
15
- * Defaults stay English, so an installation that passes no labels keeps the
16
- * words it has today.
1
+ /**
2
+ * Every word this table says on its own, so a portal can say them in its own
3
+ * language.
4
+ *
5
+ * The DataTable is the one component in the kit that almost every screen of an
6
+ * installation is built out of — every list of employees, documents, requests
7
+ * and announcements is this table. Column headers and cell contents already
8
+ * come from the caller, which hid the problem: the words the table supplies
9
+ * *itself* were welded into the components. A Turkish intranet could name its
10
+ * columns "Ad", "Birim", "Tarih" and still show "No data available" when the
11
+ * list was empty, "Loading..." while it filled, "Save"/"Cancel" on every
12
+ * inline edit, and "3 item selected" over a selection toolbar whose own buttons
13
+ * were Turkish. Half a screen in one language and half in another.
14
+ *
15
+ * Defaults stay English, so an installation that passes no labels keeps the
16
+ * words it has today.
17
17
  */ export const DEFAULT_DATA_TABLE_LABELS = {
18
18
  tableLabel: 'Data table',
19
19
  empty: 'No data available',
@@ -76,16 +76,16 @@ function getTrustScoreColor(score) {
76
76
  if (score >= 40) return 'bg-orange-500';
77
77
  return 'bg-red-500';
78
78
  }
79
- /**
80
- * When a device was last here, in a form that cannot tear on hydration.
81
- *
82
- * It used to be `toLocaleDateString(undefined, …)`, which reads the SERVER's
83
- * locale while the page renders on the server and the BROWSER's once React
84
- * takes over — two different strings for the same row, and React replacing one
85
- * with the other after mount. It also printed 8/5/2026, which in Turkey reads
86
- * as the 8th of May. The locale is now named by the labels, and the clock is
87
- * pinned to 24 hours so "14:32" does not become "2:32 PM" between the two
88
- * passes.
79
+ /**
80
+ * When a device was last here, in a form that cannot tear on hydration.
81
+ *
82
+ * It used to be `toLocaleDateString(undefined, …)`, which reads the SERVER's
83
+ * locale while the page renders on the server and the BROWSER's once React
84
+ * takes over — two different strings for the same row, and React replacing one
85
+ * with the other after mount. It also printed 8/5/2026, which in Turkey reads
86
+ * as the 8th of May. The locale is now named by the labels, and the clock is
87
+ * pinned to 24 hours so "14:32" does not become "2:32 PM" between the two
88
+ * passes.
89
89
  */ function formatDate(dateString, say) {
90
90
  if (!dateString) return say.unknown;
91
91
  const date = new Date(dateString);
@@ -100,11 +100,11 @@ function getTrustScoreColor(score) {
100
100
  timeZone: say.timeZone || undefined
101
101
  });
102
102
  }
103
- /**
104
- * The device kind, in words. The server sends `mobile` / `tablet` / `desktop`
105
- * and the card used to print that raw value, so a Turkish portal read
106
- * "mobile • Chrome". Anything else the server sends is named as unknown rather
107
- * than shown in the server's vocabulary.
103
+ /**
104
+ * The device kind, in words. The server sends `mobile` / `tablet` / `desktop`
105
+ * and the card used to print that raw value, so a Turkish portal read
106
+ * "mobile • Chrome". Anything else the server sends is named as unknown rather
107
+ * than shown in the server's vocabulary.
108
108
  */ function deviceTypeWord(deviceType, say) {
109
109
  switch(deviceType?.toLowerCase()){
110
110
  case 'mobile':
@@ -12,15 +12,15 @@ import { devicesPageTheme } from '../theme';
12
12
  import { DeviceCard } from './DeviceCard';
13
13
  import { DevicesHeader } from './DevicesHeader';
14
14
  gsap.registerPlugin(useGSAP);
15
- /**
16
- * When a waiting device asked, in a form that cannot tear on hydration.
17
- *
18
- * It used to be a bare `toLocaleString()`, which reads the SERVER's locale
19
- * while the page renders on the server and the BROWSER's once React takes over
20
- * — two different strings for the same tile, and React replacing one with the
21
- * other after mount. It also printed 8/5/2026, which in Turkey reads as the 8th
22
- * of May. The locale comes from the labels now, and the clock is pinned to 24
23
- * hours so the two passes cannot disagree over "14:32" and "2:32 PM".
15
+ /**
16
+ * When a waiting device asked, in a form that cannot tear on hydration.
17
+ *
18
+ * It used to be a bare `toLocaleString()`, which reads the SERVER's locale
19
+ * while the page renders on the server and the BROWSER's once React takes over
20
+ * — two different strings for the same tile, and React replacing one with the
21
+ * other after mount. It also printed 8/5/2026, which in Turkey reads as the 8th
22
+ * of May. The locale comes from the labels now, and the clock is pinned to 24
23
+ * hours so the two passes cannot disagree over "14:32" and "2:32 PM".
24
24
  */ function formatRequestedAt(value, say) {
25
25
  if (!value) return say.unknown;
26
26
  const when = new Date(value);
@@ -1,15 +1,15 @@
1
- /**
2
- * Every word this page says, so a portal can say them in its own language.
3
- *
4
- * `title` and `subtitle` were already props — which is the tell: an
5
- * installation could rename the heading and nothing underneath it, so the page
6
- * that lists where an account is signed in read "Etkin Cihazlar" over "Manage
7
- * devices that have access to your account", "Last Active", "Trust Score: 80%"
8
- * and "Are you sure you want to revoke access for this device?". This is the
9
- * screen an employee opens when they think somebody else is on their account,
10
- * and every word on it has to be one they can act on.
11
- *
12
- * Defaults stay English, so an installation that passes no labels is unchanged.
1
+ /**
2
+ * Every word this page says, so a portal can say them in its own language.
3
+ *
4
+ * `title` and `subtitle` were already props — which is the tell: an
5
+ * installation could rename the heading and nothing underneath it, so the page
6
+ * that lists where an account is signed in read "Etkin Cihazlar" over "Manage
7
+ * devices that have access to your account", "Last Active", "Trust Score: 80%"
8
+ * and "Are you sure you want to revoke access for this device?". This is the
9
+ * screen an employee opens when they think somebody else is on their account,
10
+ * and every word on it has to be one they can act on.
11
+ *
12
+ * Defaults stay English, so an installation that passes no labels is unchanged.
13
13
  */ export const DEFAULT_DEVICES_PAGE_LABELS = {
14
14
  title: 'Active Devices',
15
15
  subtitle: 'Manage devices that have access to your account',
@@ -1,11 +1,11 @@
1
- /**
2
- * Every word this page says, so a portal can say them in its own language.
3
- *
4
- * `title` and `subtitle` were already props; everything under them was English
5
- * — including the whole success state, which is the only screen somebody who
6
- * has lost their password actually reads.
7
- *
8
- * Defaults stay English, so nothing that does not pass labels changes.
1
+ /**
2
+ * Every word this page says, so a portal can say them in its own language.
3
+ *
4
+ * `title` and `subtitle` were already props; everything under them was English
5
+ * — including the whole success state, which is the only screen somebody who
6
+ * has lost their password actually reads.
7
+ *
8
+ * Defaults stay English, so nothing that does not pass labels changes.
9
9
  */ export const DEFAULT_FORGOT_PASSWORD_LABELS = {
10
10
  emailLabel: 'Email',
11
11
  emailPlaceholder: 'you@example.com',
@@ -195,11 +195,11 @@ export function FormField({ column, config, value, onChange, error, size = 'md',
195
195
  children: renderInput()
196
196
  });
197
197
  }
198
- /**
199
- * The values a dropdown offers. Without a contract these were the raw database
200
- * enum members with their underscores taken out — `in_progress` shown to a
201
- * Turkish employee as "In Progress" — so they go through `optionLabel`, which
202
- * an installation can point at its own words.
198
+ /**
199
+ * The values a dropdown offers. Without a contract these were the raw database
200
+ * enum members with their underscores taken out — `in_progress` shown to a
201
+ * Turkish employee as "In Progress" — so they go through `optionLabel`, which
202
+ * an installation can point at its own words.
203
203
  */ function getSelectOptions(column, say, locale, customOptions) {
204
204
  if (customOptions) {
205
205
  return customOptions;
@@ -211,15 +211,15 @@ export function getDefaultValue(column) {
211
211
  return '';
212
212
  }
213
213
  }
214
- /**
215
- * Turns a database name into something readable — `first_name` into
216
- * "First Name".
217
- *
218
- * The locale is not decoration: `toUpperCase()` applies English casing rules
219
- * wherever it runs, so a column named `iban` came out "Iban" on a Turkish
220
- * portal where the language wants "İban". Passing the locale makes the first
221
- * letter the one the reader's language uses, and makes the server render and
222
- * the browser render agree on it.
214
+ /**
215
+ * Turns a database name into something readable — `first_name` into
216
+ * "First Name".
217
+ *
218
+ * The locale is not decoration: `toUpperCase()` applies English casing rules
219
+ * wherever it runs, so a column named `iban` came out "Iban" on a Turkish
220
+ * portal where the language wants "İban". Passing the locale makes the first
221
+ * letter the one the reader's language uses, and makes the server render and
222
+ * the browser render agree on it.
223
223
  */ export function formatLabel(name, locale) {
224
224
  return name.replace(/_/g, ' ').replace(/([a-z])([A-Z])/g, '$1 $2').replace(/\b\w/g, (char)=>locale ? char.toLocaleUpperCase(locale) : char.toUpperCase());
225
225
  }
@@ -7,14 +7,14 @@ import { ConnectionOauthFields } from './ConnectionOauthFields';
7
7
  import { usesHeaderName, usesQueryParam } from './connectionDraft';
8
8
  import { describedBy } from './formSupport';
9
9
  import { Field } from './Primitives';
10
- /**
11
- * How the connection proves who it is.
12
- *
13
- * Only the boxes the chosen auth type reads are on screen. A form that showed
14
- * all of them would invite an operator to fill in a token URL that a bearer
15
- * connection never looks at, and then to spend an afternoon on why it changed
16
- * nothing. The secrets themselves are not here — they live in CredentialFields,
17
- * because they are written and never read back.
10
+ /**
11
+ * How the connection proves who it is.
12
+ *
13
+ * Only the boxes the chosen auth type reads are on screen. A form that showed
14
+ * all of them would invite an operator to fill in a token URL that a bearer
15
+ * connection never looks at, and then to spend an afternoon on why it changed
16
+ * nothing. The secrets themselves are not here — they live in CredentialFields,
17
+ * because they are written and never read back.
18
18
  */ const theme = integrationsPageTheme;
19
19
  export function ConnectionAuthFields(props) {
20
20
  const labels = useLabels();
@@ -5,9 +5,9 @@ import { useLabels } from '../text/context';
5
5
  import { integrationsPageTheme } from '../theme';
6
6
  import { describedBy } from './formSupport';
7
7
  import { Field } from './Primitives';
8
- /**
9
- * What the connection IS: its name, where it lives, and the two switches that
10
- * decide whether it is used and how carefully.
8
+ /**
9
+ * What the connection IS: its name, where it lives, and the two switches that
10
+ * decide whether it is used and how carefully.
11
11
  */ const theme = integrationsPageTheme;
12
12
  const CHECKBOX = 'h-4 w-4 shrink-0 accent-sky-600 dark:accent-sky-500';
13
13
  export function ConnectionBasicFields({ draft, errors, disabled, onChange }) {
@@ -5,29 +5,29 @@ import { useIntegrationsStore } from '../store';
5
5
  import { useLabels } from '../text/context';
6
6
  import { integrationsPageTheme as theme } from '../theme';
7
7
  import { Notice } from './Primitives';
8
- /**
9
- * Taking one whole integration somewhere else.
10
- *
11
- * A connection is the address, the calls it makes, the parameters those calls
12
- * take from each other, and the mappings that turn the answers into rows.
13
- * Rebuilding that by hand in a second environment is hours of work and a fresh
14
- * chance to get one field wrong in a way nobody notices until an import writes
15
- * it. So it travels as one file.
16
- *
17
- * ## Why this is not next to Import
18
- *
19
- * It was, and it could not be pressed. Both buttons lived in the connection
20
- * rail, and Export is only meaningful once a connection is CHOSEN — but
21
- * choosing one replaces the rail with the connection's own screens, taking the
22
- * button with it. So the button existed, was correct, and was reachable only in
23
- * the state where it was disabled.
24
- *
25
- * Import belongs where there is nothing chosen yet, because that is when you
26
- * bring one in. Export belongs here, on the connection being exported.
27
- *
28
- * The file carries NO credentials — deliberately, and it says so on both sides,
29
- * because a connection that arrives looking configured and cannot authenticate
30
- * is a confusing half hour otherwise.
8
+ /**
9
+ * Taking one whole integration somewhere else.
10
+ *
11
+ * A connection is the address, the calls it makes, the parameters those calls
12
+ * take from each other, and the mappings that turn the answers into rows.
13
+ * Rebuilding that by hand in a second environment is hours of work and a fresh
14
+ * chance to get one field wrong in a way nobody notices until an import writes
15
+ * it. So it travels as one file.
16
+ *
17
+ * ## Why this is not next to Import
18
+ *
19
+ * It was, and it could not be pressed. Both buttons lived in the connection
20
+ * rail, and Export is only meaningful once a connection is CHOSEN — but
21
+ * choosing one replaces the rail with the connection's own screens, taking the
22
+ * button with it. So the button existed, was correct, and was reachable only in
23
+ * the state where it was disabled.
24
+ *
25
+ * Import belongs where there is nothing chosen yet, because that is when you
26
+ * bring one in. Export belongs here, on the connection being exported.
27
+ *
28
+ * The file carries NO credentials — deliberately, and it says so on both sides,
29
+ * because a connection that arrives looking configured and cannot authenticate
30
+ * is a confusing half hour otherwise.
31
31
  */ /** A filename somebody can still recognise a week later. */ const fileNameFor = (slug)=>`integration-${slug || 'connection'}.json`;
32
32
  export function ConnectionExport({ actions, source }) {
33
33
  const labels = useLabels();
@@ -10,12 +10,12 @@ import { draftFromSource, draftPatchFromSource, draftToSource, emptyConnectionDr
10
10
  import { errorText } from './formSupport';
11
11
  import { Badge } from './Primitives';
12
12
  import { CardSkeleton } from './Skeletons';
13
- /**
14
- * Add or edit one connection.
15
- *
16
- * The form holds a draft rather than editing the record in place, so abandoning
17
- * a half-finished change costs nothing and the saved record is never a mixture
18
- * of what was stored and what is being typed.
13
+ /**
14
+ * Add or edit one connection.
15
+ *
16
+ * The form holds a draft rather than editing the record in place, so abandoning
17
+ * a half-finished change costs nothing and the saved record is never a mixture
18
+ * of what was stored and what is being typed.
19
19
  */ const theme = integrationsPageTheme;
20
20
  export function ConnectionForm({ actions, source, loading = false, onSaved }) {
21
21
  const t = useLabels().errors;
@@ -59,22 +59,22 @@ export function ConnectionForm({ actions, source, loading = false, onSaved }) {
59
59
  // it into the list, and selecting an id the list does not hold is the
60
60
  // state every card below renders a skeleton for.
61
61
  onSaved?.(saved);
62
- /**
63
- * The boxes are re-derived from what was actually STORED.
64
- *
65
- * The effect above resets them only when the id changes, so a create
66
- * showed the truth and an edit never did. Two ways that was visible:
67
- * emptying "Timeout" and saving left the box empty while the connection
68
- * went on timing out at the stored value — the draft omits a blank
69
- * timeout, so the patch never mentions it and the server rightly keeps
70
- * what it had; and a trailing space in the name was trimmed on the way
71
- * out, so the switcher above showed "Acme" while the box below still
72
- * read "Acme ". One screen, disagreeing with itself, until F5.
73
- *
74
- * MERGED rather than replaced: a field-scoped patch claim can strip
75
- * columns out of the reply, and re-deriving wholesale from a partial
76
- * record would blank the boxes those columns fill. Nothing can have been
77
- * typed in the meantime — every field is disabled while `saving`.
62
+ /**
63
+ * The boxes are re-derived from what was actually STORED.
64
+ *
65
+ * The effect above resets them only when the id changes, so a create
66
+ * showed the truth and an edit never did. Two ways that was visible:
67
+ * emptying "Timeout" and saving left the box empty while the connection
68
+ * went on timing out at the stored value — the draft omits a blank
69
+ * timeout, so the patch never mentions it and the server rightly keeps
70
+ * what it had; and a trailing space in the name was trimmed on the way
71
+ * out, so the switcher above showed "Acme" while the box below still
72
+ * read "Acme ". One screen, disagreeing with itself, until F5.
73
+ *
74
+ * MERGED rather than replaced: a field-scoped patch claim can strip
75
+ * columns out of the reply, and re-deriving wholesale from a partial
76
+ * record would blank the boxes those columns fill. Nothing can have been
77
+ * typed in the meantime — every field is disabled while `saving`.
78
78
  */ if (source) setDraft((current)=>({
79
79
  ...current,
80
80
  ...draftPatchFromSource(saved)
@@ -9,13 +9,13 @@ import { ConnectionTransfer } from './ConnectionTransfer';
9
9
  import { Badge, Field, Notice } from './Primitives';
10
10
  import { ListSkeleton } from './Skeletons';
11
11
  import { useInfiniteList } from './useInfiniteList';
12
- /**
13
- * The rail of connections.
14
- *
15
- * The server owns the list: what the operator types goes back out as a `search`
16
- * on the next request, and the next page arrives when the sentinel comes into
17
- * view. Nothing here narrows what has already been fetched, so the rail behaves
18
- * the same at four connections and at four hundred.
12
+ /**
13
+ * The rail of connections.
14
+ *
15
+ * The server owns the list: what the operator types goes back out as a `search`
16
+ * on the next request, and the next page arrives when the sentinel comes into
17
+ * view. Nothing here narrows what has already been fetched, so the rail behaves
18
+ * the same at four connections and at four hundred.
19
19
  */ const theme = integrationsPageTheme;
20
20
  const PAGE_SIZE = 20;
21
21
  const SEARCH_DEBOUNCE_MS = 300;