nucleus-core-ts 0.9.811 → 0.9.813

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.
@@ -80,6 +80,7 @@ export declare function previewRun(chain: ResolvedChain, tokenCache: TokenCache,
80
80
  }[]>;
81
81
  readEntityColumn: (entity: string, field: string) => Promise<unknown[]>;
82
82
  requiredFields: (entity: string) => string[];
83
+ uniqueFields: (entity: string) => string[];
83
84
  }, deps?: {
84
85
  fetchImpl?: typeof fetch;
85
86
  maxRecords?: number;
@@ -76,6 +76,14 @@ export declare function resolveEndpointContext(deps: RepositoryDeps, by: {
76
76
  export declare function cacheEndpointSample(deps: RepositoryDeps, endpointId: string, records: readonly unknown[]): Promise<void>;
77
77
  /** Columns of a target that must carry a value, for pre-write validation. */
78
78
  export declare function requiredFieldsOf(entities: NucleusTable[], targetEntity: string): string[];
79
+ /**
80
+ * Columns the target enforces as unique, single-column only.
81
+ *
82
+ * A composite unique index is not a value one record can be said to duplicate,
83
+ * so it is left to the database — the point here is to name the two records that
84
+ * clash, and for a pair of columns there is nothing useful to name.
85
+ */
86
+ export declare function uniqueFieldsOf(entities: NucleusTable[], targetEntity: string): string[];
79
87
  export declare function createRunRepository(deps: RepositoryDeps, entities: NucleusTable[]): RunRepository;
80
88
  /** Current contents of the rows a revert is about to touch, keyed by id. */
81
89
  export declare function readRowsById(deps: RepositoryDeps, targetEntity: string, ids: string[]): Promise<Map<string, Record<string, unknown>>>;
@@ -56,6 +56,16 @@ export type PlanInput = {
56
56
  missingValue?: string | null;
57
57
  /** NOT NULL, no-default columns of the target — a row missing one cannot be written. */
58
58
  requiredFields?: readonly string[];
59
+ /**
60
+ * Columns the target enforces as unique.
61
+ *
62
+ * Checked here so a collision is a reported record rather than a rolled-back
63
+ * import. Two people called Ayşe Yılmaz produce the same generated address,
64
+ * and letting Postgres discover that means all eight hundred rows are lost to
65
+ * one duplicate — with a driver message naming a constraint instead of the two
66
+ * records that clashed.
67
+ */
68
+ uniqueFields?: readonly string[];
59
69
  /**
60
70
  * Values the engine puts on every NEW record, under whatever the source
61
71
  * carries.
@@ -98,6 +98,8 @@ export type RunRepository = {
98
98
  readEntityColumn(entity: string, field: string): Promise<unknown[]>;
99
99
  /** NOT NULL, no-default columns of the target. */
100
100
  requiredFields(targetEntity: string): string[];
101
+ /** Single-column unique constraints of the target. */
102
+ uniqueFields(targetEntity: string): string[];
101
103
  };
102
104
  export type RunnerDeps = {
103
105
  repo: RunRepository;
@@ -7,7 +7,9 @@
7
7
  * operator registered.
8
8
  */
9
9
  /** A per-field transform applied to a source value before it lands in a column. */
10
- export type MappingTransform = 'none' | 'trim' | 'upper' | 'lower' | 'toString' | 'toNumber' | 'toBoolean' | 'dateOnly';
10
+ export type MappingTransform = 'none' | 'trim' | 'upper' | 'lower' | 'toString' | 'toNumber' | 'toBoolean' | 'dateOnly'
11
+ /** Folds accents, lowercases, and removes what an address cannot contain. */
12
+ | 'emailSafe';
11
13
  /** One field of a mapping: external `source` path → internal `target` column. */
12
14
  export type FieldMapping = {
13
15
  /** Dot-path into the external record, e.g. `employeeNo` or `department.code`. */
@@ -17,7 +19,15 @@ export type FieldMapping = {
17
19
  transform?: MappingTransform;
18
20
  /** Used INSTEAD of reading `source` — a fixed value for every row. */
19
21
  constant?: string;
20
- /** Used when the source value resolves to null/undefined/empty. */
22
+ /**
23
+ * Used when the source value resolves to null/undefined/empty.
24
+ *
25
+ * Accepts the same `{field}` templates as `source`, so a record that arrives
26
+ * without an address can still be given one built from the fields it does
27
+ * have — `{ad}.{soyad}@example.com`. The transform is applied to it as well,
28
+ * which is what turns `Ayşe Yılmaz` into something that can be typed into a
29
+ * login box.
30
+ */
21
31
  fallback?: string;
22
32
  };
23
33
  /**
@@ -121,7 +131,7 @@ export type RunStatus = 'queued' | 'running' | 'succeeded' | 'failed' | 'cancell
121
131
  */
122
132
  export type RunIssue = {
123
133
  sourceIndex: number;
124
- kind: 'missing_required' | 'missing_dedup_key' | 'duplicate_in_batch' | 'invalid_value' | 'unmapped' | 'missing_reference';
134
+ kind: 'missing_required' | 'missing_dedup_key' | 'duplicate_in_batch' | 'duplicate_value' | 'invalid_value' | 'unmapped' | 'missing_reference';
125
135
  message: string;
126
136
  dedupKey?: string | null;
127
137
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nucleus-core-ts",
3
- "version": "0.9.811",
3
+ "version": "0.9.813",
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",