nucleus-core-ts 0.9.912 → 0.9.913

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.
package/dist/.build-ok CHANGED
@@ -1 +1 @@
1
- 0.9.912
1
+ 0.9.913
@@ -19,13 +19,13 @@ export function CredentialSlotRow({ slot, source, value, maskedHint, disabled, o
19
19
  const t = useLabels().errors;
20
20
  const labels = useLabels();
21
21
  const id = `credential-${slot}`;
22
- const label = slotLabel(slot, source);
22
+ const label = slotLabel(slot, source, labels.ui);
23
23
  const stored = maskedHint !== null && maskedHint.length > 0;
24
24
  return /*#__PURE__*/ _jsxs("div", {
25
25
  className: "flex flex-col gap-2",
26
26
  children: [
27
27
  /*#__PURE__*/ _jsx(Field, {
28
- hint: slotHint(slot, source),
28
+ hint: slotHint(slot, source, labels.ui),
29
29
  htmlFor: id,
30
30
  label: label,
31
31
  children: /*#__PURE__*/ _jsx("input", {
@@ -165,7 +165,7 @@ export function EndpointList({ sourceId, actions, onNewEndpoint, onSelect, reloa
165
165
  className: theme.button.ghost,
166
166
  onClick: list.reload,
167
167
  type: "button",
168
- children: "Try again"
168
+ children: labels.ui.tryAgain
169
169
  })
170
170
  ]
171
171
  }) : null,
@@ -240,7 +240,7 @@ export function MappingAccountFields({ value, targetFields, targets, disabled, o
240
240
  ]
241
241
  }),
242
242
  type: "button",
243
- children: "Add a membership"
243
+ children: labels.ui.addMembership
244
244
  })
245
245
  ]
246
246
  }),
@@ -287,7 +287,7 @@ export function MappingEditor({ mapping, targets, targetsLoading, endpoints, fre
287
287
  disabled: busy,
288
288
  onClick: ()=>onRunImport(draft),
289
289
  type: "button",
290
- children: "Preview and import"
290
+ children: labels.ui.previewAndImport
291
291
  }) : null,
292
292
  /*#__PURE__*/ _jsx("button", {
293
293
  className: theme.button.primary,
@@ -6,6 +6,7 @@ import { useIntegrationsStore } from '../store';
6
6
  import { useLabels } from '../text/context';
7
7
  import { integrationsPageTheme } from '../theme';
8
8
  import { Badge, Field, Notice } from './Primitives';
9
+ import { formatMoment } from './runFormat';
9
10
  import { ListSkeleton } from './Skeletons';
10
11
  import { useInfiniteList } from './useInfiniteList';
11
12
  /**
@@ -22,10 +23,18 @@ const WRITE_MODE_TONE = {
22
23
  append: 'neutral',
23
24
  replace: 'danger'
24
25
  };
25
- function describeLastRun(value) {
26
- if (!value) return 'Never run';
26
+ /**
27
+ * When this mapping last ran, in a form that cannot tear on hydration.
28
+ *
29
+ * It used to be `toLocaleString()`, which reads the SERVER's locale and zone on
30
+ * the server and the BROWSER's on the client — two different strings for the
31
+ * same row, and React replacing one with the other after mount. It also meant a
32
+ * Turkish installation was shown 8/2/2026, which in Turkey reads as the 8th of
33
+ * February. `formatMoment` is UTC, fixed-width and labelled as such.
34
+ */ function describeLastRun(value, labels) {
35
+ if (!value) return labels.neverRun;
27
36
  const when = new Date(value);
28
- return Number.isNaN(when.getTime()) ? 'Never run' : `Last run ${when.toLocaleString()}`;
37
+ return Number.isNaN(when.getTime()) ? labels.neverRun : labels.lastRun(formatMoment(value));
29
38
  }
30
39
  export function MappingList({ actions, sourceId, selectedId, reloadToken, onSelect, onRun }) {
31
40
  const t = useLabels().errors;
@@ -150,14 +159,9 @@ export function MappingList({ actions, sourceId, selectedId, reloadToken, onSele
150
159
  children: store.endpointsTotal === 0 ? t.noEndpointsForMapping : labels.mappings.empty
151
160
  }) : /*#__PURE__*/ _jsxs(_Fragment, {
152
161
  children: [
153
- /*#__PURE__*/ _jsxs("p", {
162
+ /*#__PURE__*/ _jsx("p", {
154
163
  className: theme.list.itemMeta,
155
- children: [
156
- list.items.length,
157
- " of ",
158
- list.total,
159
- " shown"
160
- ]
164
+ children: labels.ui.shownOfTotal(list.items.length, list.total)
161
165
  }),
162
166
  /*#__PURE__*/ _jsx("ul", {
163
167
  className: theme.list.wrapper,
@@ -196,19 +200,19 @@ export function MappingList({ actions, sourceId, selectedId, reloadToken, onSele
196
200
  }) : null,
197
201
  /*#__PURE__*/ _jsx("span", {
198
202
  className: theme.list.itemMeta,
199
- children: describeLastRun(mapping.lastRunAt)
203
+ children: describeLastRun(mapping.lastRunAt, labels.ui)
200
204
  })
201
205
  ]
202
206
  })
203
207
  ]
204
208
  }),
205
209
  onRun ? /*#__PURE__*/ _jsx("button", {
206
- "aria-label": `Import ${mapping.name}`,
210
+ "aria-label": labels.ui.runImportFor(mapping.name),
207
211
  className: cn(theme.button.secondary, 'self-center whitespace-nowrap'),
208
212
  onClick: ()=>onRun(mapping),
209
- title: `Preview and import ${mapping.name}`,
213
+ title: labels.ui.previewAndImportFor(mapping.name),
210
214
  type: "button",
211
- children: "Import"
215
+ children: labels.ui.runImport
212
216
  }) : null
213
217
  ]
214
218
  }, mapping.id))
@@ -50,7 +50,7 @@ import { Notice } from './Primitives';
50
50
  children: /*#__PURE__*/ _jsx("h4", {
51
51
  className: theme.card.title,
52
52
  id: `${groupId}-title`,
53
- children: "Parameter values"
53
+ children: labels.ui.parameterValues
54
54
  })
55
55
  }),
56
56
  /*#__PURE__*/ _jsxs("div", {
@@ -112,7 +112,7 @@ export function RunHistory({ actions, mappingId, refreshKey, onRefresh }) {
112
112
  className: theme.button.ghost,
113
113
  onClick: list.reload,
114
114
  type: "button",
115
- children: "Try again"
115
+ children: labels.ui.tryAgain
116
116
  })
117
117
  ]
118
118
  }) : null,
@@ -26,6 +26,7 @@ import { Field } from './Primitives';
26
26
  * somebody leaves in place. Editable — an install with a policy types its own.
27
27
  */ export const DEFAULT_SHARED_PASSWORD = 'ChanGeME2026!';
28
28
  export function RunPasswordField({ column, value, disabled, onChange }) {
29
+ const labels = useLabels();
29
30
  const t = useLabels().account;
30
31
  const uid = useId();
31
32
  const [shown, setShown] = useState(false);
@@ -53,7 +54,7 @@ export function RunPasswordField({ column, value, disabled, onChange }) {
53
54
  disabled: disabled,
54
55
  onClick: ()=>setShown((current)=>!current),
55
56
  type: "button",
56
- children: shown ? 'Hide' : 'Show'
57
+ children: shown ? labels.ui.hideSecret : labels.ui.showSecret
57
58
  })
58
59
  ]
59
60
  })
@@ -81,7 +81,7 @@ export function RunPlanSuggestions({ plan, mapping, onEditMapping }) {
81
81
  className: `${theme.button.secondary} mt-3`,
82
82
  onClick: onEditMapping,
83
83
  type: "button",
84
- children: "Open the mapping"
84
+ children: labels.ui.openTheMapping
85
85
  }) : null
86
86
  ]
87
87
  }) : null,
@@ -115,7 +115,7 @@ export function RunPlanSuggestions({ plan, mapping, onEditMapping }) {
115
115
  className: `${theme.button.secondary} mt-3`,
116
116
  onClick: onEditMapping,
117
117
  type: "button",
118
- children: "Open the mapping"
118
+ children: labels.ui.openTheMapping
119
119
  }) : null
120
120
  ]
121
121
  }, entry.field);
@@ -10,6 +10,7 @@ import { integrationsPageTheme } from '../theme';
10
10
  * SECOND, separate decision — it never rides along on the first click.
11
11
  */ const theme = integrationsPageTheme;
12
12
  export function RunRevertConflicts({ conflicts, message, working, onOverwrite, onDismiss }) {
13
+ const labels = useLabels();
13
14
  const t = useLabels().errors;
14
15
  return /*#__PURE__*/ _jsxs("section", {
15
16
  className: theme.notice.danger,
@@ -56,7 +57,7 @@ export function RunRevertConflicts({ conflicts, message, working, onOverwrite, o
56
57
  disabled: working,
57
58
  onClick: onDismiss,
58
59
  type: "button",
59
- children: "Leave those rows alone"
60
+ children: labels.ui.leaveRowsAlone
60
61
  })
61
62
  ]
62
63
  })
@@ -37,7 +37,7 @@ export function RunsTab({ actions, onSubscribeProgress }) {
37
37
  className: `${theme.button.secondary} mt-3`,
38
38
  onClick: ()=>store.setTab('mappings'),
39
39
  type: "button",
40
- children: "Go to the mappings"
40
+ children: labels.ui.goToMappings
41
41
  })
42
42
  ]
43
43
  }),
@@ -30,5 +30,18 @@ export declare function hintColumnsFor(hints: Partial<Record<CredentialSlot, str
30
30
  export declare function hintFromResult(result: Record<string, string | null>, slot: CredentialSlot): string | null | undefined;
31
31
  /** Which secrets the chosen auth type actually reads. */
32
32
  export declare function slotsForSource(source: IntegrationSource): CredentialSlot[];
33
- export declare function slotLabel(slot: CredentialSlot, source: IntegrationSource): string;
34
- export declare function slotHint(slot: CredentialSlot, source: IntegrationSource): string;
33
+ /** The words come from the installation; which one applies is decided here. */
34
+ export type SlotWords = {
35
+ slotClientSecret: string;
36
+ slotPassword: string;
37
+ slotApiKey: string;
38
+ slotBasic: string;
39
+ slotBearer: string;
40
+ slotHintClientSecret: string;
41
+ slotHintPassword: string;
42
+ slotHintApiKey: string;
43
+ slotHintBasic: string;
44
+ slotHintBearer: string;
45
+ };
46
+ export declare function slotLabel(slot: CredentialSlot, source: IntegrationSource, words: SlotWords): string;
47
+ export declare function slotHint(slot: CredentialSlot, source: IntegrationSource, words: SlotWords): string;
@@ -83,17 +83,17 @@
83
83
  'token'
84
84
  ];
85
85
  }
86
- export function slotLabel(slot, source) {
87
- if (slot === 'oauthClientSecret') return 'Client secret';
88
- if (slot === 'oauthPassword') return 'Password';
89
- if (source.authType === 'api_key') return 'API key';
90
- if (source.authType === 'basic') return 'Basic credential';
91
- return 'Bearer token';
86
+ export function slotLabel(slot, source, words) {
87
+ if (slot === 'oauthClientSecret') return words.slotClientSecret;
88
+ if (slot === 'oauthPassword') return words.slotPassword;
89
+ if (source.authType === 'api_key') return words.slotApiKey;
90
+ if (source.authType === 'basic') return words.slotBasic;
91
+ return words.slotBearer;
92
92
  }
93
- export function slotHint(slot, source) {
94
- if (slot === 'oauthClientSecret') return 'Sent to the token endpoint with the client ID.';
95
- if (slot === 'oauthPassword') return 'The password of the user named above.';
96
- if (source.authType === 'api_key') return 'Sent in the header or query parameter named in the auth section.';
97
- if (source.authType === 'basic') return 'The user name and password pair, as the service expects.';
98
- return 'Sent on every request through this connection.';
93
+ export function slotHint(slot, source, words) {
94
+ if (slot === 'oauthClientSecret') return words.slotHintClientSecret;
95
+ if (slot === 'oauthPassword') return words.slotHintPassword;
96
+ if (source.authType === 'api_key') return words.slotHintApiKey;
97
+ if (source.authType === 'basic') return words.slotHintBasic;
98
+ return words.slotHintBearer;
99
99
  }
@@ -563,6 +563,41 @@ export type IntegrationsLabels = {
563
563
  * irreversible. The short labels were always translatable; the reasoning was
564
564
  * not, which is backwards.
565
565
  */
566
+ /**
567
+ * The last of the words that were typed into the components.
568
+ *
569
+ * A screen half in Turkish reads worse than one entirely in English: the
570
+ * reader stops trusting that the two halves mean the same thing. These are
571
+ * short, which is exactly why they survived three passes.
572
+ */
573
+ ui: {
574
+ tryAgain: string;
575
+ neverRun: string;
576
+ lastRun: (moment: string) => string;
577
+ shownOfTotal: (shown: string | number, total: string | number) => string;
578
+ runImport: string;
579
+ runImportFor: (name: string) => string;
580
+ previewAndImportFor: (name: string) => string;
581
+ parameterValues: string;
582
+ openTheMapping: string;
583
+ leaveRowsAlone: string;
584
+ goToMappings: string;
585
+ addMembership: string;
586
+ previewAndImport: string;
587
+ cancel: string;
588
+ showSecret: string;
589
+ hideSecret: string;
590
+ slotClientSecret: string;
591
+ slotPassword: string;
592
+ slotApiKey: string;
593
+ slotBasic: string;
594
+ slotBearer: string;
595
+ slotHintClientSecret: string;
596
+ slotHintPassword: string;
597
+ slotHintApiKey: string;
598
+ slotHintBasic: string;
599
+ slotHintBearer: string;
600
+ };
566
601
  explain: {
567
602
  exportBundleRebuildsIntegration: string;
568
603
  exportOmitsCredentials: string;
@@ -509,6 +509,34 @@
509
509
  dismiss: 'Dismiss error',
510
510
  remove: 'Remove'
511
511
  },
512
+ ui: {
513
+ tryAgain: 'Try again',
514
+ neverRun: 'Never run',
515
+ lastRun: (moment)=>`Last run ${moment}`,
516
+ shownOfTotal: (shown, total)=>`${shown} of ${total} shown`,
517
+ runImport: 'Import',
518
+ runImportFor: (name)=>`Import ${name}`,
519
+ previewAndImportFor: (name)=>`Preview and import ${name}`,
520
+ parameterValues: 'Parameter values',
521
+ openTheMapping: 'Open the mapping',
522
+ leaveRowsAlone: 'Leave those rows alone',
523
+ goToMappings: 'Go to the mappings',
524
+ addMembership: 'Add a membership',
525
+ previewAndImport: 'Preview and import',
526
+ cancel: 'Cancel',
527
+ showSecret: 'Show',
528
+ hideSecret: 'Hide',
529
+ slotClientSecret: 'Client secret',
530
+ slotPassword: 'Password',
531
+ slotApiKey: 'API key',
532
+ slotBasic: 'Basic credential',
533
+ slotBearer: 'Bearer token',
534
+ slotHintClientSecret: 'Sent to the token endpoint with the client ID.',
535
+ slotHintPassword: 'The password of the user named above.',
536
+ slotHintApiKey: 'Sent in the header or query parameter named in the auth section.',
537
+ slotHintBasic: 'The user name and password pair, as the service expects.',
538
+ slotHintBearer: 'Sent on every request through this connection.'
539
+ },
512
540
  explain: {
513
541
  exportBundleRebuildsIntegration: 'One file holding this connection, its calls and its mappings — enough to rebuild the whole integration in another installation. Bring it in there with Import, on the connections screen.',
514
542
  exportOmitsCredentials: 'Tokens, passwords and keys are left out on purpose. Whatever this connection authenticates with has to be entered again wherever the file lands.',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nucleus-core-ts",
3
- "version": "0.9.912",
3
+ "version": "0.9.913",
4
4
  "description": "Production-ready, enterprise-grade TypeScript framework for building multi-tenant APIs",
5
5
  "author": "Hidayet Can Özcan <hidayetcan@gmail.com>",
6
6
  "license": "SEE LICENSE IN LICENSE",