@dudousxd/nestjs-catalog 0.12.0 → 0.13.0
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/catalog.events.d.ts +10 -3
- package/dist/catalog.pipeline.d.ts +283 -0
- package/dist/catalog.pipeline.js +24 -0
- package/dist/catalog.store.d.ts +25 -0
- package/dist/catalog.store.js +70 -1
- package/dist/client.d.ts +109 -0
- package/dist/client.js +56 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +6 -2
- package/package.json +1 -1
package/dist/catalog.events.d.ts
CHANGED
|
@@ -106,10 +106,17 @@ export interface CatalogEventPayloads {
|
|
|
106
106
|
snapshotId: string;
|
|
107
107
|
};
|
|
108
108
|
/**
|
|
109
|
-
* Someone changed a label, description, unit or visibility
|
|
109
|
+
* Someone changed a label, description, unit or visibility — or stated how a
|
|
110
|
+
* type reconciles deletes.
|
|
110
111
|
*
|
|
111
|
-
* Presentation
|
|
112
|
-
* is a governance question
|
|
112
|
+
* Presentation was the whole of it once, and emitted anyway: "who renamed this
|
|
113
|
+
* column and when" is a governance question whose answer is otherwise nowhere.
|
|
114
|
+
* Per-type load expectations then arrived on the same event, and a delete
|
|
115
|
+
* strategy is not presentation — it decides whether an incremental load of the
|
|
116
|
+
* type may commit at all. `changed` tells the two apart (`expectation.deletes`
|
|
117
|
+
* and `expectation.cleared` against the field names a rename carries), which is
|
|
118
|
+
* why widening this event was better than minting a second one nobody's
|
|
119
|
+
* recorder would have been reading.
|
|
113
120
|
*/
|
|
114
121
|
'type.curated': {
|
|
115
122
|
typeName: string;
|
|
@@ -122,6 +122,211 @@ export interface CatalogConnector {
|
|
|
122
122
|
lastRunAt?: string;
|
|
123
123
|
lastRunStatus?: 'succeeded' | 'failed' | 'running';
|
|
124
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* What a load has to be true of before it is allowed to become the data
|
|
127
|
+
* everybody reads.
|
|
128
|
+
*
|
|
129
|
+
* Two failures live here, and they are the same failure seen from two ends: a
|
|
130
|
+
* load that is *fresh and wrong*. Every signal this catalog publishes about a
|
|
131
|
+
* type — `lastCommittedAt`, the age badge on the Model screen, a green run in
|
|
132
|
+
* the runs list — reports on whether a load HAPPENED. None of them reports on
|
|
133
|
+
* whether what it loaded resembles the dataset it replaced, and a snapshot
|
|
134
|
+
* commit is atomic, so the moment a wrong load commits it is indistinguishable
|
|
135
|
+
* from a right one until somebody counts rows by hand.
|
|
136
|
+
*
|
|
137
|
+
* - **Deletes.** An incremental connector asks its source for what changed
|
|
138
|
+
* since a watermark. A row physically removed from the source never changes
|
|
139
|
+
* again, so it is never returned again, so `carryForward` copies it into
|
|
140
|
+
* every subsequent snapshot forever. The catalog does not go wrong at any
|
|
141
|
+
* point; it simply never finds out. See {@link DeleteReconciliation}.
|
|
142
|
+
* - **Collapse.** A source-side filter change, a broken `WHERE`, a partial
|
|
143
|
+
* outage: the connector returns 12 rows where it returned 40,000, the
|
|
144
|
+
* snapshot commits, and the freshness signals all say healthy — correctly,
|
|
145
|
+
* because it IS fresh. See {@link RowCountBound}.
|
|
146
|
+
*
|
|
147
|
+
* **Why a policy object and not a column on the connector.** Both facts are
|
|
148
|
+
* statements about a *type*, not about the reader of a source. "It is
|
|
149
|
+
* acceptable that `Employee` accumulates rows deleted upstream" and "`Employee`
|
|
150
|
+
* must never lose half its rows in one load" stay true whether the rows arrive
|
|
151
|
+
* from a connector, from a workflow sink, or from an application POSTing to the
|
|
152
|
+
* publish API — and all three of those paths end at the same two methods on
|
|
153
|
+
* `PublishService`, which is where these are enforced. A per-connector field
|
|
154
|
+
* would have covered one of the three and would have had to be checked in three
|
|
155
|
+
* places to cover the rest.
|
|
156
|
+
*
|
|
157
|
+
* The second reason is who should be able to change it. Accepting that a
|
|
158
|
+
* dataset silently accumulates deleted rows is not a checkbox decision; it is
|
|
159
|
+
* the kind of thing that should appear in a diff with a reason attached, which
|
|
160
|
+
* is why {@link DeleteReconciliation} makes the reason a required field.
|
|
161
|
+
*/
|
|
162
|
+
export interface CatalogLoadExpectations {
|
|
163
|
+
/** Applied to every type that has no entry of its own. */
|
|
164
|
+
default?: LoadExpectation;
|
|
165
|
+
/**
|
|
166
|
+
* Keyed by object type name. Merged OVER {@link default} field by field, so a
|
|
167
|
+
* host can set one house-wide row-count bound and still say something about
|
|
168
|
+
* deletes for the three types that are loaded incrementally.
|
|
169
|
+
*/
|
|
170
|
+
byType?: Record<string, LoadExpectation>;
|
|
171
|
+
}
|
|
172
|
+
export interface LoadExpectation {
|
|
173
|
+
/**
|
|
174
|
+
* How deletions at the source reach this type. **Absent means the load is
|
|
175
|
+
* refused**, which is the whole mechanism — see {@link
|
|
176
|
+
* refuseUndeclaredDeletes}.
|
|
177
|
+
*/
|
|
178
|
+
deletes?: DeleteReconciliation;
|
|
179
|
+
/**
|
|
180
|
+
* How far one load may move this type's row count. Merged over
|
|
181
|
+
* {@link DEFAULT_ROW_COUNT_BOUND}, so a host that only wants to raise
|
|
182
|
+
* `maxShrink` writes exactly that one field.
|
|
183
|
+
*/
|
|
184
|
+
rowCount?: Partial<RowCountBound>;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* How a type that is loaded incrementally learns about rows that were deleted.
|
|
188
|
+
*
|
|
189
|
+
* Three answers, and the honest thing to say about them up front is that only
|
|
190
|
+
* one is *policed*. What this file enforces is that somebody chose one and
|
|
191
|
+
* wrote down why — because the state being prevented is nobody having thought
|
|
192
|
+
* about it at all, and that state is invisible by construction.
|
|
193
|
+
*
|
|
194
|
+
* The fourth answer, tombstones off a change feed, is the correct one and is
|
|
195
|
+
* deliberately not here. It needs the source to publish a delete stream, the
|
|
196
|
+
* catalog to hold a delete log per type, and the merge to apply it — which is
|
|
197
|
+
* a larger machine than the problem justifies today, and adding a strategy name
|
|
198
|
+
* that nothing implements would be exactly the dropdown-with-a-lie this
|
|
199
|
+
* codebase refuses everywhere else.
|
|
200
|
+
*/
|
|
201
|
+
export type DeleteReconciliation =
|
|
202
|
+
/**
|
|
203
|
+
* Nothing reconciles them, and that is a decision somebody made.
|
|
204
|
+
*
|
|
205
|
+
* The legitimate cases are real and common: an append-only ledger where rows
|
|
206
|
+
* are never removed, a source that only ever soft-retires records by changing
|
|
207
|
+
* a status the transform can see, or a dataset where a handful of stale rows
|
|
208
|
+
* is genuinely cheaper than a nightly full read. What is not legitimate is
|
|
209
|
+
* arriving here by default, which is why {@link because} cannot be omitted.
|
|
210
|
+
*/
|
|
211
|
+
{
|
|
212
|
+
strategy: 'accepted';
|
|
213
|
+
because: string;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* The source marks a deletion instead of performing one, and the watermark
|
|
217
|
+
* therefore sees it — a `deleted_at` that moves, a status column that flips —
|
|
218
|
+
* so the deleted row arrives as an ordinary change and the transform drops it
|
|
219
|
+
* or the type keeps it flagged.
|
|
220
|
+
*
|
|
221
|
+
* The strongest of the three, and the one that pushes a requirement onto a
|
|
222
|
+
* source that may refuse it. Not verifiable from here: the catalog cannot
|
|
223
|
+
* tell a source that soft-deletes from one that claims to, so this is a
|
|
224
|
+
* declaration like the one above. It is a separate value anyway because the
|
|
225
|
+
* two say completely different things to the next person who reads the
|
|
226
|
+
* config, and collapsing them would lose that.
|
|
227
|
+
*/
|
|
228
|
+
| {
|
|
229
|
+
strategy: 'soft-deleted-at-source';
|
|
230
|
+
because: string;
|
|
231
|
+
column?: string;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Full reads reconcile, incremental reads fill the gaps between them.
|
|
235
|
+
*
|
|
236
|
+
* The interval is the trade-off, and it is stated in time rather than in runs
|
|
237
|
+
* because "reconciled daily" is what anybody actually means and because the
|
|
238
|
+
* only thing the catalog can count is the snapshots a store chooses to
|
|
239
|
+
* report, which is a window of unknown depth. {@link refuseStaleReconciliation}
|
|
240
|
+
* makes the interval real: once the newest full load of the type is older
|
|
241
|
+
* than `withinMs`, incremental loads of it stop committing.
|
|
242
|
+
*/
|
|
243
|
+
| {
|
|
244
|
+
strategy: 'periodic-full-reload';
|
|
245
|
+
because: string;
|
|
246
|
+
withinMs: number;
|
|
247
|
+
};
|
|
248
|
+
/**
|
|
249
|
+
* How far a single load may move a type's row count before it is refused.
|
|
250
|
+
*
|
|
251
|
+
* **Asymmetric on purpose.** A type that doubles has usually had a good day —
|
|
252
|
+
* a backfill landed, a new base was onboarded, a source finished catching up.
|
|
253
|
+
* A type that loses 90% has almost never had a good day. Bounding both sides by
|
|
254
|
+
* the same number would mean picking a growth bound loose enough to be useless
|
|
255
|
+
* as a shrink bound, or a shrink bound tight enough to refuse every backfill.
|
|
256
|
+
*
|
|
257
|
+
* **Conditional on the store, and a host configuring this should know which
|
|
258
|
+
* condition.** {@link refuseRowCountDrift} is pure and decides on two numbers;
|
|
259
|
+
* somebody has to fetch them, and both come from members that are optional on
|
|
260
|
+
* the store interface. Without `currentSnapshot` there is no served baseline;
|
|
261
|
+
* without `listSnapshots`, or from a `listSnapshots` whose window does not
|
|
262
|
+
* reach the snapshot about to be committed, there is no count for the pending
|
|
263
|
+
* one. Either way the bound is not applied to that commit. That is the same
|
|
264
|
+
* permissive-rather-than-punishing stance {@link CARRIED_FROM_LABEL} takes for
|
|
265
|
+
* the same reason — an adapter that records less than the bundled one is not
|
|
266
|
+
* the failure this file exists for — but it means a number written here is a
|
|
267
|
+
* bound the store has to be able to measure, not one it is guaranteed to have.
|
|
268
|
+
* `PublishService.assertRowCountIsPlausible` is where that is decided; a skip
|
|
269
|
+
* that is not said out loud there is a bound believed to be on and off, which
|
|
270
|
+
* is the one outcome neither this file nor that one may produce.
|
|
271
|
+
*/
|
|
272
|
+
export interface RowCountBound {
|
|
273
|
+
/**
|
|
274
|
+
* The largest fraction of the previously served snapshot a load may lose.
|
|
275
|
+
* `0.5` refuses a load that comes back with less than half of what is live.
|
|
276
|
+
*/
|
|
277
|
+
maxShrink: number;
|
|
278
|
+
/**
|
|
279
|
+
* The ratio above which growth is refused — `10` refuses a load ten times the
|
|
280
|
+
* size of the previous one. **Absent means growth is never refused**, which is
|
|
281
|
+
* the default, because the failure this file exists for is collapse and a
|
|
282
|
+
* growth bound that fires on a legitimate backfill teaches people to raise
|
|
283
|
+
* every bound in this object until none of them do anything.
|
|
284
|
+
*/
|
|
285
|
+
maxGrowth?: number;
|
|
286
|
+
/**
|
|
287
|
+
* Below this many rows in the previously served snapshot, no ratio applies.
|
|
288
|
+
*
|
|
289
|
+
* A percentage of a small number is noise. A four-row lookup table dropping to
|
|
290
|
+
* one is a 75% collapse and is also a Tuesday, and a bound that fires on it is
|
|
291
|
+
* a bound somebody switches off — taking the forty-thousand-row types with it.
|
|
292
|
+
*/
|
|
293
|
+
minRows: number;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* A per-type expectation as an operator set it, with who and when.
|
|
297
|
+
*
|
|
298
|
+
* The layer between a host's `byType` entry and its `default`. It exists because
|
|
299
|
+
* the control the docblocks above argue for was never "it must be in code" —
|
|
300
|
+
* it is that **somebody chose a strategy and wrote down why**, which needs
|
|
301
|
+
* attribution and visibility rather than compilation. A host object gives the
|
|
302
|
+
* reason a place to live and gives attribution to nobody: a `git blame` on a
|
|
303
|
+
* deployment's wiring names whoever last reformatted the file. So the reason
|
|
304
|
+
* arrives with the principal that set it and the instant they did, and the
|
|
305
|
+
* declaration requirement is unchanged — {@link refuseUndeclaredDeletes} asks
|
|
306
|
+
* the same question of a stored row as it does of a host one.
|
|
307
|
+
*
|
|
308
|
+
* The grain is still the type, and only the type. A connector, a workflow sink
|
|
309
|
+
* and an application POSTing to the publish API all end at the same two
|
|
310
|
+
* `PublishService` methods and all have the same delete problem, so a per-
|
|
311
|
+
* connector or per-workflow row would give one dataset several answers to one
|
|
312
|
+
* question — see {@link CatalogLoadExpectations}, which argues it at length and
|
|
313
|
+
* is unaffected by this layer existing.
|
|
314
|
+
*
|
|
315
|
+
* Both policy fields are optional, and a row may carry either, both or neither:
|
|
316
|
+
* precedence is resolved field by field, so an operator raising a shrink bound
|
|
317
|
+
* says nothing about deletes and does not have to.
|
|
318
|
+
*/
|
|
319
|
+
export interface StoredLoadExpectation {
|
|
320
|
+
typeName: string;
|
|
321
|
+
deletes?: DeleteReconciliation;
|
|
322
|
+
rowCount?: Partial<RowCountBound>;
|
|
323
|
+
/** Principal id of whoever set it. */
|
|
324
|
+
setBy: string;
|
|
325
|
+
/** Actor id when a person was behind the principal — the audit's real subject. */
|
|
326
|
+
setByActor?: string;
|
|
327
|
+
/** ISO 8601. */
|
|
328
|
+
setAt: string;
|
|
329
|
+
}
|
|
125
330
|
/**
|
|
126
331
|
* TypeScript is Node's own type stripping, so it costs no compiler and no build
|
|
127
332
|
* step — and types are erased, never checked. A transform with a wrong type
|
|
@@ -852,6 +1057,37 @@ export declare function supportsWorkflows(store: CatalogPipelineStore): store is
|
|
|
852
1057
|
*/
|
|
853
1058
|
export declare function supportsTransformRevisions(store: CatalogPipelineStore): store is CatalogPipelineStore & Required<Pick<CatalogPipelineStore, 'listTransformRevisions'>>;
|
|
854
1059
|
export declare function supportsWorkflowStages(store: CatalogPipelineStore): store is CatalogPipelineStore & CatalogStageStore;
|
|
1060
|
+
/**
|
|
1061
|
+
* A store that really does hold operator-set expectations, all four members
|
|
1062
|
+
* present.
|
|
1063
|
+
*
|
|
1064
|
+
* Derived from {@link CatalogPipelineStore} rather than declared as a separate
|
|
1065
|
+
* interface the way {@link CatalogWorkflowStore} is, and the difference is not
|
|
1066
|
+
* stylistic: these four are optional members OF the pipeline store, so writing
|
|
1067
|
+
* them out a second time here would be a copy that can drift from the one the
|
|
1068
|
+
* signatures are read from. `CatalogWorkflowStore` predates that lesson and is
|
|
1069
|
+
* mixed in through `Partial<>`, which reaches the same place from the other
|
|
1070
|
+
* side.
|
|
1071
|
+
*/
|
|
1072
|
+
export type CatalogLoadExpectationStore = Required<Pick<CatalogPipelineStore, 'listLoadExpectations' | 'getLoadExpectation' | 'saveLoadExpectation' | 'clearLoadExpectation'>>;
|
|
1073
|
+
/**
|
|
1074
|
+
* Whether an operator can set a load expectation on this deployment at all.
|
|
1075
|
+
*
|
|
1076
|
+
* The methods rather than a flag, the same argument as {@link supportsWorkflows}
|
|
1077
|
+
* — and all four of them by name rather than one standing in for the rest, for
|
|
1078
|
+
* that function's other reason: the write path and the read path are used at
|
|
1079
|
+
* different moments, so a store with the getter and not the setter would narrow
|
|
1080
|
+
* cleanly here and fail on the save, after the screen had already offered an
|
|
1081
|
+
* editor.
|
|
1082
|
+
*
|
|
1083
|
+
* A store that has none of them is not broken and is not second-class. It
|
|
1084
|
+
* behaves exactly as every store did before this existed: the host's
|
|
1085
|
+
* `CATALOG_LOAD_EXPECTATIONS` object is the only layer, which is a complete and
|
|
1086
|
+
* supported answer. What this probe buys is that the console can say "this
|
|
1087
|
+
* deployment's store cannot hold operator-set expectations" instead of offering
|
|
1088
|
+
* an editor whose save has nowhere to go.
|
|
1089
|
+
*/
|
|
1090
|
+
export declare function supportsLoadExpectations(store: CatalogPipelineStore): store is CatalogPipelineStore & CatalogLoadExpectationStore;
|
|
855
1091
|
export interface CatalogPipelineStore extends Partial<CatalogWorkflowStore>, Partial<CatalogStageStore> {
|
|
856
1092
|
listConnectors(): Promise<CatalogConnector[]>;
|
|
857
1093
|
getConnector(id: string): Promise<CatalogConnector | undefined>;
|
|
@@ -905,6 +1141,53 @@ export interface CatalogPipelineStore extends Partial<CatalogWorkflowStore>, Par
|
|
|
905
1141
|
* that bound costs.
|
|
906
1142
|
*/
|
|
907
1143
|
listTransformRevisions?(id: string): Promise<CatalogRevision[]>;
|
|
1144
|
+
/**
|
|
1145
|
+
* Per-type load expectations as an operator set them.
|
|
1146
|
+
*
|
|
1147
|
+
* **Optional**, and here more deliberately than anywhere else in this
|
|
1148
|
+
* interface. `@dudousxd/nestjs-catalog-store-mikro-orm` is not the only
|
|
1149
|
+
* implementation — a host may have written its own against an earlier shape of
|
|
1150
|
+
* this file — and every one of them satisfies `CatalogPipelineStore` today.
|
|
1151
|
+
* Widening it with four required members would turn all of them into compile
|
|
1152
|
+
* errors for a feature that is purely additive, and, worse, would do it
|
|
1153
|
+
* *silently* to the ones checked structurally: `isPipelineStore` and the
|
|
1154
|
+
* `supports*` probes narrow on methods, so a store that no longer satisfies
|
|
1155
|
+
* the interface is discovered by a caller, at run time, rather than by a build.
|
|
1156
|
+
* {@link supportsLoadExpectations} is how a caller asks, and a store that
|
|
1157
|
+
* implements none of these behaves exactly as it does today — the host's
|
|
1158
|
+
* `CATALOG_LOAD_EXPECTATIONS` object is then the whole policy.
|
|
1159
|
+
*
|
|
1160
|
+
* These hold rows; they do not resolve them. Precedence — a host's `byType`
|
|
1161
|
+
* entry over a stored row over the host's `default`, field by field — is the
|
|
1162
|
+
* pipeline package's business, beside the enforcement functions that consume
|
|
1163
|
+
* it, and it stays pure and synchronous. A store that resolved would be a
|
|
1164
|
+
* second place the precedence is decided, which for a policy whose whole point
|
|
1165
|
+
* is "somebody decided this" is the one duplication that cannot be tolerated.
|
|
1166
|
+
*/
|
|
1167
|
+
listLoadExpectations?(): Promise<StoredLoadExpectation[]>;
|
|
1168
|
+
getLoadExpectation?(typeName: string): Promise<StoredLoadExpectation | undefined>;
|
|
1169
|
+
/**
|
|
1170
|
+
* Upsert, keyed by type name, recording the principal and the instant.
|
|
1171
|
+
*
|
|
1172
|
+
* `setBy` and `setByActor` are arguments rather than fields on the
|
|
1173
|
+
* `expectation` for the reason `startRun` records attribution the way it does:
|
|
1174
|
+
* a caller cannot claim them. `setAt` is not an input at all — a stored
|
|
1175
|
+
* timestamp a client could choose is not an audit record.
|
|
1176
|
+
*
|
|
1177
|
+
* `setByActor` is the person behind the principal when there was one. The
|
|
1178
|
+
* write route requires a human, so in practice there always is; it is
|
|
1179
|
+
* separate from `setBy` because a principal is a key and an actor is a
|
|
1180
|
+
* subject, and the trail needs the second to answer "who decided this".
|
|
1181
|
+
*/
|
|
1182
|
+
saveLoadExpectation?(typeName: string, expectation: Pick<StoredLoadExpectation, 'deletes' | 'rowCount'>, setBy: string, setByActor?: string): Promise<StoredLoadExpectation>;
|
|
1183
|
+
/**
|
|
1184
|
+
* Drop the stored row for a type. The host's layer is untouched, so a type the
|
|
1185
|
+
* deployment declared in code keeps that declaration.
|
|
1186
|
+
*
|
|
1187
|
+
* `false` means there was nothing stored, which is a fact a caller may report
|
|
1188
|
+
* and never an error.
|
|
1189
|
+
*/
|
|
1190
|
+
clearLoadExpectation?(typeName: string): Promise<boolean>;
|
|
908
1191
|
startRun(input: {
|
|
909
1192
|
connectorId: string;
|
|
910
1193
|
snapshotId: string;
|
package/dist/catalog.pipeline.js
CHANGED
|
@@ -23,6 +23,7 @@ exports.isWorkflowEdge = isWorkflowEdge;
|
|
|
23
23
|
exports.supportsWorkflows = supportsWorkflows;
|
|
24
24
|
exports.supportsTransformRevisions = supportsTransformRevisions;
|
|
25
25
|
exports.supportsWorkflowStages = supportsWorkflowStages;
|
|
26
|
+
exports.supportsLoadExpectations = supportsLoadExpectations;
|
|
26
27
|
exports.isPipelineStore = isPipelineStore;
|
|
27
28
|
/**
|
|
28
29
|
* Where a connector pulls from.
|
|
@@ -729,6 +730,29 @@ function supportsTransformRevisions(store) {
|
|
|
729
730
|
function supportsWorkflowStages(store) {
|
|
730
731
|
return typeof store.writeStage === 'function' && typeof store.readStage === 'function';
|
|
731
732
|
}
|
|
733
|
+
/**
|
|
734
|
+
* Whether an operator can set a load expectation on this deployment at all.
|
|
735
|
+
*
|
|
736
|
+
* The methods rather than a flag, the same argument as {@link supportsWorkflows}
|
|
737
|
+
* — and all four of them by name rather than one standing in for the rest, for
|
|
738
|
+
* that function's other reason: the write path and the read path are used at
|
|
739
|
+
* different moments, so a store with the getter and not the setter would narrow
|
|
740
|
+
* cleanly here and fail on the save, after the screen had already offered an
|
|
741
|
+
* editor.
|
|
742
|
+
*
|
|
743
|
+
* A store that has none of them is not broken and is not second-class. It
|
|
744
|
+
* behaves exactly as every store did before this existed: the host's
|
|
745
|
+
* `CATALOG_LOAD_EXPECTATIONS` object is the only layer, which is a complete and
|
|
746
|
+
* supported answer. What this probe buys is that the console can say "this
|
|
747
|
+
* deployment's store cannot hold operator-set expectations" instead of offering
|
|
748
|
+
* an editor whose save has nowhere to go.
|
|
749
|
+
*/
|
|
750
|
+
function supportsLoadExpectations(store) {
|
|
751
|
+
return (typeof store.listLoadExpectations === 'function' &&
|
|
752
|
+
typeof store.getLoadExpectation === 'function' &&
|
|
753
|
+
typeof store.saveLoadExpectation === 'function' &&
|
|
754
|
+
typeof store.clearLoadExpectation === 'function');
|
|
755
|
+
}
|
|
732
756
|
exports.CATALOG_PIPELINE_STORE = Symbol('CATALOG_PIPELINE_STORE');
|
|
733
757
|
function isPipelineStore(store) {
|
|
734
758
|
return (typeof store === 'object' &&
|
package/dist/catalog.store.d.ts
CHANGED
|
@@ -345,6 +345,31 @@ export interface CatalogMergeStore extends CatalogWriteStore {
|
|
|
345
345
|
export declare const CATALOG_RESERVED_COLUMNS: readonly ["_snapshot_id", "_principal_id", "_loaded_at", "_batch", "_row"];
|
|
346
346
|
export type CatalogReservedColumn = (typeof CATALOG_RESERVED_COLUMNS)[number];
|
|
347
347
|
export declare function isReservedColumn(column: string): boolean;
|
|
348
|
+
/**
|
|
349
|
+
* Why a name cannot be written into SQL, in the words a publisher is given.
|
|
350
|
+
*
|
|
351
|
+
* One class for the whole ecosystem rather than one per adapter, so
|
|
352
|
+
* `instanceof` is a usable question across packages. The publish-time check in
|
|
353
|
+
* the pipeline package catches this to tell "that name cannot be an identifier"
|
|
354
|
+
* from "something else failed inside the store", and with a class per adapter
|
|
355
|
+
* that check would re-throw the moment the mounted store was not the one it
|
|
356
|
+
* imported — turning a 400 that names the property into a 500 that names
|
|
357
|
+
* nothing.
|
|
358
|
+
*/
|
|
359
|
+
export declare class UnsafeIdentifierError extends Error {
|
|
360
|
+
constructor(value: string);
|
|
361
|
+
}
|
|
362
|
+
/** Whether a name can be written into SQL as it stands. */
|
|
363
|
+
export declare function isSafeIdentifier(value: string): boolean;
|
|
364
|
+
/**
|
|
365
|
+
* Refuse a name that cannot be a SQL identifier.
|
|
366
|
+
*
|
|
367
|
+
* Throws rather than answering, because the caller's next line writes the value
|
|
368
|
+
* into a statement: a boolean that can be ignored is a boolean that eventually
|
|
369
|
+
* is. {@link isSafeIdentifier} is there for the callers that are asking rather
|
|
370
|
+
* than about to build.
|
|
371
|
+
*/
|
|
372
|
+
export declare function assertSafeIdentifier(value: string): void;
|
|
348
373
|
/** One property, and the column it cannot have. */
|
|
349
374
|
export interface CatalogColumnCollision {
|
|
350
375
|
/** `reserved` — it lands on a store column. `shared` — two properties collide. */
|
package/dist/catalog.store.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CATALOG_STORE = exports.CatalogColumnCollisionError = exports.CATALOG_RESERVED_COLUMNS = exports.CATALOG_SNAPSHOT_MODES = void 0;
|
|
3
|
+
exports.CATALOG_STORE = exports.CatalogColumnCollisionError = exports.UnsafeIdentifierError = exports.CATALOG_RESERVED_COLUMNS = exports.CATALOG_SNAPSHOT_MODES = void 0;
|
|
4
4
|
exports.isCatalogStoreCapabilities = isCatalogStoreCapabilities;
|
|
5
5
|
exports.isReservedColumn = isReservedColumn;
|
|
6
|
+
exports.isSafeIdentifier = isSafeIdentifier;
|
|
7
|
+
exports.assertSafeIdentifier = assertSafeIdentifier;
|
|
6
8
|
exports.findColumnCollisions = findColumnCollisions;
|
|
7
9
|
exports.assertNoColumnCollisions = assertNoColumnCollisions;
|
|
8
10
|
exports.isWriteStore = isWriteStore;
|
|
@@ -72,6 +74,73 @@ exports.CATALOG_RESERVED_COLUMNS = [
|
|
|
72
74
|
function isReservedColumn(column) {
|
|
73
75
|
return exports.CATALOG_RESERVED_COLUMNS.some((reserved) => reserved === column.toLowerCase());
|
|
74
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* What a name has to look like before a store will write it into SQL.
|
|
79
|
+
*
|
|
80
|
+
* Identifiers are *rejected*, never escaped and never sanitised. Every table
|
|
81
|
+
* and column name a store emits arrives from another application over HTTP and
|
|
82
|
+
* ends up in DDL and in SELECT lists, where no placeholder can stand in for it,
|
|
83
|
+
* so anything outside this character set never becomes SQL at all.
|
|
84
|
+
*
|
|
85
|
+
* Here, beside {@link CATALOG_RESERVED_COLUMNS}, for the same reason: it is
|
|
86
|
+
* part of what the catalog promises a *publisher*. Refuse a property name and
|
|
87
|
+
* the sentence explaining why is the only statement of the rule most people
|
|
88
|
+
* will ever read, so it belongs to the contract rather than to whichever
|
|
89
|
+
* adapter happens to be mounted.
|
|
90
|
+
*
|
|
91
|
+
* And for one more reason. It used to be two copies — `store-mikro-orm` and
|
|
92
|
+
* `store-clickhouse` each carried this pattern and this sentence, byte for
|
|
93
|
+
* byte — and the publish-time refusal in the pipeline package borrowed the
|
|
94
|
+
* MySQL one so that publish-time and DDL-time could not disagree about the
|
|
95
|
+
* character set, the length or the wording. That bought the guarantee for a
|
|
96
|
+
* MySQL deployment and left a ClickHouse-only one trusting two files to be
|
|
97
|
+
* edited together. One definition is the guarantee; two identical ones are a
|
|
98
|
+
* habit.
|
|
99
|
+
*
|
|
100
|
+
* 63 characters because it is under MySQL's 64-character ceiling and no engine
|
|
101
|
+
* a store here targets refuses a name that short, and because the number is
|
|
102
|
+
* quoted in the refusal below: a per-store limit would mean a publisher being
|
|
103
|
+
* told a different rule depending on what is mounted, for a name the catalog
|
|
104
|
+
* would then be unable to promise anything about across a fan-out.
|
|
105
|
+
*
|
|
106
|
+
* Not exported. A `RegExp` is mutable and shared state, and the two questions
|
|
107
|
+
* anyone has of it — "may I?" and "why not?" — are {@link isSafeIdentifier} and
|
|
108
|
+
* {@link UnsafeIdentifierError}.
|
|
109
|
+
*/
|
|
110
|
+
const SAFE_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]{0,62}$/;
|
|
111
|
+
/**
|
|
112
|
+
* Why a name cannot be written into SQL, in the words a publisher is given.
|
|
113
|
+
*
|
|
114
|
+
* One class for the whole ecosystem rather than one per adapter, so
|
|
115
|
+
* `instanceof` is a usable question across packages. The publish-time check in
|
|
116
|
+
* the pipeline package catches this to tell "that name cannot be an identifier"
|
|
117
|
+
* from "something else failed inside the store", and with a class per adapter
|
|
118
|
+
* that check would re-throw the moment the mounted store was not the one it
|
|
119
|
+
* imported — turning a 400 that names the property into a 500 that names
|
|
120
|
+
* nothing.
|
|
121
|
+
*/
|
|
122
|
+
class UnsafeIdentifierError extends Error {
|
|
123
|
+
constructor(value) {
|
|
124
|
+
super(`Refusing to use "${value}" as a SQL identifier: letters, digits and underscore only, starting with a letter or underscore, 63 characters max.`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
exports.UnsafeIdentifierError = UnsafeIdentifierError;
|
|
128
|
+
/** Whether a name can be written into SQL as it stands. */
|
|
129
|
+
function isSafeIdentifier(value) {
|
|
130
|
+
return SAFE_IDENTIFIER.test(value);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Refuse a name that cannot be a SQL identifier.
|
|
134
|
+
*
|
|
135
|
+
* Throws rather than answering, because the caller's next line writes the value
|
|
136
|
+
* into a statement: a boolean that can be ignored is a boolean that eventually
|
|
137
|
+
* is. {@link isSafeIdentifier} is there for the callers that are asking rather
|
|
138
|
+
* than about to build.
|
|
139
|
+
*/
|
|
140
|
+
function assertSafeIdentifier(value) {
|
|
141
|
+
if (!isSafeIdentifier(value))
|
|
142
|
+
throw new UnsafeIdentifierError(value);
|
|
143
|
+
}
|
|
75
144
|
/**
|
|
76
145
|
* Every way a type's properties would fight over a physical column.
|
|
77
146
|
*
|
package/dist/client.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* own UI. The endpoints alone are not an API; the endpoints plus the response
|
|
10
10
|
* types are.
|
|
11
11
|
*/
|
|
12
|
+
import type { DeleteReconciliation, LoadExpectation, RowCountBound, StoredLoadExpectation } from './catalog.pipeline';
|
|
12
13
|
export type { AuditQuery, CatalogAuditEvent, CatalogRevision, Dashboard, DashboardCard, QueryVisualization, SaveQueryInput, SavedQuery, } from './catalog.workspace';
|
|
13
14
|
export { CATALOG_REVISION_LIMIT } from './catalog.workspace';
|
|
14
15
|
export type { CatalogQueryRelation, CatalogQueryRequest, CatalogQueryResult, } from './catalog.query';
|
|
@@ -106,3 +107,111 @@ export { CONNECTOR_KINDS, isConnectorKind, isTransformLanguage, isWorkflowEdge,
|
|
|
106
107
|
export { validateWorkflow, WORKFLOW_EXECUTION_MODES, WORKFLOW_ISSUE_CODES, WORKFLOW_NODE_ID_PATTERN, WORKFLOW_NODE_KINDS, WORKFLOW_STATUSES, workflowGraphHash, workflowRunOrder, isWorkflowExecutionMode, isWorkflowNodeKind, isWorkflowStatus, } from './catalog.pipeline';
|
|
107
108
|
export type { WorkflowStatus } from './catalog.pipeline';
|
|
108
109
|
export type { CatalogTrace, CatalogTraceList, CatalogTraceOutcome, CatalogTraceSpan, TraceQuery, } from './catalog.workspace';
|
|
110
|
+
export type { CatalogLoadExpectations, DeleteReconciliation, LoadExpectation, RowCountBound, StoredLoadExpectation, } from './catalog.pipeline';
|
|
111
|
+
/**
|
|
112
|
+
* The three answers to "how do deletions at the source reach this type", as a
|
|
113
|
+
* value.
|
|
114
|
+
*
|
|
115
|
+
* A list rather than only the union, because the editor on the Model screen has
|
|
116
|
+
* to offer them and a hand-written array in a component is the copy that drifts
|
|
117
|
+
* — the same argument {@link CONNECTOR_KINDS} makes one screen over. The server
|
|
118
|
+
* validates against this too: a `strategy` off the wire is `string` until
|
|
119
|
+
* something checks it, and the check and the dropdown reading one list is what
|
|
120
|
+
* stops the two from disagreeing about what is acceptable.
|
|
121
|
+
*
|
|
122
|
+
* **There are three and there is deliberately no fourth.** Tombstones off a
|
|
123
|
+
* change feed is the correct answer and needs machinery nothing here has; a
|
|
124
|
+
* strategy name that nothing implements is a dropdown with a lie in it. See
|
|
125
|
+
* `DeleteReconciliation` for the whole argument.
|
|
126
|
+
*/
|
|
127
|
+
export declare const DELETE_RECONCILIATION_STRATEGIES: readonly ["accepted", "soft-deleted-at-source", "periodic-full-reload"];
|
|
128
|
+
export type DeleteReconciliationStrategy = (typeof DELETE_RECONCILIATION_STRATEGIES)[number];
|
|
129
|
+
/** Whether a value off the wire names one of the three. */
|
|
130
|
+
export declare function isDeleteReconciliationStrategy(value: unknown): value is DeleteReconciliationStrategy;
|
|
131
|
+
/**
|
|
132
|
+
* What an operator sends to set a type's expectation.
|
|
133
|
+
*
|
|
134
|
+
* Both fields optional and both meaning "leave this alone" when absent, which is
|
|
135
|
+
* why they are not simply `LoadExpectation`: a request that omits `rowCount`
|
|
136
|
+
* has said nothing about row counts, and reading that as "clear it" would let a
|
|
137
|
+
* form that only renders the delete strategy silently drop a bound somebody set.
|
|
138
|
+
* Clearing the whole stored row is `DELETE`, which is a decision with a verb on
|
|
139
|
+
* it.
|
|
140
|
+
*/
|
|
141
|
+
export interface LoadExpectationInput {
|
|
142
|
+
deletes?: DeleteReconciliation;
|
|
143
|
+
rowCount?: Partial<RowCountBound>;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* The resolved expectation for one type, and which layer won each field.
|
|
147
|
+
*
|
|
148
|
+
* The provenance is the whole reason this is not just a `LoadExpectation`. The
|
|
149
|
+
* policy is sourced from three layers — `host.byType[type]`, then the stored row
|
|
150
|
+
* an operator set, then `host.default` — and a screen that showed only the
|
|
151
|
+
* answer would let somebody edit a field this deployment has pinned in code and
|
|
152
|
+
* watch the edit vanish on the next read, with nothing anywhere saying why.
|
|
153
|
+
* {@link hostLocked} is what lets it say "this deployment fixed it" instead.
|
|
154
|
+
*/
|
|
155
|
+
export interface ResolvedLoadExpectation {
|
|
156
|
+
typeName: string;
|
|
157
|
+
/** The three layers merged, field by field. What the load is actually judged against. */
|
|
158
|
+
resolved: LoadExpectation;
|
|
159
|
+
/**
|
|
160
|
+
* Which layer supplied the delete strategy.
|
|
161
|
+
*
|
|
162
|
+
* `'default'` means the host's house-wide `default` did. `'none'` means
|
|
163
|
+
* nothing did, anywhere — which is not a gap to be filled in silently: it is
|
|
164
|
+
* the state that refuses every incremental load of this type, and the one the
|
|
165
|
+
* screen most needs to name.
|
|
166
|
+
*/
|
|
167
|
+
deletesFrom: 'host' | 'stored' | 'default' | 'none';
|
|
168
|
+
/**
|
|
169
|
+
* Which layer supplied the row-count bound — the strongest one that set any
|
|
170
|
+
* field of it, since the three are merged key by key rather than replaced
|
|
171
|
+
* whole.
|
|
172
|
+
*
|
|
173
|
+
* There is no `'none'`, and that is a statement rather than an omission: a
|
|
174
|
+
* bound always applies. Where no layer says anything the built-in
|
|
175
|
+
* `DEFAULT_ROW_COUNT_BOUND` does, and that is what `'default'` covers as well
|
|
176
|
+
* as the host's own `default`.
|
|
177
|
+
*/
|
|
178
|
+
rowCountFrom: 'host' | 'stored' | 'default';
|
|
179
|
+
/** The operator's row, present whether or not it won anything. */
|
|
180
|
+
stored?: StoredLoadExpectation;
|
|
181
|
+
/**
|
|
182
|
+
* Which fields this deployment declared in code, per field.
|
|
183
|
+
*
|
|
184
|
+
* True means a stored value for that field would never apply, so the editor
|
|
185
|
+
* shows it disabled and says so. Only `host.byType[type]` locks: `host.default`
|
|
186
|
+
* is the weakest layer and an operator's row beats it, so a house-wide default
|
|
187
|
+
* is not a lock and must not be drawn as one.
|
|
188
|
+
*/
|
|
189
|
+
hostLocked: {
|
|
190
|
+
deletes: boolean;
|
|
191
|
+
rowCount: boolean;
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Where the per-type expectations sit, relative to wherever the pipeline
|
|
196
|
+
* controller was mounted.
|
|
197
|
+
*
|
|
198
|
+
* A function of the base path rather than a frozen object like
|
|
199
|
+
* {@link catalogRoutes}, and the difference is the one `routes.ts` in the React
|
|
200
|
+
* package draws: the catalog controller's paths cannot move, and these move with
|
|
201
|
+
* whatever `path` the host passed to `CatalogPipelineModule.forRoot` — the
|
|
202
|
+
* routes below are `<path>/pipeline/expectations`, and `/pipeline` is only the
|
|
203
|
+
* default.
|
|
204
|
+
*
|
|
205
|
+
* Two builders for four routes: `PUT` and `DELETE` address the same path a `GET`
|
|
206
|
+
* of one type does, and a builder per verb would be three names for one string.
|
|
207
|
+
*/
|
|
208
|
+
export declare function pipelineExpectationRoutes(basePath?: string): {
|
|
209
|
+
/** Every stored row, plus the types the host has locked. `GET`, `catalog:read`. */
|
|
210
|
+
readonly expectations: () => string;
|
|
211
|
+
/**
|
|
212
|
+
* One type: `GET` for the resolved expectation and its provenance, `PUT` to
|
|
213
|
+
* set the stored row, `DELETE` to drop it. The writes need `catalog:curate`
|
|
214
|
+
* and a signed-in person.
|
|
215
|
+
*/
|
|
216
|
+
readonly expectation: (typeName: string) => string;
|
|
217
|
+
};
|
package/dist/client.js
CHANGED
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
* types are.
|
|
12
12
|
*/
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.isWorkflowStatus = exports.isWorkflowNodeKind = exports.isWorkflowExecutionMode = exports.workflowRunOrder = exports.workflowGraphHash = exports.WORKFLOW_STATUSES = exports.WORKFLOW_NODE_KINDS = exports.WORKFLOW_NODE_ID_PATTERN = exports.WORKFLOW_ISSUE_CODES = exports.WORKFLOW_EXECUTION_MODES = exports.validateWorkflow = exports.TRANSFORM_LANGUAGES = exports.isWorkflowNode = exports.isWorkflowEdge = exports.isTransformLanguage = exports.isConnectorKind = exports.CONNECTOR_KINDS = exports.catalogRoutes = exports.CATALOG_REVISION_LIMIT = void 0;
|
|
14
|
+
exports.DELETE_RECONCILIATION_STRATEGIES = exports.isWorkflowStatus = exports.isWorkflowNodeKind = exports.isWorkflowExecutionMode = exports.workflowRunOrder = exports.workflowGraphHash = exports.WORKFLOW_STATUSES = exports.WORKFLOW_NODE_KINDS = exports.WORKFLOW_NODE_ID_PATTERN = exports.WORKFLOW_ISSUE_CODES = exports.WORKFLOW_EXECUTION_MODES = exports.validateWorkflow = exports.TRANSFORM_LANGUAGES = exports.isWorkflowNode = exports.isWorkflowEdge = exports.isTransformLanguage = exports.isConnectorKind = exports.CONNECTOR_KINDS = exports.catalogRoutes = exports.CATALOG_REVISION_LIMIT = void 0;
|
|
15
|
+
exports.isDeleteReconciliationStrategy = isDeleteReconciliationStrategy;
|
|
16
|
+
exports.pipelineExpectationRoutes = pipelineExpectationRoutes;
|
|
15
17
|
// A value, not a type: a screen saying how far back the history goes should read
|
|
16
18
|
// the number rather than print one of its own. See its docblock for what the cap
|
|
17
19
|
// costs.
|
|
@@ -113,3 +115,56 @@ Object.defineProperty(exports, "workflowRunOrder", { enumerable: true, get: func
|
|
|
113
115
|
Object.defineProperty(exports, "isWorkflowExecutionMode", { enumerable: true, get: function () { return catalog_pipeline_2.isWorkflowExecutionMode; } });
|
|
114
116
|
Object.defineProperty(exports, "isWorkflowNodeKind", { enumerable: true, get: function () { return catalog_pipeline_2.isWorkflowNodeKind; } });
|
|
115
117
|
Object.defineProperty(exports, "isWorkflowStatus", { enumerable: true, get: function () { return catalog_pipeline_2.isWorkflowStatus; } });
|
|
118
|
+
/**
|
|
119
|
+
* The three answers to "how do deletions at the source reach this type", as a
|
|
120
|
+
* value.
|
|
121
|
+
*
|
|
122
|
+
* A list rather than only the union, because the editor on the Model screen has
|
|
123
|
+
* to offer them and a hand-written array in a component is the copy that drifts
|
|
124
|
+
* — the same argument {@link CONNECTOR_KINDS} makes one screen over. The server
|
|
125
|
+
* validates against this too: a `strategy` off the wire is `string` until
|
|
126
|
+
* something checks it, and the check and the dropdown reading one list is what
|
|
127
|
+
* stops the two from disagreeing about what is acceptable.
|
|
128
|
+
*
|
|
129
|
+
* **There are three and there is deliberately no fourth.** Tombstones off a
|
|
130
|
+
* change feed is the correct answer and needs machinery nothing here has; a
|
|
131
|
+
* strategy name that nothing implements is a dropdown with a lie in it. See
|
|
132
|
+
* `DeleteReconciliation` for the whole argument.
|
|
133
|
+
*/
|
|
134
|
+
exports.DELETE_RECONCILIATION_STRATEGIES = [
|
|
135
|
+
'accepted',
|
|
136
|
+
'soft-deleted-at-source',
|
|
137
|
+
'periodic-full-reload',
|
|
138
|
+
];
|
|
139
|
+
/** Whether a value off the wire names one of the three. */
|
|
140
|
+
function isDeleteReconciliationStrategy(value) {
|
|
141
|
+
return (typeof value === 'string' &&
|
|
142
|
+
exports.DELETE_RECONCILIATION_STRATEGIES.includes(value));
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Where the per-type expectations sit, relative to wherever the pipeline
|
|
146
|
+
* controller was mounted.
|
|
147
|
+
*
|
|
148
|
+
* A function of the base path rather than a frozen object like
|
|
149
|
+
* {@link catalogRoutes}, and the difference is the one `routes.ts` in the React
|
|
150
|
+
* package draws: the catalog controller's paths cannot move, and these move with
|
|
151
|
+
* whatever `path` the host passed to `CatalogPipelineModule.forRoot` — the
|
|
152
|
+
* routes below are `<path>/pipeline/expectations`, and `/pipeline` is only the
|
|
153
|
+
* default.
|
|
154
|
+
*
|
|
155
|
+
* Two builders for four routes: `PUT` and `DELETE` address the same path a `GET`
|
|
156
|
+
* of one type does, and a builder per verb would be three names for one string.
|
|
157
|
+
*/
|
|
158
|
+
function pipelineExpectationRoutes(basePath = '/pipeline') {
|
|
159
|
+
const base = basePath.endsWith('/') ? basePath.slice(0, -1) : basePath;
|
|
160
|
+
return {
|
|
161
|
+
/** Every stored row, plus the types the host has locked. `GET`, `catalog:read`. */
|
|
162
|
+
expectations: () => `${base}/expectations`,
|
|
163
|
+
/**
|
|
164
|
+
* One type: `GET` for the resolved expectation and its provenance, `PUT` to
|
|
165
|
+
* set the stored row, `DELETE` to drop it. The writes need `catalog:curate`
|
|
166
|
+
* and a signed-in person.
|
|
167
|
+
*/
|
|
168
|
+
expectation: (typeName) => `${base}/expectations/${encodeURIComponent(typeName)}`,
|
|
169
|
+
};
|
|
170
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { type CatalogOverlayStore, FileCatalogOverlayStore, InMemoryCatalogOverl
|
|
|
8
8
|
export { CATALOG_OVERLAY_STORE } from './catalog.overlay-store.token';
|
|
9
9
|
export { MikroOrmCatalogRegistry } from './catalog.registry';
|
|
10
10
|
export { CatalogRegistry } from './catalog.registry.base';
|
|
11
|
-
export { CATALOG_PIPELINE_STORE, type CatalogConnection, type CatalogConnector, type ConnectionCheck, CONNECTOR_KINDS, type CatalogPipelineStore, type CatalogStageStore, type CatalogTransform, type CatalogWorkflow, type CatalogWorkflowCapabilities, type CatalogWorkflowStore, type ConnectorKind, type ConnectorRun, isConnectorKind, isPipelineStore, isTransformLanguage, supportsTransformRevisions, isWorkflowEdge, isWorkflowExecutionMode, isWorkflowNode, isWorkflowNodeKind, isWorkflowStatus, supportsWorkflows, supportsWorkflowStages, TRANSFORM_RUNNER, TRANSFORM_LANGUAGES, type TransformLanguage, type TransformResult, type TransformRunner, validateWorkflow, WORKFLOW_EXECUTION_MODES, WORKFLOW_ISSUE_CODES, WORKFLOW_NODE_ID_PATTERN, WORKFLOW_NODE_KINDS, WORKFLOW_STATUSES, type WorkflowEdge, type WorkflowExecutionMode, type WorkflowGraph, workflowGraphHash, type WorkflowIssueCode, type WorkflowNode, type WorkflowNodeKind, type WorkflowNodeOutcome, type WorkflowNodeStepInput, type WorkflowNodeStepOutput, workflowRunOrder, type WorkflowSinkNode, type WorkflowSourceNode, type WorkflowStageRef, type WorkflowStatus, type WorkflowTransformNode, type WorkflowValidationIssue, } from './catalog.pipeline';
|
|
11
|
+
export { CATALOG_PIPELINE_STORE, type CatalogConnection, type CatalogConnector, type ConnectionCheck, CONNECTOR_KINDS, type CatalogLoadExpectations, type CatalogLoadExpectationStore, type CatalogPipelineStore, type CatalogStageStore, type CatalogTransform, type CatalogWorkflow, type CatalogWorkflowCapabilities, type CatalogWorkflowStore, type ConnectorKind, type ConnectorRun, type DeleteReconciliation, isConnectorKind, isPipelineStore, isTransformLanguage, type LoadExpectation, type RowCountBound, type StoredLoadExpectation, supportsLoadExpectations, supportsTransformRevisions, isWorkflowEdge, isWorkflowExecutionMode, isWorkflowNode, isWorkflowNodeKind, isWorkflowStatus, supportsWorkflows, supportsWorkflowStages, TRANSFORM_RUNNER, TRANSFORM_LANGUAGES, type TransformLanguage, type TransformResult, type TransformRunner, validateWorkflow, WORKFLOW_EXECUTION_MODES, WORKFLOW_ISSUE_CODES, WORKFLOW_NODE_ID_PATTERN, WORKFLOW_NODE_KINDS, WORKFLOW_STATUSES, type WorkflowEdge, type WorkflowExecutionMode, type WorkflowGraph, workflowGraphHash, type WorkflowIssueCode, type WorkflowNode, type WorkflowNodeKind, type WorkflowNodeOutcome, type WorkflowNodeStepInput, type WorkflowNodeStepOutput, workflowRunOrder, type WorkflowSinkNode, type WorkflowSourceNode, type WorkflowStageRef, type WorkflowStatus, type WorkflowTransformNode, type WorkflowValidationIssue, } from './catalog.pipeline';
|
|
12
12
|
export * from './catalog.environment';
|
|
13
13
|
export { QueryCache, toCsv } from './catalog.query-cache';
|
|
14
14
|
export { SubprocessTransformRunner, type TransformRunnerOptions, } from './transform-runner';
|
|
@@ -18,7 +18,7 @@ export type { CatalogSearchField, CatalogSearchHit, CatalogSearchKind, CatalogSe
|
|
|
18
18
|
export { type AuditQuery, CATALOG_REVISION_LIMIT, CATALOG_TRACE_OUTCOMES, CATALOG_TRACE_STORE, CATALOG_WORKSPACE_STORE, type CatalogAuditEvent, type CatalogRevision, type CatalogTrace, type CatalogTraceList, type CatalogTraceOutcome, type CatalogTraceSpan, type CatalogTraceStore, type CatalogTraceTotals, type CatalogUnlinkedList, type CatalogWorkspaceStore, type Dashboard, type DashboardCard, type EmbeddedChart, type EmbeddedChartPlacement, type EmbeddedDashboard, embeddedVisualization, isCatalogTraceOutcome, isTraceStore, isWorkspaceStore, type QueryVisualization, type SaveQueryInput, type SavedQuery, supportsSavedQueryRevisions, type TraceQuery, traceOutcomeFilter, } from './catalog.workspace';
|
|
19
19
|
export { CATALOG_PRINCIPAL_RESOLVER, type CatalogActor, type CatalogGrants, type CatalogPrincipal, type CatalogPrincipalResolver, type CatalogScope, composePrincipalId, delegatePrincipal, expandScopes, hasScope, parsePrincipalId, PRINCIPAL_ACTOR_SEPARATOR, maySeeClassification, mayRead, mayWrite, readableObjectPage, StaticKeyPrincipalResolver, } from './catalog.principal';
|
|
20
20
|
export * from './catalog.access';
|
|
21
|
-
export { assertNoColumnCollisions, CATALOG_RESERVED_COLUMNS, CATALOG_SNAPSHOT_MODES, CATALOG_STORE, type CarryForwardResult, type CatalogColumnCollision, CatalogColumnCollisionError, type CatalogMergeStore, type CatalogReadQuery, type CatalogReadResult, type CatalogReadStore, type CatalogReservedColumn, type CatalogSnapshotMode, type CatalogStoreCapabilities, type CatalogWriteStore, type ColumnCollisionOptions, findColumnCollisions, isCatalogStoreCapabilities, isReservedColumn, isWriteStore, type SnapshotRef, supportsCarryForward, } from './catalog.store';
|
|
21
|
+
export { assertNoColumnCollisions, assertSafeIdentifier, CATALOG_RESERVED_COLUMNS, CATALOG_SNAPSHOT_MODES, CATALOG_STORE, type CarryForwardResult, type CatalogColumnCollision, CatalogColumnCollisionError, type CatalogMergeStore, type CatalogReadQuery, type CatalogReadResult, type CatalogReadStore, type CatalogReservedColumn, type CatalogSnapshotMode, type CatalogStoreCapabilities, type CatalogWriteStore, type ColumnCollisionOptions, findColumnCollisions, isCatalogStoreCapabilities, isReservedColumn, isSafeIdentifier, isWriteStore, type SnapshotRef, supportsCarryForward, UnsafeIdentifierError, } from './catalog.store';
|
|
22
22
|
export { MikroOrmReadStore } from './stores/mikro-orm-read.store';
|
|
23
23
|
export type { CatalogGraph, CatalogObjectPage, CatalogObjectQuery, CatalogObjectTypeDef, CatalogOverlay, CatalogPropertyDef, CatalogRelationDef, CatalogSnapshot, RelationKind, ScalarType, } from './catalog.types';
|
|
24
24
|
export { REQUIRED_SCOPES, REQUIRES_HUMAN, RequireHuman, RequireScopes, } from './catalog.route-auth';
|
package/dist/index.js
CHANGED
|
@@ -14,8 +14,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.
|
|
18
|
-
exports.RequireScopes = exports.RequireHuman = exports.REQUIRES_HUMAN = exports.REQUIRED_SCOPES = exports.MikroOrmReadStore = exports.supportsCarryForward = exports.isWriteStore = exports.isReservedColumn = exports.isCatalogStoreCapabilities = exports.findColumnCollisions = exports.CatalogColumnCollisionError = exports.CATALOG_STORE = exports.CATALOG_SNAPSHOT_MODES = exports.CATALOG_RESERVED_COLUMNS = exports.assertNoColumnCollisions = exports.StaticKeyPrincipalResolver = exports.readableObjectPage = exports.mayWrite = exports.mayRead = exports.maySeeClassification = exports.PRINCIPAL_ACTOR_SEPARATOR = exports.parsePrincipalId = exports.hasScope = exports.expandScopes = exports.delegatePrincipal = exports.composePrincipalId = exports.CATALOG_PRINCIPAL_RESOLVER = exports.traceOutcomeFilter = exports.supportsSavedQueryRevisions = exports.isWorkspaceStore = exports.isTraceStore = exports.isCatalogTraceOutcome = exports.embeddedVisualization = exports.CATALOG_WORKSPACE_STORE = exports.CATALOG_TRACE_STORE = exports.CATALOG_TRACE_OUTCOMES = exports.CATALOG_REVISION_LIMIT = exports.visibleToPrincipal = exports.searchCatalog = exports.maySearch = exports.emptySearch = void 0;
|
|
17
|
+
exports.MAX_SEARCH_LIMIT = exports.DEFAULT_SEARCH_LIMIT = exports.CatalogService = exports.SubprocessTransformRunner = exports.toCsv = exports.QueryCache = exports.workflowRunOrder = exports.workflowGraphHash = exports.WORKFLOW_STATUSES = exports.WORKFLOW_NODE_KINDS = exports.WORKFLOW_NODE_ID_PATTERN = exports.WORKFLOW_ISSUE_CODES = exports.WORKFLOW_EXECUTION_MODES = exports.validateWorkflow = exports.TRANSFORM_LANGUAGES = exports.TRANSFORM_RUNNER = exports.supportsWorkflowStages = exports.supportsWorkflows = exports.isWorkflowStatus = exports.isWorkflowNodeKind = exports.isWorkflowNode = exports.isWorkflowExecutionMode = exports.isWorkflowEdge = exports.supportsTransformRevisions = exports.supportsLoadExpectations = exports.isTransformLanguage = exports.isPipelineStore = exports.isConnectorKind = exports.CONNECTOR_KINDS = exports.CATALOG_PIPELINE_STORE = exports.CatalogRegistry = exports.MikroOrmCatalogRegistry = exports.CATALOG_OVERLAY_STORE = exports.InMemoryCatalogOverlayStore = exports.FileCatalogOverlayStore = exports.CATALOG_OPTIONS = exports.isQueryStore = exports.assertReadOnlyShape = exports.CatalogModule = exports.emitCatalog = exports.curationActor = exports.channelNameFor = exports.catalogEventPhase = exports.UNATTRIBUTED_PRINCIPAL_ID = exports.CATALOG_LIB = exports.CATALOG_EVENTS = exports.CATALOG_EVENT_PHASE_FALLBACK = exports.CATALOG_EVENT_PHASE = exports.CatalogType = exports.CatalogProperty = void 0;
|
|
18
|
+
exports.RequireScopes = exports.RequireHuman = exports.REQUIRES_HUMAN = exports.REQUIRED_SCOPES = exports.MikroOrmReadStore = exports.UnsafeIdentifierError = exports.supportsCarryForward = exports.isWriteStore = exports.isSafeIdentifier = exports.isReservedColumn = exports.isCatalogStoreCapabilities = exports.findColumnCollisions = exports.CatalogColumnCollisionError = exports.CATALOG_STORE = exports.CATALOG_SNAPSHOT_MODES = exports.CATALOG_RESERVED_COLUMNS = exports.assertSafeIdentifier = exports.assertNoColumnCollisions = exports.StaticKeyPrincipalResolver = exports.readableObjectPage = exports.mayWrite = exports.mayRead = exports.maySeeClassification = exports.PRINCIPAL_ACTOR_SEPARATOR = exports.parsePrincipalId = exports.hasScope = exports.expandScopes = exports.delegatePrincipal = exports.composePrincipalId = exports.CATALOG_PRINCIPAL_RESOLVER = exports.traceOutcomeFilter = exports.supportsSavedQueryRevisions = exports.isWorkspaceStore = exports.isTraceStore = exports.isCatalogTraceOutcome = exports.embeddedVisualization = exports.CATALOG_WORKSPACE_STORE = exports.CATALOG_TRACE_STORE = exports.CATALOG_TRACE_OUTCOMES = exports.CATALOG_REVISION_LIMIT = exports.visibleToPrincipal = exports.searchCatalog = exports.maySearch = exports.emptySearch = exports.bestMatch = void 0;
|
|
19
19
|
var catalog_decorators_1 = require("./catalog.decorators");
|
|
20
20
|
Object.defineProperty(exports, "CatalogProperty", { enumerable: true, get: function () { return catalog_decorators_1.CatalogProperty; } });
|
|
21
21
|
Object.defineProperty(exports, "CatalogType", { enumerable: true, get: function () { return catalog_decorators_1.CatalogType; } });
|
|
@@ -59,6 +59,7 @@ Object.defineProperty(exports, "CONNECTOR_KINDS", { enumerable: true, get: funct
|
|
|
59
59
|
Object.defineProperty(exports, "isConnectorKind", { enumerable: true, get: function () { return catalog_pipeline_1.isConnectorKind; } });
|
|
60
60
|
Object.defineProperty(exports, "isPipelineStore", { enumerable: true, get: function () { return catalog_pipeline_1.isPipelineStore; } });
|
|
61
61
|
Object.defineProperty(exports, "isTransformLanguage", { enumerable: true, get: function () { return catalog_pipeline_1.isTransformLanguage; } });
|
|
62
|
+
Object.defineProperty(exports, "supportsLoadExpectations", { enumerable: true, get: function () { return catalog_pipeline_1.supportsLoadExpectations; } });
|
|
62
63
|
Object.defineProperty(exports, "supportsTransformRevisions", { enumerable: true, get: function () { return catalog_pipeline_1.supportsTransformRevisions; } });
|
|
63
64
|
Object.defineProperty(exports, "isWorkflowEdge", { enumerable: true, get: function () { return catalog_pipeline_1.isWorkflowEdge; } });
|
|
64
65
|
Object.defineProperty(exports, "isWorkflowExecutionMode", { enumerable: true, get: function () { return catalog_pipeline_1.isWorkflowExecutionMode; } });
|
|
@@ -133,6 +134,7 @@ Object.defineProperty(exports, "StaticKeyPrincipalResolver", { enumerable: true,
|
|
|
133
134
|
__exportStar(require("./catalog.access"), exports);
|
|
134
135
|
var catalog_store_1 = require("./catalog.store");
|
|
135
136
|
Object.defineProperty(exports, "assertNoColumnCollisions", { enumerable: true, get: function () { return catalog_store_1.assertNoColumnCollisions; } });
|
|
137
|
+
Object.defineProperty(exports, "assertSafeIdentifier", { enumerable: true, get: function () { return catalog_store_1.assertSafeIdentifier; } });
|
|
136
138
|
Object.defineProperty(exports, "CATALOG_RESERVED_COLUMNS", { enumerable: true, get: function () { return catalog_store_1.CATALOG_RESERVED_COLUMNS; } });
|
|
137
139
|
Object.defineProperty(exports, "CATALOG_SNAPSHOT_MODES", { enumerable: true, get: function () { return catalog_store_1.CATALOG_SNAPSHOT_MODES; } });
|
|
138
140
|
Object.defineProperty(exports, "CATALOG_STORE", { enumerable: true, get: function () { return catalog_store_1.CATALOG_STORE; } });
|
|
@@ -140,8 +142,10 @@ Object.defineProperty(exports, "CatalogColumnCollisionError", { enumerable: true
|
|
|
140
142
|
Object.defineProperty(exports, "findColumnCollisions", { enumerable: true, get: function () { return catalog_store_1.findColumnCollisions; } });
|
|
141
143
|
Object.defineProperty(exports, "isCatalogStoreCapabilities", { enumerable: true, get: function () { return catalog_store_1.isCatalogStoreCapabilities; } });
|
|
142
144
|
Object.defineProperty(exports, "isReservedColumn", { enumerable: true, get: function () { return catalog_store_1.isReservedColumn; } });
|
|
145
|
+
Object.defineProperty(exports, "isSafeIdentifier", { enumerable: true, get: function () { return catalog_store_1.isSafeIdentifier; } });
|
|
143
146
|
Object.defineProperty(exports, "isWriteStore", { enumerable: true, get: function () { return catalog_store_1.isWriteStore; } });
|
|
144
147
|
Object.defineProperty(exports, "supportsCarryForward", { enumerable: true, get: function () { return catalog_store_1.supportsCarryForward; } });
|
|
148
|
+
Object.defineProperty(exports, "UnsafeIdentifierError", { enumerable: true, get: function () { return catalog_store_1.UnsafeIdentifierError; } });
|
|
145
149
|
var mikro_orm_read_store_1 = require("./stores/mikro-orm-read.store");
|
|
146
150
|
Object.defineProperty(exports, "MikroOrmReadStore", { enumerable: true, get: function () { return mikro_orm_read_store_1.MikroOrmReadStore; } });
|
|
147
151
|
var catalog_route_auth_1 = require("./catalog.route-auth");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dudousxd/nestjs-catalog",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "A metadata registry for NestJS: object types, properties and relations, derived from your ORM and enriched with decorators.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Davide Carvalho",
|