nucleus-core-ts 0.9.806 → 0.9.807

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.
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useLabels } from '../text/context';
3
4
  import { integrationsPageTheme } from '../theme';
4
5
  import { AUTH_TYPE_OPTIONS, authTypeHint, toAuthType } from './authOptions';
5
6
  import { ConnectionOauthFields } from './ConnectionOauthFields';
@@ -16,15 +17,16 @@ import { Field } from './Primitives';
16
17
  * because they are written and never read back.
17
18
  */ const theme = integrationsPageTheme;
18
19
  export function ConnectionAuthFields(props) {
20
+ const labels = useLabels();
19
21
  const { draft, disabled, onChange } = props;
20
22
  return /*#__PURE__*/ _jsxs("section", {
21
- "aria-label": "Authentication",
23
+ "aria-label": labels.auth.sectionLabel,
22
24
  className: "flex flex-col gap-3",
23
25
  children: [
24
26
  /*#__PURE__*/ _jsx(Field, {
25
27
  hint: authTypeHint(draft.authType),
26
28
  htmlFor: "connection-auth-type",
27
- label: "Auth type",
29
+ label: labels.auth.type,
28
30
  children: /*#__PURE__*/ _jsx("select", {
29
31
  "aria-describedby": describedBy('connection-auth-type', true, false),
30
32
  className: theme.field.input,
@@ -44,9 +46,9 @@ export function ConnectionAuthFields(props) {
44
46
  })
45
47
  }),
46
48
  usesHeaderName(draft.authType) ? /*#__PURE__*/ _jsx(Field, {
47
- hint: "Empty means Authorization. Set it when the service reads the credential from a header of its own.",
49
+ hint: labels.auth.headerNameHint,
48
50
  htmlFor: "connection-auth-header",
49
- label: "Header name",
51
+ label: labels.auth.headerName,
50
52
  children: /*#__PURE__*/ _jsx("input", {
51
53
  "aria-describedby": describedBy('connection-auth-header', true, false),
52
54
  className: theme.field.input,
@@ -55,15 +57,15 @@ export function ConnectionAuthFields(props) {
55
57
  onChange: (event)=>onChange({
56
58
  authHeaderName: event.target.value
57
59
  }),
58
- placeholder: "X-Api-Key",
60
+ placeholder: labels.auth.headerNamePlaceholder,
59
61
  type: "text",
60
62
  value: draft.authHeaderName
61
63
  })
62
64
  }) : null,
63
65
  usesQueryParam(draft.authType) ? /*#__PURE__*/ _jsx(Field, {
64
- hint: "Use this instead of a header when the key belongs in the query string. Fill in one or the other, not both.",
66
+ hint: labels.auth.queryParamHint,
65
67
  htmlFor: "connection-auth-query",
66
- label: "Query parameter",
68
+ label: labels.auth.queryParam,
67
69
  children: /*#__PURE__*/ _jsx("input", {
68
70
  "aria-describedby": describedBy('connection-auth-query', true, false),
69
71
  className: theme.field.input,
@@ -72,7 +74,7 @@ export function ConnectionAuthFields(props) {
72
74
  onChange: (event)=>onChange({
73
75
  authQueryParam: event.target.value
74
76
  }),
75
- placeholder: "api_key",
77
+ placeholder: labels.auth.queryParamPlaceholder,
76
78
  type: "text",
77
79
  value: draft.authQueryParam
78
80
  })
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useLabels } from '../text/context';
3
4
  import { integrationsPageTheme } from '../theme';
4
5
  import { CLIENT_AUTH_OPTIONS, GRANT_TYPE_OPTIONS, toClientAuth, toGrantType } from './authOptions';
5
6
  import { usesOauth } from './connectionDraft';
@@ -13,14 +14,15 @@ import { Field } from './Primitives';
13
14
  * place instead of at every field.
14
15
  */ const theme = integrationsPageTheme;
15
16
  export function ConnectionOauthFields({ draft, errors, disabled, onChange }) {
17
+ const labels = useLabels();
16
18
  if (!usesOauth(draft.authType)) return null;
17
19
  return /*#__PURE__*/ _jsxs(_Fragment, {
18
20
  children: [
19
21
  /*#__PURE__*/ _jsx(Field, {
20
22
  error: errors.tokenUrl,
21
- hint: "The full URL the token is fetched from. Same rule as the base URL: any scheme, http included.",
23
+ hint: labels.auth.tokenUrlHint,
22
24
  htmlFor: "connection-token-url",
23
- label: "Token URL",
25
+ label: labels.auth.tokenUrl,
24
26
  children: /*#__PURE__*/ _jsx("input", {
25
27
  "aria-describedby": describedBy('connection-token-url', true, Boolean(errors.tokenUrl)),
26
28
  className: theme.field.input,
@@ -29,15 +31,15 @@ export function ConnectionOauthFields({ draft, errors, disabled, onChange }) {
29
31
  onChange: (event)=>onChange({
30
32
  tokenUrl: event.target.value
31
33
  }),
32
- placeholder: "https://api.example.com/oauth/token",
34
+ placeholder: labels.auth.tokenUrlPlaceholder,
33
35
  type: "text",
34
36
  value: draft.tokenUrl
35
37
  })
36
38
  }),
37
39
  /*#__PURE__*/ _jsx(Field, {
38
- hint: "Client credentials calls as the application. Password calls as a named user and needs that user's name and password.",
40
+ hint: labels.auth.grantTypeHint,
39
41
  htmlFor: "connection-grant-type",
40
- label: "Grant type",
42
+ label: labels.auth.grantType,
41
43
  children: /*#__PURE__*/ _jsx("select", {
42
44
  "aria-describedby": describedBy('connection-grant-type', true, false),
43
45
  className: theme.field.input,
@@ -58,7 +60,7 @@ export function ConnectionOauthFields({ draft, errors, disabled, onChange }) {
58
60
  }),
59
61
  /*#__PURE__*/ _jsx(Field, {
60
62
  htmlFor: "connection-client-id",
61
- label: "Client ID",
63
+ label: labels.auth.clientId,
62
64
  children: /*#__PURE__*/ _jsx("input", {
63
65
  className: theme.field.input,
64
66
  disabled: disabled,
@@ -66,14 +68,14 @@ export function ConnectionOauthFields({ draft, errors, disabled, onChange }) {
66
68
  onChange: (event)=>onChange({
67
69
  oauthClientId: event.target.value
68
70
  }),
69
- placeholder: "integration-client",
71
+ placeholder: labels.auth.clientIdPlaceholder,
70
72
  type: "text",
71
73
  value: draft.oauthClientId
72
74
  })
73
75
  }),
74
76
  draft.oauthGrantType === 'password' ? /*#__PURE__*/ _jsx(Field, {
75
77
  htmlFor: "connection-oauth-username",
76
- label: "User name",
78
+ label: labels.auth.username,
77
79
  children: /*#__PURE__*/ _jsx("input", {
78
80
  autoComplete: "off",
79
81
  className: theme.field.input,
@@ -82,15 +84,15 @@ export function ConnectionOauthFields({ draft, errors, disabled, onChange }) {
82
84
  onChange: (event)=>onChange({
83
85
  oauthUsername: event.target.value
84
86
  }),
85
- placeholder: "service-account",
87
+ placeholder: labels.auth.usernamePlaceholder,
86
88
  type: "text",
87
89
  value: draft.oauthUsername
88
90
  })
89
91
  }) : null,
90
92
  /*#__PURE__*/ _jsx(Field, {
91
- hint: "Space-separated. Leave it empty to take whatever the token endpoint grants by default.",
93
+ hint: labels.auth.scopeHint,
92
94
  htmlFor: "connection-scope",
93
- label: "Scope",
95
+ label: labels.auth.scope,
94
96
  children: /*#__PURE__*/ _jsx("input", {
95
97
  "aria-describedby": describedBy('connection-scope', true, false),
96
98
  className: theme.field.input,
@@ -99,7 +101,7 @@ export function ConnectionOauthFields({ draft, errors, disabled, onChange }) {
99
101
  onChange: (event)=>onChange({
100
102
  oauthScope: event.target.value
101
103
  }),
102
- placeholder: "read:records",
104
+ placeholder: labels.auth.scopePlaceholder,
103
105
  type: "text",
104
106
  value: draft.oauthScope
105
107
  })
@@ -107,7 +109,7 @@ export function ConnectionOauthFields({ draft, errors, disabled, onChange }) {
107
109
  /*#__PURE__*/ _jsx(Field, {
108
110
  hint: "Where the client ID and secret go on the token request. A server accepts one or the other; if the token call comes back with an invalid-client error, try the other.",
109
111
  htmlFor: "connection-client-auth",
110
- label: "Client authentication",
112
+ label: labels.auth.clientAuth,
111
113
  children: /*#__PURE__*/ _jsx("select", {
112
114
  "aria-describedby": describedBy('connection-client-auth', true, false),
113
115
  className: theme.field.input,
@@ -2,6 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useEffectEvent, useState } from 'react';
4
4
  import { cn } from '../../../utils/cn';
5
+ import { useLabels } from '../text/context';
5
6
  import { integrationsPageTheme } from '../theme';
6
7
  import { errorText } from './formSupport';
7
8
  import { Badge, Notice } from './Primitives';
@@ -15,6 +16,7 @@ import { CardSkeleton } from './Skeletons';
15
16
  * sends the operator back to guessing.
16
17
  */ const theme = integrationsPageTheme;
17
18
  export function ConnectionTest({ actions, source, loading = false }) {
19
+ const labels = useLabels();
18
20
  const [testing, setTesting] = useState(false);
19
21
  const [result, setResult] = useState(null);
20
22
  // A result describes the connection it was run against. Leaving it up under
@@ -45,7 +47,7 @@ export function ConnectionTest({ actions, source, loading = false }) {
45
47
  };
46
48
  if (loading) return /*#__PURE__*/ _jsx(CardSkeleton, {});
47
49
  return /*#__PURE__*/ _jsxs("section", {
48
- "aria-label": "Connection test",
50
+ "aria-label": labels.auth.testHeading,
49
51
  className: theme.card.wrapper,
50
52
  children: [
51
53
  /*#__PURE__*/ _jsxs("div", {
@@ -53,7 +55,7 @@ export function ConnectionTest({ actions, source, loading = false }) {
53
55
  children: [
54
56
  /*#__PURE__*/ _jsx("h2", {
55
57
  className: theme.card.title,
56
- children: "Connection test"
58
+ children: labels.auth.testHeading
57
59
  }),
58
60
  result ? /*#__PURE__*/ _jsx(Badge, {
59
61
  tone: result.ok ? 'success' : 'danger',
@@ -76,13 +78,13 @@ export function ConnectionTest({ actions, source, loading = false }) {
76
78
  children: "Save the connection first — there is nothing to call yet."
77
79
  }),
78
80
  result?.ok ? /*#__PURE__*/ _jsxs(Notice, {
79
- title: "Connection succeeded",
81
+ title: labels.auth.testOkTitle,
80
82
  tone: "info",
81
83
  children: [
82
84
  /*#__PURE__*/ _jsx("p", {
83
85
  children: /*#__PURE__*/ _jsx(Badge, {
84
86
  tone: "success",
85
- children: "Reachable"
87
+ children: labels.auth.testOkBadge
86
88
  })
87
89
  }),
88
90
  result.detail ? /*#__PURE__*/ _jsx("p", {
@@ -92,7 +94,7 @@ export function ConnectionTest({ actions, source, loading = false }) {
92
94
  ]
93
95
  }) : null,
94
96
  result && !result.ok ? /*#__PURE__*/ _jsx(Notice, {
95
- title: "Connection failed",
97
+ title: labels.auth.testFailedTitle,
96
98
  tone: "danger",
97
99
  children: /*#__PURE__*/ _jsx("p", {
98
100
  className: cn(theme.notice.body, 'whitespace-pre-wrap break-words font-mono'),
@@ -2,6 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useEffectEvent, useState } from 'react';
4
4
  import { useIntegrationsStore } from '../store';
5
+ import { useLabels } from '../text/context';
5
6
  import { integrationsPageTheme } from '../theme';
6
7
  import { CredentialSlotRow } from './CredentialSlotRow';
7
8
  import { hintFromResult, patchFor, slotsForSource, storedHint } from './credentialSlots';
@@ -18,6 +19,7 @@ import { CardSkeleton } from './Skeletons';
18
19
  * button per field.
19
20
  */ const theme = integrationsPageTheme;
20
21
  export function CredentialFields({ actions, source, loading = false }) {
22
+ const labels = useLabels();
21
23
  const store = useIntegrationsStore();
22
24
  const [values, setValues] = useState({});
23
25
  const [hints, setHints] = useState({});
@@ -39,10 +41,10 @@ export function CredentialFields({ actions, source, loading = false }) {
39
41
  if (loading) return /*#__PURE__*/ _jsx(CardSkeleton, {});
40
42
  if (!source) {
41
43
  return /*#__PURE__*/ _jsx(Notice, {
42
- title: "Save the connection first",
44
+ title: labels.auth.saveFirstTitle,
43
45
  tone: "info",
44
46
  children: /*#__PURE__*/ _jsx("p", {
45
- children: "Secrets are stored against a saved connection, so there is somewhere to put them."
47
+ children: labels.auth.saveFirstBody
46
48
  })
47
49
  });
48
50
  }
@@ -114,21 +116,21 @@ export function CredentialFields({ actions, source, loading = false }) {
114
116
  });
115
117
  };
116
118
  return /*#__PURE__*/ _jsxs("section", {
117
- "aria-label": "Credentials",
119
+ "aria-label": labels.auth.credentialsHeading,
118
120
  className: theme.card.wrapper,
119
121
  children: [
120
122
  /*#__PURE__*/ _jsx("div", {
121
123
  className: theme.card.header,
122
124
  children: /*#__PURE__*/ _jsx("h2", {
123
125
  className: theme.card.title,
124
- children: "Credentials"
126
+ children: labels.auth.credentialsHeading
125
127
  })
126
128
  }),
127
129
  /*#__PURE__*/ _jsxs("div", {
128
130
  className: theme.card.body,
129
131
  children: [
130
132
  /*#__PURE__*/ _jsx(Notice, {
131
- title: "Written once, never read back",
133
+ title: labels.auth.writeOnlyTitle,
132
134
  tone: "info",
133
135
  children: /*#__PURE__*/ _jsx("p", {
134
136
  children: "A value typed here is stored and from then on only ever sent to the service. It is not returned to this screen, or to any other, no matter who asks — all that comes back is a masked hint. Leave a box empty to keep whatever is already stored."
@@ -2,6 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useEffectEvent, useState } from 'react';
4
4
  import { useIntegrationsStore } from '../store';
5
+ import { useLabels } from '../text/context';
5
6
  import { integrationsPageTheme } from '../theme';
6
7
  import { EndpointFormFields } from './EndpointFormFields';
7
8
  import { formatJsonObject, parseJsonObject } from './jsonObjectField';
@@ -17,6 +18,7 @@ import { pathParamNames } from './pathParams';
17
18
  * a list page arriving in the background.
18
19
  */ const theme = integrationsPageTheme;
19
20
  export function EndpointForm({ sourceId, endpoint, actions, onSaved, onDeleted, onCancel }) {
21
+ const labels = useLabels();
20
22
  const store = useIntegrationsStore();
21
23
  const [saving, setSaving] = useState(false);
22
24
  const [deleting, setDeleting] = useState(false);
@@ -123,7 +125,7 @@ export function EndpointForm({ sourceId, endpoint, actions, onSaved, onDeleted,
123
125
  className: theme.card.header,
124
126
  children: /*#__PURE__*/ _jsx("h3", {
125
127
  className: theme.card.title,
126
- children: endpoint ? 'Edit endpoint' : 'New endpoint'
128
+ children: endpoint ? labels.endpoints.editTitle : labels.endpoints.newTitle
127
129
  })
128
130
  }),
129
131
  /*#__PURE__*/ _jsxs("div", {
@@ -163,20 +165,20 @@ export function EndpointForm({ sourceId, endpoint, actions, onSaved, onDeleted,
163
165
  disabled: busy,
164
166
  onClick: remove,
165
167
  type: "button",
166
- children: deleting ? 'Deleting…' : 'Delete'
168
+ children: deleting ? labels.common.deleting : labels.common.delete
167
169
  }) : null,
168
170
  /*#__PURE__*/ _jsx("button", {
169
171
  className: theme.button.secondary,
170
172
  disabled: busy,
171
173
  onClick: onCancel,
172
174
  type: "button",
173
- children: "Cancel"
175
+ children: labels.common.cancel
174
176
  }),
175
177
  /*#__PURE__*/ _jsx("button", {
176
178
  className: theme.button.primary,
177
179
  disabled: busy || !canSave,
178
180
  type: "submit",
179
- children: saving ? 'Saving…' : 'Save endpoint'
181
+ children: saving ? labels.common.saving : labels.endpoints.save
180
182
  })
181
183
  ]
182
184
  })
@@ -107,7 +107,7 @@ export function EndpointList({ sourceId, actions, onNewEndpoint, onSelect, reloa
107
107
  }),
108
108
  /*#__PURE__*/ _jsx("p", {
109
109
  className: theme.header.subtitle,
110
- children: list.total === 1 ? '1 endpoint' : `${list.total} endpoints`
110
+ children: list.total === 1 ? labels.endpoints.countOne : labels.endpoints.countMany(list.total)
111
111
  })
112
112
  ]
113
113
  }),
@@ -117,7 +117,7 @@ export function EndpointList({ sourceId, actions, onNewEndpoint, onSelect, reloa
117
117
  className: theme.button.primary,
118
118
  onClick: handleNew,
119
119
  type: "button",
120
- children: "New endpoint"
120
+ children: labels.endpoints.create
121
121
  })
122
122
  })
123
123
  ]
@@ -153,7 +153,7 @@ export function EndpointList({ sourceId, actions, onNewEndpoint, onSelect, reloa
153
153
  }) : null,
154
154
  !firstLoad && list.items.length === 0 && !list.error ? /*#__PURE__*/ _jsx("p", {
155
155
  className: theme.list.empty,
156
- children: search.length > 0 ? `No endpoint matches “${search}”. Clear the search to see them all.` : 'No endpoints yet. An endpoint is one call this connection can make — a method, a path, and where the records sit in the answer. Start with New endpoint.'
156
+ children: search.length > 0 ? labels.endpoints.emptySearch(search) : labels.endpoints.empty
157
157
  }) : null,
158
158
  list.items.length > 0 ? /*#__PURE__*/ _jsx("ul", {
159
159
  className: theme.list.wrapper,
@@ -225,6 +225,48 @@ export type IntegrationsLabels = {
225
225
  fallbackPlaceholder: string;
226
226
  save: string;
227
227
  };
228
+ /** Authentication, its credentials, and whether the service answers. */
229
+ auth: {
230
+ sectionLabel: string;
231
+ type: string;
232
+ headerName: string;
233
+ headerNameHint: string;
234
+ headerNamePlaceholder: string;
235
+ queryParam: string;
236
+ queryParamHint: string;
237
+ queryParamPlaceholder: string;
238
+ tokenUrl: string;
239
+ tokenUrlHint: string;
240
+ tokenUrlPlaceholder: string;
241
+ grantType: string;
242
+ grantTypeHint: string;
243
+ clientId: string;
244
+ clientIdPlaceholder: string;
245
+ username: string;
246
+ usernamePlaceholder: string;
247
+ scope: string;
248
+ scopeHint: string;
249
+ scopePlaceholder: string;
250
+ clientAuth: string;
251
+ clientAuthHint: string;
252
+ credentialsHeading: string;
253
+ saveFirstTitle: string;
254
+ saveFirstBody: string;
255
+ writeOnlyTitle: string;
256
+ writeOnlyBody: string;
257
+ saveCredentials: string;
258
+ notSet: string;
259
+ stored: string;
260
+ clear: string;
261
+ testHeading: string;
262
+ testRun: string;
263
+ testOkTitle: string;
264
+ testOkBadge: string;
265
+ testFailedTitle: string;
266
+ testNotReachable: string;
267
+ testSaveFirst: string;
268
+ testCalls: (url: string) => string;
269
+ };
228
270
  /** The long form of each write mode, for the picker. */
229
271
  writeModeFull: {
230
272
  upsert: string;
@@ -215,6 +215,47 @@
215
215
  fallbackPlaceholder: 'Used when the source is empty',
216
216
  save: 'Save mapping'
217
217
  },
218
+ auth: {
219
+ sectionLabel: 'Authentication',
220
+ type: 'How we prove who we are',
221
+ headerName: 'Header name',
222
+ headerNameHint: 'Empty means Authorization. Set it when the service reads the credential from a header of its own.',
223
+ headerNamePlaceholder: 'X-Api-Key',
224
+ queryParam: 'Query parameter',
225
+ queryParamHint: 'Use this instead of a header when the key belongs in the query string. Fill in one or the other, not both.',
226
+ queryParamPlaceholder: 'api_key',
227
+ tokenUrl: 'Token address',
228
+ tokenUrlHint: 'The full URL the token is fetched from. Same rule as the base URL: any scheme, http included.',
229
+ tokenUrlPlaceholder: 'https://api.example.com/oauth/token',
230
+ grantType: 'Grant type',
231
+ grantTypeHint: "Client credentials calls as the application. Password calls as a named user and needs that user's name and password.",
232
+ clientId: 'Client ID',
233
+ clientIdPlaceholder: 'integration-client',
234
+ username: 'User name',
235
+ usernamePlaceholder: 'service-account',
236
+ scope: 'Scope',
237
+ scopeHint: 'Space-separated. Leave it empty to take whatever the token endpoint grants by default.',
238
+ scopePlaceholder: 'read:records',
239
+ clientAuth: 'Client authentication',
240
+ clientAuthHint: 'Where the client ID and secret go on the token request. A server accepts one or the other; if the token call comes back with an invalid-client error, try the other.',
241
+ credentialsHeading: 'Credentials',
242
+ saveFirstTitle: 'Save the connection first',
243
+ saveFirstBody: 'Secrets are stored against a saved connection, so there is somewhere to put them.',
244
+ writeOnlyTitle: 'Written once, never read back',
245
+ writeOnlyBody: 'A value typed here is stored and from then on only ever sent to the service. It is not returned to this screen, or to any other, no matter who asks — all that comes back is a masked hint. Leave a box empty to keep whatever is already stored.',
246
+ saveCredentials: 'Save credentials',
247
+ notSet: 'Not set',
248
+ stored: 'Stored',
249
+ clear: 'Clear',
250
+ testHeading: 'Does it answer?',
251
+ testRun: 'Test the connection',
252
+ testOkTitle: 'Connection succeeded',
253
+ testOkBadge: 'Reachable',
254
+ testFailedTitle: 'Connection failed',
255
+ testNotReachable: 'Not reachable',
256
+ testSaveFirst: 'Save the connection first — there is nothing to call yet.',
257
+ testCalls: (url)=>`Calls ${url} with the settings and credentials as they are stored right now.`
258
+ },
218
259
  writeModeFull: {
219
260
  upsert: 'Upsert — update what matches, insert the rest',
220
261
  append: 'Append — insert every fetched record',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nucleus-core-ts",
3
- "version": "0.9.806",
3
+ "version": "0.9.807",
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",