nucleus-core-ts 0.9.782 → 0.9.783

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 (114) hide show
  1. package/dist/fe/components/IntegrationsPage/components/ConnectionAuthFields.d.ts +2 -0
  2. package/dist/fe/components/IntegrationsPage/components/ConnectionAuthFields.js +85 -0
  3. package/dist/fe/components/IntegrationsPage/components/ConnectionBasicFields.d.ts +2 -0
  4. package/dist/fe/components/IntegrationsPage/components/ConnectionBasicFields.js +165 -0
  5. package/dist/fe/components/IntegrationsPage/components/ConnectionForm.d.ts +10 -0
  6. package/dist/fe/components/IntegrationsPage/components/ConnectionForm.js +112 -0
  7. package/dist/fe/components/IntegrationsPage/components/ConnectionList.d.ts +9 -0
  8. package/dist/fe/components/IntegrationsPage/components/ConnectionList.js +184 -0
  9. package/dist/fe/components/IntegrationsPage/components/ConnectionOauthFields.d.ts +2 -0
  10. package/dist/fe/components/IntegrationsPage/components/ConnectionOauthFields.js +131 -0
  11. package/dist/fe/components/IntegrationsPage/components/ConnectionSettingsTab.d.ts +21 -0
  12. package/dist/fe/components/IntegrationsPage/components/ConnectionSettingsTab.js +49 -0
  13. package/dist/fe/components/IntegrationsPage/components/ConnectionTabs.d.ts +12 -0
  14. package/dist/fe/components/IntegrationsPage/components/ConnectionTabs.js +95 -0
  15. package/dist/fe/components/IntegrationsPage/components/ConnectionTest.d.ts +9 -0
  16. package/dist/fe/components/IntegrationsPage/components/ConnectionTest.js +116 -0
  17. package/dist/fe/components/IntegrationsPage/components/CredentialFields.d.ts +9 -0
  18. package/dist/fe/components/IntegrationsPage/components/CredentialFields.js +171 -0
  19. package/dist/fe/components/IntegrationsPage/components/CredentialSlotRow.d.ts +13 -0
  20. package/dist/fe/components/IntegrationsPage/components/CredentialSlotRow.js +63 -0
  21. package/dist/fe/components/IntegrationsPage/components/EndpointForm.d.ts +11 -0
  22. package/dist/fe/components/IntegrationsPage/components/EndpointForm.js +166 -0
  23. package/dist/fe/components/IntegrationsPage/components/EndpointFormFields.d.ts +19 -0
  24. package/dist/fe/components/IntegrationsPage/components/EndpointFormFields.js +162 -0
  25. package/dist/fe/components/IntegrationsPage/components/EndpointList.d.ts +12 -0
  26. package/dist/fe/components/IntegrationsPage/components/EndpointList.js +205 -0
  27. package/dist/fe/components/IntegrationsPage/components/EndpointSample.d.ts +6 -0
  28. package/dist/fe/components/IntegrationsPage/components/EndpointSample.js +204 -0
  29. package/dist/fe/components/IntegrationsPage/components/EndpointsTab.d.ts +5 -0
  30. package/dist/fe/components/IntegrationsPage/components/EndpointsTab.js +101 -0
  31. package/dist/fe/components/IntegrationsPage/components/FieldMappingRow.d.ts +17 -0
  32. package/dist/fe/components/IntegrationsPage/components/FieldMappingRow.js +179 -0
  33. package/dist/fe/components/IntegrationsPage/components/FieldMappingRows.d.ts +11 -0
  34. package/dist/fe/components/IntegrationsPage/components/FieldMappingRows.js +115 -0
  35. package/dist/fe/components/IntegrationsPage/components/IntegrationsPage.d.ts +2 -0
  36. package/dist/fe/components/IntegrationsPage/components/IntegrationsPage.js +175 -0
  37. package/dist/fe/components/IntegrationsPage/components/MappingEditor.d.ts +15 -0
  38. package/dist/fe/components/IntegrationsPage/components/MappingEditor.js +193 -0
  39. package/dist/fe/components/IntegrationsPage/components/MappingList.d.ts +11 -0
  40. package/dist/fe/components/IntegrationsPage/components/MappingList.js +191 -0
  41. package/dist/fe/components/IntegrationsPage/components/MappingWriteModeFields.d.ts +19 -0
  42. package/dist/fe/components/IntegrationsPage/components/MappingWriteModeFields.js +150 -0
  43. package/dist/fe/components/IntegrationsPage/components/MappingsTab.d.ts +5 -0
  44. package/dist/fe/components/IntegrationsPage/components/MappingsTab.js +154 -0
  45. package/dist/fe/components/IntegrationsPage/components/PaginationFields.d.ts +9 -0
  46. package/dist/fe/components/IntegrationsPage/components/PaginationFields.js +218 -0
  47. package/dist/fe/components/IntegrationsPage/components/ParamBindingRow.d.ts +24 -0
  48. package/dist/fe/components/IntegrationsPage/components/ParamBindingRow.js +180 -0
  49. package/dist/fe/components/IntegrationsPage/components/ParamBindingRows.d.ts +33 -0
  50. package/dist/fe/components/IntegrationsPage/components/ParamBindingRows.js +100 -0
  51. package/dist/fe/components/IntegrationsPage/components/Primitives.d.ts +65 -0
  52. package/dist/fe/components/IntegrationsPage/components/Primitives.js +94 -0
  53. package/dist/fe/components/IntegrationsPage/components/RunConfirmStep.d.ts +10 -0
  54. package/dist/fe/components/IntegrationsPage/components/RunConfirmStep.js +48 -0
  55. package/dist/fe/components/IntegrationsPage/components/RunHistory.d.ts +10 -0
  56. package/dist/fe/components/IntegrationsPage/components/RunHistory.js +124 -0
  57. package/dist/fe/components/IntegrationsPage/components/RunHistoryRow.d.ts +7 -0
  58. package/dist/fe/components/IntegrationsPage/components/RunHistoryRow.js +129 -0
  59. package/dist/fe/components/IntegrationsPage/components/RunPanel.d.ts +9 -0
  60. package/dist/fe/components/IntegrationsPage/components/RunPanel.js +160 -0
  61. package/dist/fe/components/IntegrationsPage/components/RunPlanIssues.d.ts +5 -0
  62. package/dist/fe/components/IntegrationsPage/components/RunPlanIssues.js +43 -0
  63. package/dist/fe/components/IntegrationsPage/components/RunPlanSummary.d.ts +5 -0
  64. package/dist/fe/components/IntegrationsPage/components/RunPlanSummary.js +92 -0
  65. package/dist/fe/components/IntegrationsPage/components/RunProgressBar.d.ts +8 -0
  66. package/dist/fe/components/IntegrationsPage/components/RunProgressBar.js +77 -0
  67. package/dist/fe/components/IntegrationsPage/components/RunRevertConflicts.d.ts +13 -0
  68. package/dist/fe/components/IntegrationsPage/components/RunRevertConflicts.js +65 -0
  69. package/dist/fe/components/IntegrationsPage/components/RunsTab.d.ts +13 -0
  70. package/dist/fe/components/IntegrationsPage/components/RunsTab.js +39 -0
  71. package/dist/fe/components/IntegrationsPage/components/Skeletons.d.ts +9 -0
  72. package/dist/fe/components/IntegrationsPage/components/Skeletons.js +139 -0
  73. package/dist/fe/components/IntegrationsPage/components/authOptions.d.ts +29 -0
  74. package/dist/fe/components/IntegrationsPage/components/authOptions.js +71 -0
  75. package/dist/fe/components/IntegrationsPage/components/connectionDraft.d.ts +64 -0
  76. package/dist/fe/components/IntegrationsPage/components/connectionDraft.js +112 -0
  77. package/dist/fe/components/IntegrationsPage/components/credentialSlots.d.ts +25 -0
  78. package/dist/fe/components/IntegrationsPage/components/credentialSlots.js +67 -0
  79. package/dist/fe/components/IntegrationsPage/components/fieldMappingOptions.d.ts +16 -0
  80. package/dist/fe/components/IntegrationsPage/components/fieldMappingOptions.js +41 -0
  81. package/dist/fe/components/IntegrationsPage/components/formSupport.d.ts +19 -0
  82. package/dist/fe/components/IntegrationsPage/components/formSupport.js +25 -0
  83. package/dist/fe/components/IntegrationsPage/components/mappingDraft.d.ts +40 -0
  84. package/dist/fe/components/IntegrationsPage/components/mappingDraft.js +44 -0
  85. package/dist/fe/components/IntegrationsPage/components/pathParams.d.ts +9 -0
  86. package/dist/fe/components/IntegrationsPage/components/pathParams.js +15 -0
  87. package/dist/fe/components/IntegrationsPage/components/runFormat.d.ts +33 -0
  88. package/dist/fe/components/IntegrationsPage/components/runFormat.js +85 -0
  89. package/dist/fe/components/IntegrationsPage/components/useInfiniteList.d.ts +40 -0
  90. package/dist/fe/components/IntegrationsPage/components/useInfiniteList.js +110 -0
  91. package/dist/fe/components/IntegrationsPage/index.d.ts +18 -0
  92. package/dist/fe/components/IntegrationsPage/index.js +11 -0
  93. package/dist/fe/components/IntegrationsPage/store/index.d.ts +2 -0
  94. package/dist/fe/components/IntegrationsPage/store/index.js +124 -0
  95. package/dist/fe/components/IntegrationsPage/store/state.d.ts +80 -0
  96. package/dist/fe/components/IntegrationsPage/store/state.js +32 -0
  97. package/dist/fe/components/IntegrationsPage/theme/index.d.ts +103 -0
  98. package/dist/fe/components/IntegrationsPage/theme/index.js +113 -0
  99. package/dist/fe/components/IntegrationsPage/types/actions.d.ts +91 -0
  100. package/dist/fe/components/IntegrationsPage/types/actions.js +1 -0
  101. package/dist/fe/components/IntegrationsPage/types/index.d.ts +3 -0
  102. package/dist/fe/components/IntegrationsPage/types/index.js +3 -0
  103. package/dist/fe/components/IntegrationsPage/types/records.d.ts +139 -0
  104. package/dist/fe/components/IntegrationsPage/types/records.js +11 -0
  105. package/dist/fe/components/IntegrationsPage/types/results.d.ts +52 -0
  106. package/dist/fe/components/IntegrationsPage/types/results.js +4 -0
  107. package/dist/fe/index.d.ts +2 -0
  108. package/dist/fe/index.js +1 -0
  109. package/dist/index.js +9 -9
  110. package/dist/src/ElysiaPlugin/routes/integrations/inspect.d.ts +87 -0
  111. package/dist/src/ElysiaPlugin/routes/integrations/inspectRoutes.d.ts +41 -0
  112. package/dist/src/ElysiaPlugin/routes/integrations/repository.d.ts +31 -0
  113. package/package.json +1 -1
  114. package/scripts/generate-schema.ts +1 -0
@@ -0,0 +1,39 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from 'react';
4
+ import { useIntegrationsStore } from '../store';
5
+ import { Notice } from './Primitives';
6
+ import { RunHistory } from './RunHistory';
7
+ import { RunPanel } from './RunPanel';
8
+ export function RunsTab({ actions, onSubscribeProgress }) {
9
+ const store = useIntegrationsStore();
10
+ // A lookup by id, not a list operation: the selected mapping is on the page the
11
+ // server already returned, and nothing here filters, sorts or pages it.
12
+ const selectedId = store.selectedMappingId;
13
+ const mapping = selectedId ? store.mappings.find((item)=>item.id === selectedId) : undefined;
14
+ const [refreshKey, setRefreshKey] = useState(0);
15
+ const refresh = ()=>{
16
+ setRefreshKey((key)=>key + 1);
17
+ };
18
+ return /*#__PURE__*/ _jsxs("section", {
19
+ className: "flex flex-col gap-4",
20
+ children: [
21
+ mapping ? /*#__PURE__*/ _jsx(RunPanel, {
22
+ actions: actions,
23
+ mapping: mapping,
24
+ onRunSettled: refresh,
25
+ onSubscribeProgress: onSubscribeProgress
26
+ }) : /*#__PURE__*/ _jsx(Notice, {
27
+ tone: "info",
28
+ title: "Choose a mapping to preview or run an import",
29
+ children: "A mapping is what says which endpoint feeds which target entity, and how missing rows are treated. Pick one on the Mappings tab; the history below still lists every run of this connection."
30
+ }),
31
+ /*#__PURE__*/ _jsx(RunHistory, {
32
+ actions: actions,
33
+ mappingId: mapping ? mapping.id : null,
34
+ onRefresh: refresh,
35
+ refreshKey: refreshKey
36
+ })
37
+ ]
38
+ });
39
+ }
@@ -0,0 +1,9 @@
1
+ export type ListSkeletonProps = {
2
+ rows: number;
3
+ };
4
+ /** Stands in for a list of rows while the first page is on its way. */
5
+ export declare function ListSkeleton({ rows }: ListSkeletonProps): import("react/jsx-runtime").JSX.Element;
6
+ /** Stands in for a card: the same header bar, the same padded body. */
7
+ export declare function CardSkeleton(): import("react/jsx-runtime").JSX.Element;
8
+ /** Stands in for the counts strip — six cells, the grid the real one uses. */
9
+ export declare function StatGridSkeleton(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,139 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { cn } from '../../../utils/cn';
4
+ import { integrationsPageTheme } from '../theme';
5
+ /**
6
+ * The loading shapes.
7
+ *
8
+ * Each one wears the SAME layout classes as the thing it stands in for, and the
9
+ * grey bars sit inside boxes the height of the text they replace. That is the
10
+ * whole point: the list must not grow taller the moment the rows arrive, or the
11
+ * button the operator was reaching for moves out from under the finger.
12
+ */ const theme = integrationsPageTheme;
13
+ /** Cycled so the placeholder reads as a list of different names, not a barcode. */ const TITLE_WIDTHS = [
14
+ 'w-2/5',
15
+ 'w-3/5',
16
+ 'w-1/2',
17
+ 'w-2/3'
18
+ ];
19
+ const META_WIDTHS = [
20
+ 'w-3/4',
21
+ 'w-1/2',
22
+ 'w-2/3',
23
+ 'w-3/5'
24
+ ];
25
+ function widthAt(widths, index) {
26
+ return widths[index % widths.length] ?? 'w-1/2';
27
+ }
28
+ /** Stands in for a list of rows while the first page is on its way. */ export function ListSkeleton({ rows }) {
29
+ return /*#__PURE__*/ _jsx("output", {
30
+ "aria-busy": "true",
31
+ "aria-label": "Loading list",
32
+ className: theme.list.wrapper,
33
+ children: Array.from({
34
+ length: Math.max(rows, 1)
35
+ }, (_, index)=>/*#__PURE__*/ _jsxs("div", {
36
+ "aria-hidden": "true",
37
+ className: cn(theme.list.item, 'pointer-events-none'),
38
+ children: [
39
+ /*#__PURE__*/ _jsx("span", {
40
+ className: "flex h-5 items-center",
41
+ children: /*#__PURE__*/ _jsx("span", {
42
+ className: cn(theme.skeleton.line, widthAt(TITLE_WIDTHS, index))
43
+ })
44
+ }),
45
+ /*#__PURE__*/ _jsx("span", {
46
+ className: "flex h-4 items-center",
47
+ children: /*#__PURE__*/ _jsx("span", {
48
+ className: cn(theme.skeleton.line, 'h-2', widthAt(META_WIDTHS, index))
49
+ })
50
+ })
51
+ ]
52
+ }, `list-skeleton-${index}`))
53
+ });
54
+ }
55
+ // ── CardSkeleton ────────────────────────────────────────────────────────────
56
+ /** Stands in for a card: the same header bar, the same padded body. */ export function CardSkeleton() {
57
+ return(// `output` carries role=status on its own, but it is inline by default and
58
+ // the card wrapper only ever styled a block, so the display is restored.
59
+ /*#__PURE__*/ _jsxs("output", {
60
+ "aria-busy": "true",
61
+ "aria-label": "Loading panel",
62
+ className: cn(theme.card.wrapper, 'block'),
63
+ children: [
64
+ /*#__PURE__*/ _jsxs("div", {
65
+ "aria-hidden": "true",
66
+ className: theme.card.header,
67
+ children: [
68
+ /*#__PURE__*/ _jsx("span", {
69
+ className: "flex h-5 items-center",
70
+ children: /*#__PURE__*/ _jsx("span", {
71
+ className: cn(theme.skeleton.line, 'w-32')
72
+ })
73
+ }),
74
+ /*#__PURE__*/ _jsx("span", {
75
+ className: "flex h-5 items-center",
76
+ children: /*#__PURE__*/ _jsx("span", {
77
+ className: cn(theme.skeleton.line, 'w-16')
78
+ })
79
+ })
80
+ ]
81
+ }),
82
+ /*#__PURE__*/ _jsxs("div", {
83
+ "aria-hidden": "true",
84
+ className: theme.card.body,
85
+ children: [
86
+ /*#__PURE__*/ _jsx("span", {
87
+ className: "flex h-5 items-center",
88
+ children: /*#__PURE__*/ _jsx("span", {
89
+ className: cn(theme.skeleton.line, 'w-full')
90
+ })
91
+ }),
92
+ /*#__PURE__*/ _jsx("span", {
93
+ className: "flex h-5 items-center",
94
+ children: /*#__PURE__*/ _jsx("span", {
95
+ className: cn(theme.skeleton.line, 'w-4/5')
96
+ })
97
+ }),
98
+ /*#__PURE__*/ _jsx("span", {
99
+ className: cn(theme.skeleton.block, 'h-20 w-full')
100
+ }),
101
+ /*#__PURE__*/ _jsx("span", {
102
+ className: "flex h-5 items-center",
103
+ children: /*#__PURE__*/ _jsx("span", {
104
+ className: cn(theme.skeleton.line, 'w-2/3')
105
+ })
106
+ })
107
+ ]
108
+ })
109
+ ]
110
+ }));
111
+ }
112
+ // ── StatGridSkeleton ────────────────────────────────────────────────────────
113
+ /** Stands in for the counts strip — six cells, the grid the real one uses. */ export function StatGridSkeleton() {
114
+ return /*#__PURE__*/ _jsx("output", {
115
+ "aria-busy": "true",
116
+ "aria-label": "Loading totals",
117
+ className: theme.stat.grid,
118
+ children: Array.from({
119
+ length: 6
120
+ }, (_, index)=>/*#__PURE__*/ _jsxs("div", {
121
+ "aria-hidden": "true",
122
+ className: theme.stat.cell,
123
+ children: [
124
+ /*#__PURE__*/ _jsx("span", {
125
+ className: "flex h-7 items-center",
126
+ children: /*#__PURE__*/ _jsx("span", {
127
+ className: cn(theme.skeleton.line, 'h-4 w-10')
128
+ })
129
+ }),
130
+ /*#__PURE__*/ _jsx("span", {
131
+ className: "flex h-3.5 items-center",
132
+ children: /*#__PURE__*/ _jsx("span", {
133
+ className: cn(theme.skeleton.line, 'h-2 w-12')
134
+ })
135
+ })
136
+ ]
137
+ }, `stat-skeleton-${index}`))
138
+ });
139
+ }
@@ -0,0 +1,29 @@
1
+ import type { IntegrationAuthType } from '../types';
2
+ /**
3
+ * The three closed choices in the auth section, and the only way a `<select>`
4
+ * value gets back into one of them.
5
+ *
6
+ * A select hands back a plain string. Narrowing it against the list that
7
+ * produced the options is what keeps the draft honest without a cast — an
8
+ * unrecognised value is simply not applied.
9
+ */
10
+ export type AuthTypeOption = {
11
+ value: IntegrationAuthType;
12
+ label: string;
13
+ hint: string;
14
+ };
15
+ export declare const AUTH_TYPE_OPTIONS: AuthTypeOption[];
16
+ export type GrantTypeValue = 'password' | 'client_credentials';
17
+ export type ClientAuthValue = 'basic' | 'body';
18
+ export declare const GRANT_TYPE_OPTIONS: {
19
+ value: GrantTypeValue;
20
+ label: string;
21
+ }[];
22
+ export declare const CLIENT_AUTH_OPTIONS: {
23
+ value: ClientAuthValue;
24
+ label: string;
25
+ }[];
26
+ export declare function toAuthType(value: string): IntegrationAuthType | null;
27
+ export declare function toGrantType(value: string): GrantTypeValue | null;
28
+ export declare function toClientAuth(value: string): ClientAuthValue | null;
29
+ export declare function authTypeHint(authType: IntegrationAuthType): string;
@@ -0,0 +1,71 @@
1
+ export const AUTH_TYPE_OPTIONS = [
2
+ {
3
+ value: 'none',
4
+ label: 'None',
5
+ hint: 'The service is called with no credential of any kind.'
6
+ },
7
+ {
8
+ value: 'bearer',
9
+ label: 'Bearer token',
10
+ hint: 'A token is sent on every request, by default as Authorization: Bearer …'
11
+ },
12
+ {
13
+ value: 'api_key',
14
+ label: 'API key',
15
+ hint: 'A key is sent in a header or as a query parameter. Say which below.'
16
+ },
17
+ {
18
+ value: 'basic',
19
+ label: 'Basic',
20
+ hint: 'A user name and password pair, sent as HTTP basic authentication.'
21
+ },
22
+ {
23
+ value: 'oauth2',
24
+ label: 'OAuth 2',
25
+ hint: 'A token is fetched from the token endpoint before each batch of calls and refreshed when it expires.'
26
+ }
27
+ ];
28
+ export const GRANT_TYPE_OPTIONS = [
29
+ {
30
+ value: 'client_credentials',
31
+ label: 'Client credentials'
32
+ },
33
+ {
34
+ value: 'password',
35
+ label: 'Password'
36
+ }
37
+ ];
38
+ export const CLIENT_AUTH_OPTIONS = [
39
+ {
40
+ value: 'basic',
41
+ label: 'Authorization header (basic)'
42
+ },
43
+ {
44
+ value: 'body',
45
+ label: 'Request body'
46
+ }
47
+ ];
48
+ export function toAuthType(value) {
49
+ for (const option of AUTH_TYPE_OPTIONS){
50
+ if (option.value === value) return option.value;
51
+ }
52
+ return null;
53
+ }
54
+ export function toGrantType(value) {
55
+ for (const option of GRANT_TYPE_OPTIONS){
56
+ if (option.value === value) return option.value;
57
+ }
58
+ return null;
59
+ }
60
+ export function toClientAuth(value) {
61
+ for (const option of CLIENT_AUTH_OPTIONS){
62
+ if (option.value === value) return option.value;
63
+ }
64
+ return null;
65
+ }
66
+ export function authTypeHint(authType) {
67
+ for (const option of AUTH_TYPE_OPTIONS){
68
+ if (option.value === authType) return option.hint;
69
+ }
70
+ return '';
71
+ }
@@ -0,0 +1,64 @@
1
+ import type { IntegrationAuthType, IntegrationSource } from '../types';
2
+ /**
3
+ * The form's own copy of a connection.
4
+ *
5
+ * Every box is a string or a boolean because that is what an `<input>` gives
6
+ * back; the record is rebuilt on save. Keeping a half-typed timeout as `12` the
7
+ * NUMBER would mean the field could never hold an empty string, and "clear it
8
+ * and think again" is a thing an operator does constantly.
9
+ */
10
+ export type ConnectionDraft = {
11
+ name: string;
12
+ slug: string;
13
+ baseUrl: string;
14
+ description: string;
15
+ enabled: boolean;
16
+ authType: IntegrationAuthType;
17
+ authHeaderName: string;
18
+ authQueryParam: string;
19
+ tokenUrl: string;
20
+ oauthGrantType: 'password' | 'client_credentials';
21
+ oauthClientId: string;
22
+ oauthUsername: string;
23
+ oauthScope: string;
24
+ oauthClientAuth: 'basic' | 'body';
25
+ tlsVerify: boolean;
26
+ timeoutMs: string;
27
+ };
28
+ export type ConnectionDraftErrors = {
29
+ name?: string;
30
+ slug?: string;
31
+ baseUrl?: string;
32
+ tokenUrl?: string;
33
+ timeoutMs?: string;
34
+ };
35
+ /** What each group of fields is handed. The groups are display only. */
36
+ export type ConnectionFieldsProps = {
37
+ draft: ConnectionDraft;
38
+ errors: ConnectionDraftErrors;
39
+ disabled: boolean;
40
+ onChange: (patch: Partial<ConnectionDraft>) => void;
41
+ };
42
+ export declare const emptyConnectionDraft: ConnectionDraft;
43
+ export declare function draftFromSource(source: IntegrationSource): ConnectionDraft;
44
+ export declare function usesHeaderName(authType: IntegrationAuthType): boolean;
45
+ export declare function usesQueryParam(authType: IntegrationAuthType): boolean;
46
+ export declare function usesOauth(authType: IntegrationAuthType): boolean;
47
+ /**
48
+ * Rebuilds the record.
49
+ *
50
+ * Fields the chosen auth type does not use are sent as null rather than left
51
+ * alone. Switching a connection from OAuth to a bearer token and leaving the old
52
+ * token URL behind is how a source ends up carrying settings nobody can see in
53
+ * the form but the server still reads.
54
+ */
55
+ export declare function draftToSource(draft: ConnectionDraft, id?: string): Partial<IntegrationSource>;
56
+ /**
57
+ * What must be filled in before a save is worth attempting.
58
+ *
59
+ * The base URL is checked for a scheme and nothing else. It is deliberately not
60
+ * checked for https, for a public host or for a resolvable name: an in-cluster
61
+ * service on plain http is a normal target, and a form that rejected it would be
62
+ * rejecting a working setup.
63
+ */
64
+ export declare function validateConnectionDraft(draft: ConnectionDraft): ConnectionDraftErrors;
@@ -0,0 +1,112 @@
1
+ export const emptyConnectionDraft = {
2
+ name: '',
3
+ slug: '',
4
+ baseUrl: '',
5
+ description: '',
6
+ enabled: true,
7
+ authType: 'none',
8
+ authHeaderName: '',
9
+ authQueryParam: '',
10
+ tokenUrl: '',
11
+ oauthGrantType: 'client_credentials',
12
+ oauthClientId: '',
13
+ oauthUsername: '',
14
+ oauthScope: '',
15
+ oauthClientAuth: 'basic',
16
+ // Verification on and no timeout override: the safe end of both, so a
17
+ // connection is only ever loosened by someone who went and loosened it.
18
+ tlsVerify: true,
19
+ timeoutMs: ''
20
+ };
21
+ function text(value) {
22
+ return value ?? '';
23
+ }
24
+ function orNull(value) {
25
+ const trimmed = value.trim();
26
+ return trimmed.length > 0 ? trimmed : null;
27
+ }
28
+ export function draftFromSource(source) {
29
+ return {
30
+ name: source.name,
31
+ slug: source.slug,
32
+ baseUrl: source.baseUrl,
33
+ description: text(source.description),
34
+ enabled: source.enabled !== false,
35
+ authType: source.authType,
36
+ authHeaderName: text(source.authHeaderName),
37
+ authQueryParam: text(source.authQueryParam),
38
+ tokenUrl: text(source.tokenUrl),
39
+ oauthGrantType: source.oauthGrantType ?? 'client_credentials',
40
+ oauthClientId: text(source.oauthClientId),
41
+ oauthUsername: text(source.oauthUsername),
42
+ oauthScope: text(source.oauthScope),
43
+ oauthClientAuth: source.oauthClientAuth ?? 'basic',
44
+ tlsVerify: source.tlsVerify !== false,
45
+ timeoutMs: source.timeoutMs == null ? '' : String(source.timeoutMs)
46
+ };
47
+ }
48
+ // ── which extras an auth type actually uses ─────────────────────────────────
49
+ export function usesHeaderName(authType) {
50
+ return authType === 'bearer' || authType === 'api_key';
51
+ }
52
+ export function usesQueryParam(authType) {
53
+ return authType === 'api_key';
54
+ }
55
+ export function usesOauth(authType) {
56
+ return authType === 'oauth2';
57
+ }
58
+ /**
59
+ * Rebuilds the record.
60
+ *
61
+ * Fields the chosen auth type does not use are sent as null rather than left
62
+ * alone. Switching a connection from OAuth to a bearer token and leaving the old
63
+ * token URL behind is how a source ends up carrying settings nobody can see in
64
+ * the form but the server still reads.
65
+ */ export function draftToSource(draft, id) {
66
+ const oauth = usesOauth(draft.authType);
67
+ const timeout = Number.parseInt(draft.timeoutMs.trim(), 10);
68
+ return {
69
+ ...id ? {
70
+ id
71
+ } : {},
72
+ name: draft.name.trim(),
73
+ slug: draft.slug.trim(),
74
+ baseUrl: draft.baseUrl.trim(),
75
+ description: orNull(draft.description),
76
+ enabled: draft.enabled,
77
+ authType: draft.authType,
78
+ authHeaderName: usesHeaderName(draft.authType) ? orNull(draft.authHeaderName) : null,
79
+ authQueryParam: usesQueryParam(draft.authType) ? orNull(draft.authQueryParam) : null,
80
+ tokenUrl: oauth ? orNull(draft.tokenUrl) : null,
81
+ oauthGrantType: oauth ? draft.oauthGrantType : null,
82
+ oauthClientId: oauth ? orNull(draft.oauthClientId) : null,
83
+ oauthUsername: oauth && draft.oauthGrantType === 'password' ? orNull(draft.oauthUsername) : null,
84
+ oauthScope: oauth ? orNull(draft.oauthScope) : null,
85
+ oauthClientAuth: oauth ? draft.oauthClientAuth : null,
86
+ tlsVerify: draft.tlsVerify,
87
+ timeoutMs: Number.isFinite(timeout) && timeout > 0 ? timeout : null
88
+ };
89
+ }
90
+ const SLUG_PATTERN = /^[a-z0-9][a-z0-9_-]*$/;
91
+ const DIGITS_PATTERN = /^\d+$/;
92
+ /**
93
+ * What must be filled in before a save is worth attempting.
94
+ *
95
+ * The base URL is checked for a scheme and nothing else. It is deliberately not
96
+ * checked for https, for a public host or for a resolvable name: an in-cluster
97
+ * service on plain http is a normal target, and a form that rejected it would be
98
+ * rejecting a working setup.
99
+ */ export function validateConnectionDraft(draft) {
100
+ const errors = {};
101
+ if (draft.name.trim().length === 0) errors.name = 'Give the connection a name.';
102
+ const slug = draft.slug.trim();
103
+ if (slug.length === 0) errors.slug = 'Give the connection a slug.';
104
+ else if (!SLUG_PATTERN.test(slug)) errors.slug = 'Lower-case letters, digits, hyphen and underscore only.';
105
+ const baseUrl = draft.baseUrl.trim();
106
+ if (baseUrl.length === 0) errors.baseUrl = 'Give the base URL of the service.';
107
+ else if (!baseUrl.includes('://')) errors.baseUrl = 'Include the scheme, for example http://hr-service:8080.';
108
+ if (usesOauth(draft.authType) && draft.tokenUrl.trim().length === 0) errors.tokenUrl = 'OAuth 2 needs the token endpoint.';
109
+ const timeout = draft.timeoutMs.trim();
110
+ if (timeout.length > 0 && !DIGITS_PATTERN.test(timeout)) errors.timeoutMs = 'Whole milliseconds, for example 30000.';
111
+ return errors;
112
+ }
@@ -0,0 +1,25 @@
1
+ import type { IntegrationSource } from '../types';
2
+ /**
3
+ * The write-only halves of a connection.
4
+ *
5
+ * Everything here is deliberately explicit rather than keyed by a variable: the
6
+ * action takes a fixed set of three optional keys, and building that object from
7
+ * a computed key would need a cast to type-check — a cast that would happily let
8
+ * a typo through to a call that stores secrets.
9
+ */
10
+ export type CredentialSlot = 'token' | 'oauthClientSecret' | 'oauthPassword';
11
+ export type CredentialValues = {
12
+ token?: string;
13
+ oauthClientSecret?: string;
14
+ oauthPassword?: string;
15
+ };
16
+ /** One key at a time, for the per-field Clear button. */
17
+ export declare function patchFor(slot: CredentialSlot, value: string): CredentialValues;
18
+ /** The masked preview already stored against the record, if there is one. */
19
+ export declare function storedHint(source: IntegrationSource, slot: CredentialSlot): string | null;
20
+ /** `undefined` means the reply said nothing about this slot; null means cleared. */
21
+ export declare function hintFromResult(result: Record<string, string | null>, slot: CredentialSlot): string | null | undefined;
22
+ /** Which secrets the chosen auth type actually reads. */
23
+ export declare function slotsForSource(source: IntegrationSource): CredentialSlot[];
24
+ export declare function slotLabel(slot: CredentialSlot, source: IntegrationSource): string;
25
+ export declare function slotHint(slot: CredentialSlot, source: IntegrationSource): string;
@@ -0,0 +1,67 @@
1
+ /** One key at a time, for the per-field Clear button. */ export function patchFor(slot, value) {
2
+ if (slot === 'token') return {
3
+ token: value
4
+ };
5
+ if (slot === 'oauthClientSecret') return {
6
+ oauthClientSecret: value
7
+ };
8
+ return {
9
+ oauthPassword: value
10
+ };
11
+ }
12
+ /** The masked preview already stored against the record, if there is one. */ export function storedHint(source, slot) {
13
+ if (slot === 'token') return source.authTokenHint ?? null;
14
+ if (slot === 'oauthClientSecret') return source.oauthClientSecretHint ?? null;
15
+ return source.oauthPasswordHint ?? null;
16
+ }
17
+ /**
18
+ * Servers name the returned previews after either the slot or its hint column.
19
+ * Both are accepted so a correct reply is never read as "nothing came back".
20
+ */ const HINT_KEYS = {
21
+ token: [
22
+ 'token',
23
+ 'authTokenHint'
24
+ ],
25
+ oauthClientSecret: [
26
+ 'oauthClientSecret',
27
+ 'oauthClientSecretHint'
28
+ ],
29
+ oauthPassword: [
30
+ 'oauthPassword',
31
+ 'oauthPasswordHint'
32
+ ]
33
+ };
34
+ /** `undefined` means the reply said nothing about this slot; null means cleared. */ export function hintFromResult(result, slot) {
35
+ for (const key of HINT_KEYS[slot]){
36
+ if (key in result) return result[key] ?? null;
37
+ }
38
+ return undefined;
39
+ }
40
+ /** Which secrets the chosen auth type actually reads. */ export function slotsForSource(source) {
41
+ if (source.authType === 'oauth2') {
42
+ return source.oauthGrantType === 'password' ? [
43
+ 'oauthClientSecret',
44
+ 'oauthPassword'
45
+ ] : [
46
+ 'oauthClientSecret'
47
+ ];
48
+ }
49
+ if (source.authType === 'none') return [];
50
+ return [
51
+ 'token'
52
+ ];
53
+ }
54
+ export function slotLabel(slot, source) {
55
+ if (slot === 'oauthClientSecret') return 'Client secret';
56
+ if (slot === 'oauthPassword') return 'Password';
57
+ if (source.authType === 'api_key') return 'API key';
58
+ if (source.authType === 'basic') return 'Basic credential';
59
+ return 'Bearer token';
60
+ }
61
+ export function slotHint(slot, source) {
62
+ if (slot === 'oauthClientSecret') return 'Sent to the token endpoint with the client ID.';
63
+ if (slot === 'oauthPassword') return 'The password of the user named above.';
64
+ if (source.authType === 'api_key') return 'Sent in the header or query parameter named in the auth section.';
65
+ if (source.authType === 'basic') return 'The user name and password pair, as the service expects.';
66
+ return 'Sent on every request through this connection.';
67
+ }
@@ -0,0 +1,16 @@
1
+ import type { FieldMappingValue, MappingTransformValue } from '../types';
2
+ /**
3
+ * The vocabulary of a field mapping row, kept out of the components so the
4
+ * header, the row and the editor cannot disagree about what a column is called
5
+ * or how wide it is.
6
+ */
7
+ /** A source that reads from the record the PARENT endpoint produced. */
8
+ export declare const PARENT_PREFIX = "__parent.";
9
+ /** One template for the header and every row, so the columns cannot drift apart. */
10
+ export declare const FIELD_MAPPING_GRID = "grid grid-cols-1 gap-2 sm:grid-cols-2 lg:grid-cols-[1fr_1fr_1fr_1fr_1fr_auto]";
11
+ export declare const FIELD_MAPPING_COLUMNS: string[];
12
+ export declare const EMPTY_FIELD_MAPPING: FieldMappingValue;
13
+ export declare const TRANSFORMS: MappingTransformValue[];
14
+ export declare const TRANSFORM_LABEL: Record<MappingTransformValue, string>;
15
+ /** Narrows what a select reported back to a transform this panel knows. */
16
+ export declare function toTransform(value: string): MappingTransformValue;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The vocabulary of a field mapping row, kept out of the components so the
3
+ * header, the row and the editor cannot disagree about what a column is called
4
+ * or how wide it is.
5
+ */ /** A source that reads from the record the PARENT endpoint produced. */ export const PARENT_PREFIX = '__parent.';
6
+ /** One template for the header and every row, so the columns cannot drift apart. */ export const FIELD_MAPPING_GRID = 'grid grid-cols-1 gap-2 sm:grid-cols-2 lg:grid-cols-[1fr_1fr_1fr_1fr_1fr_auto]';
7
+ export const FIELD_MAPPING_COLUMNS = [
8
+ 'Source',
9
+ 'Target',
10
+ 'Transform',
11
+ 'Constant',
12
+ 'Fallback'
13
+ ];
14
+ export const EMPTY_FIELD_MAPPING = {
15
+ source: '',
16
+ target: '',
17
+ transform: 'none'
18
+ };
19
+ export const TRANSFORMS = [
20
+ 'none',
21
+ 'trim',
22
+ 'upper',
23
+ 'lower',
24
+ 'toString',
25
+ 'toNumber',
26
+ 'toBoolean',
27
+ 'dateOnly'
28
+ ];
29
+ export const TRANSFORM_LABEL = {
30
+ none: 'No transform',
31
+ trim: 'Trim spaces',
32
+ upper: 'Uppercase',
33
+ lower: 'Lowercase',
34
+ toString: 'To text',
35
+ toNumber: 'To number',
36
+ toBoolean: 'To boolean',
37
+ dateOnly: 'Date only'
38
+ };
39
+ /** Narrows what a select reported back to a transform this panel knows. */ export function toTransform(value) {
40
+ return TRANSFORMS.find((option)=>option === value) ?? 'none';
41
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Two things every form in this panel needs and neither of them deserves a file.
3
+ */
4
+ /**
5
+ * The ids a control should point `aria-describedby` at.
6
+ *
7
+ * {@link Field} renders its hint as `<id>-hint` and its error as `<id>-error`,
8
+ * so pointing at an id that was not rendered would leave a screen reader
9
+ * announcing nothing — the ids are named here only when they exist.
10
+ */
11
+ export declare function describedBy(id: string, hasHint: boolean, hasError: boolean): string | undefined;
12
+ /**
13
+ * Whatever a rejected action carries, as a sentence.
14
+ *
15
+ * The server's own wording is kept verbatim wherever there is one: it is the
16
+ * only text that knows WHICH setting was wrong, and a friendlier replacement
17
+ * would be a friendlier way of saying nothing.
18
+ */
19
+ export declare function errorText(reason: unknown, fallback: string): string;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Two things every form in this panel needs and neither of them deserves a file.
3
+ */ /**
4
+ * The ids a control should point `aria-describedby` at.
5
+ *
6
+ * {@link Field} renders its hint as `<id>-hint` and its error as `<id>-error`,
7
+ * so pointing at an id that was not rendered would leave a screen reader
8
+ * announcing nothing — the ids are named here only when they exist.
9
+ */ export function describedBy(id, hasHint, hasError) {
10
+ if (hasHint && hasError) return `${id}-hint ${id}-error`;
11
+ if (hasHint) return `${id}-hint`;
12
+ if (hasError) return `${id}-error`;
13
+ return undefined;
14
+ }
15
+ /**
16
+ * Whatever a rejected action carries, as a sentence.
17
+ *
18
+ * The server's own wording is kept verbatim wherever there is one: it is the
19
+ * only text that knows WHICH setting was wrong, and a friendlier replacement
20
+ * would be a friendlier way of saying nothing.
21
+ */ export function errorText(reason, fallback) {
22
+ if (reason instanceof Error && reason.message.length > 0) return reason.message;
23
+ if (typeof reason === 'string' && reason.length > 0) return reason;
24
+ return fallback;
25
+ }