nucleus-core-ts 0.9.821 → 0.9.822

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.
@@ -12,6 +12,7 @@ import type { EndpointSpec } from 'src/Services/Integrations/collect';
12
12
  import type { SourceConnection } from 'src/Services/Integrations/fetcher';
13
13
  import type { OAuthConfig } from 'src/Services/Integrations/oauth';
14
14
  import type { MappingSpec, RunRepository } from 'src/Services/Integrations/runner';
15
+ import type { TransferDocument } from 'src/Services/Integrations/transfer';
15
16
  import type { PreImage } from 'src/Services/Integrations/writer';
16
17
  import type { Logger } from 'src/Services/Logger';
17
18
  import type { NucleusTable } from 'src/types';
@@ -75,6 +76,41 @@ export declare function resolveEndpointContext(deps: RepositoryDeps, by: {
75
76
  */
76
77
  export declare function cacheEndpointSample(deps: RepositoryDeps, endpointId: string, records: readonly unknown[]): Promise<void>;
77
78
  /** Columns of a target that must carry a value, for pre-write validation. */
79
+ /**
80
+ * Everything one connection is made of, for an export.
81
+ *
82
+ * Read as three plain selects rather than through `resolveChain`, which starts
83
+ * from a mapping — a connection worth exporting may have endpoints and no
84
+ * mappings yet, and that is a legitimate thing to move.
85
+ */
86
+ export declare function readConnectionBundle(deps: RepositoryDeps, sourceId: string): Promise<{
87
+ source: Record<string, unknown>;
88
+ endpoints: Record<string, unknown>[];
89
+ mappings: Record<string, unknown>[];
90
+ } | null>;
91
+ /**
92
+ * Writes an exported connection into this installation.
93
+ *
94
+ * Matched by NAME throughout — the connection by its slug, endpoints and
95
+ * mappings by their name — so bringing the same file in twice updates what is
96
+ * here instead of leaving two of everything. That is the behaviour somebody
97
+ * actually wants: the file is how a configuration is kept in step between two
98
+ * environments, not a one-shot.
99
+ *
100
+ * Credentials are neither in the file nor invented here. A connection arrives
101
+ * unable to authenticate, and says so, rather than arriving with an empty token
102
+ * that looks configured.
103
+ */
104
+ export declare function applyTransferDocument(deps: RepositoryDeps, document: TransferDocument, userId: string): Promise<{
105
+ ok: true;
106
+ sourceId: string;
107
+ created: boolean;
108
+ endpoints: number;
109
+ mappings: number;
110
+ } | {
111
+ ok: false;
112
+ error: string;
113
+ }>;
78
114
  export declare function requiredFieldsOf(entities: NucleusTable[], targetEntity: string): string[];
79
115
  /**
80
116
  * Columns the target enforces as unique, single-column only.
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Moving a whole integration between installations.
3
+ *
4
+ * A connection is not one record. It is a connection, the calls it makes, the
5
+ * parameters those calls take from each other, and the mappings that turn the
6
+ * answers into rows — and rebuilding that by hand in a second environment is
7
+ * both hours of work and a fresh chance to get one field wrong in a way nobody
8
+ * notices until an import writes it.
9
+ *
10
+ * So it travels as one document.
11
+ *
12
+ * ## What deliberately does NOT travel
13
+ *
14
+ * Every secret. Tokens, client secrets, OAuth passwords: none of them are in the
15
+ * document, and the import asks for them again on the other side. A file that
16
+ * carries credentials is a file that gets mailed, pasted into a ticket and
17
+ * committed — and the whole point of storing them encrypted is undone by one
18
+ * convenient export.
19
+ *
20
+ * ## Why names, not identifiers
21
+ *
22
+ * An endpoint's parameters can be bound to another endpoint, and a mapping reads
23
+ * from one. Those are foreign keys, and a foreign key means nothing in a
24
+ * database that has never seen it. On the way out they become the endpoint's
25
+ * NAME; on the way in they are looked up again. So a document stays valid across
26
+ * installations, and a re-import onto an existing connection updates what is
27
+ * there rather than duplicating it.
28
+ */
29
+ import type { FieldMapping, MissingRecordPolicy, ReferenceCheck, WriteMode } from './types';
30
+ /** Bumped only when an older document could be READ wrongly, not merely partially. */
31
+ export declare const TRANSFER_VERSION = 1;
32
+ export type TransferEndpoint = {
33
+ /** Unique within the document; how bindings and mappings refer to it. */
34
+ name: string;
35
+ method: string;
36
+ path: string;
37
+ description?: string | null;
38
+ queryParams?: Record<string, unknown> | null;
39
+ requestBody?: Record<string, unknown> | null;
40
+ responseRootPath?: string | null;
41
+ pagination?: Record<string, unknown> | null;
42
+ /** `endpointId` is replaced by `endpointName`; every other form is unchanged. */
43
+ paramBindings?: Record<string, unknown>[] | null;
44
+ enabled?: boolean;
45
+ };
46
+ export type TransferMapping = {
47
+ name: string;
48
+ /** The endpoint this mapping reads, by name. */
49
+ endpointName: string | null;
50
+ targetEntity: string;
51
+ fieldMappings: FieldMapping[];
52
+ referenceChecks?: ReferenceCheck[];
53
+ dedupSourceField?: string | null;
54
+ dedupTargetField?: string | null;
55
+ writeMode: WriteMode;
56
+ missingRecordPolicy: MissingRecordPolicy;
57
+ missingRecordColumn?: string | null;
58
+ missingRecordValue?: string | null;
59
+ passwordTargetColumn?: string | null;
60
+ enabled?: boolean;
61
+ };
62
+ export type TransferDocument = {
63
+ version: number;
64
+ /** Stamped by the caller; the engine has no clock of its own to trust. */
65
+ exportedAt?: string;
66
+ connection: {
67
+ name: string;
68
+ slug: string;
69
+ baseUrl: string;
70
+ description?: string | null;
71
+ authType: string;
72
+ authHeaderName?: string | null;
73
+ authQueryParam?: string | null;
74
+ extraHeaders?: Record<string, string> | null;
75
+ tokenUrl?: string | null;
76
+ oauthGrantType?: string | null;
77
+ oauthClientId?: string | null;
78
+ oauthUsername?: string | null;
79
+ oauthScope?: string | null;
80
+ oauthClientAuth?: string | null;
81
+ tlsVerify?: boolean;
82
+ timeoutMs?: number | null;
83
+ enabled?: boolean;
84
+ };
85
+ endpoints: TransferEndpoint[];
86
+ mappings: TransferMapping[];
87
+ /**
88
+ * Named so the person opening the file knows what it cannot do on its own.
89
+ * Read by nothing; it exists to be read by a human.
90
+ */
91
+ secretsExcluded: true;
92
+ };
93
+ /** True when a row carries something that must not be exported. Used by tests. */
94
+ export declare function hasSecret(row: Record<string, unknown>): boolean;
95
+ /**
96
+ * Builds the document from rows as they are stored.
97
+ *
98
+ * Field by field rather than by spreading the row: a column added to the table
99
+ * later — including the next encrypted one — must not ride out to a file simply
100
+ * because nobody updated this function.
101
+ */
102
+ export declare function buildTransferDocument(input: {
103
+ source: Record<string, unknown>;
104
+ endpoints: Record<string, unknown>[];
105
+ mappings: Record<string, unknown>[];
106
+ exportedAt?: string;
107
+ }): TransferDocument;
108
+ export type TransferProblem = {
109
+ path: string;
110
+ message: string;
111
+ };
112
+ /**
113
+ * Checks a document before anything is written.
114
+ *
115
+ * Refusing a bad file costs one message; accepting one costs a half-built
116
+ * connection that looks configured and imports nothing — or worse, imports into
117
+ * the wrong table.
118
+ */
119
+ export declare function validateTransferDocument(value: unknown): {
120
+ ok: boolean;
121
+ document: TransferDocument | null;
122
+ problems: TransferProblem[];
123
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -11,7 +11,9 @@ export type MappingTransform = 'none' | 'trim' | 'upper' | 'lower' | 'toString'
11
11
  /** Folds accents, lowercases, and removes what an address cannot contain. */
12
12
  | 'emailSafe'
13
13
  /** The last part of a path-like value: `A/B/C` → `C`. */
14
- | 'pathLeaf';
14
+ | 'pathLeaf'
15
+ /** Wraps a value as a list, for a column that holds one: `100712` → `['100712']`. */
16
+ | 'toList';
15
17
  /** One field of a mapping: external `source` path → internal `target` column. */
16
18
  export type FieldMapping = {
17
19
  /** Dot-path into the external record, e.g. `employeeNo` or `department.code`. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nucleus-core-ts",
3
- "version": "0.9.821",
3
+ "version": "0.9.822",
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",