@dudousxd/nestjs-catalog 0.5.0 → 0.6.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.
@@ -14,6 +14,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.CatalogService = void 0;
16
16
  const common_1 = require("@nestjs/common");
17
+ const catalog_events_1 = require("./catalog.events");
17
18
  const catalog_options_1 = require("./catalog.options");
18
19
  const catalog_query_1 = require("./catalog.query");
19
20
  const catalog_query_cache_1 = require("./catalog.query-cache");
@@ -79,6 +80,17 @@ let CatalogService = class CatalogService {
79
80
  visibleColumns(type) {
80
81
  return type.properties.filter((p) => !p.hidden && p.type !== 'json');
81
82
  }
83
+ /**
84
+ * Rows of one type, paged.
85
+ *
86
+ * **No principal, and so no access control.** This applies the guardrails that
87
+ * hold for every caller — the type exists, the page is bounded, the sort names
88
+ * a real column — and none that depend on who is asking: a classified column
89
+ * comes back to whoever the host's guard let through the door. That is the
90
+ * library's declare-and-enforce split, written out at length above `mayWrite`
91
+ * in `catalog.principal.ts`. A host that wants per-principal reads passes this
92
+ * page through `readableObjectPage`.
93
+ */
82
94
  async readObjects(typeName, query) {
83
95
  const type = this.registry.getType(typeName);
84
96
  if (!type)
@@ -213,23 +225,120 @@ let CatalogService = class CatalogService {
213
225
  throw new common_1.NotFoundException(`No saved query ${id}`);
214
226
  return found;
215
227
  }
216
- saveQuery(input, createdBy) {
228
+ // ---------------------------------------------------------------------------
229
+ // Sharing is audited, and the six methods below are where.
230
+ //
231
+ // `shared` on a saved query or a dashboard is the entire embed boundary: it is
232
+ // the one field that hands another company's frontend rows out of this
233
+ // catalog, and it is set by a person clicking a toggle. So it is emitted the
234
+ // way every other governance decision here is — `type.curated`,
235
+ // `transform.changed` — rather than being the one that is not.
236
+ //
237
+ // Two rules hold across all six, and both are load-bearing:
238
+ //
239
+ // *On the transition, never on the write.* A save that leaves the flag where
240
+ // it was is not a sharing decision. A trail that recorded one per keystroke
241
+ // would be a trail people learn to scroll past, which costs more than the
242
+ // entries are worth. Un-sharing is emitted too, under the same event name with
243
+ // `shared: false` — a trail that records only grants cannot answer "was this
244
+ // still shared last Tuesday".
245
+ //
246
+ // *Against what the store returned, never against what the caller asked for.*
247
+ // A store that ignores `shared` must not produce an entry claiming access was
248
+ // granted when nothing was.
249
+ //
250
+ // **Deleting is a transition.** For a while the first rule was applied only to
251
+ // the writes, so revoking access with the delete button — which is how it
252
+ // actually gets revoked — left nothing at all, and the only way to date the
253
+ // revocation was to notice that a thing had stopped appearing. Deleting
254
+ // something shared now emits `shared: false` with `deleted: true`, under the
255
+ // same event name, so the one filter anybody runs answers the whole question.
256
+ //
257
+ // Deleting something *un*shared emits nothing, and that is the first rule
258
+ // rather than an exception to it: an unshared query was not reachable from
259
+ // outside before and is not reachable after, so no access changed. Recording
260
+ // it would put entries carrying no grant and no revocation on the one channel
261
+ // whose entries all carry one. A host that wants every deletion in the trail
262
+ // wants a workspace-lifecycle event, which is a different event and not this
263
+ // one.
264
+ // ---------------------------------------------------------------------------
265
+ /**
266
+ * @param createdBy who saved it — the row's author and the audit entry's
267
+ * actor. The host's resolved principal id where the host resolves one; see
268
+ * the enforcement note in `catalog.principal.ts` for why this library cannot
269
+ * work it out itself.
270
+ */
271
+ async saveQuery(input, createdBy) {
217
272
  if (!input?.name?.trim()) {
218
273
  throw new common_1.BadRequestException('A saved query needs a name.');
219
274
  }
220
275
  (0, catalog_query_1.assertReadOnlyShape)(input.sql ?? '');
221
- return this.requireWorkspace().saveQuery(input, createdBy);
276
+ const saved = await this.requireWorkspace().saveQuery(input, createdBy);
277
+ // Born shared is a grant with nothing to transition from: an outside
278
+ // application can fetch it the moment this returns. Born unshared is not an
279
+ // event at all.
280
+ if (saved.shared) {
281
+ (0, catalog_events_1.emitCatalog)('query.shared', {
282
+ savedQueryId: saved.id,
283
+ name: saved.name,
284
+ shared: true,
285
+ principalId: createdBy,
286
+ });
287
+ }
288
+ return saved;
222
289
  }
223
- async updateSavedQuery(id, input) {
290
+ /** @param changedBy who made the change, for the audit trail. */
291
+ async updateSavedQuery(id, input, changedBy) {
224
292
  if (input.sql !== undefined)
225
293
  (0, catalog_query_1.assertReadOnlyShape)(input.sql);
294
+ // Read the old value only when the flag is in play. A transition needs both
295
+ // ends, and every other edit — a rename, a new chart type — should not pay
296
+ // for a round trip it does not need.
297
+ const before = input.shared === undefined ? undefined : await this.requireWorkspace().getSavedQuery(id);
226
298
  const updated = await this.requireWorkspace().updateSavedQuery(id, input);
227
299
  if (!updated)
228
300
  throw new common_1.NotFoundException(`No saved query ${id}`);
301
+ // `before` missing while the update succeeded means a store that disagrees
302
+ // with itself about whether this query exists. The transition is then
303
+ // unknowable, and an audit trail should over-record a grant rather than
304
+ // miss one, so it is emitted.
305
+ if (input.shared !== undefined && before?.shared !== updated.shared) {
306
+ (0, catalog_events_1.emitCatalog)('query.shared', {
307
+ savedQueryId: updated.id,
308
+ name: updated.name,
309
+ shared: updated.shared,
310
+ principalId: changedBy,
311
+ });
312
+ }
229
313
  return updated;
230
314
  }
231
- deleteSavedQuery(id) {
232
- return this.requireWorkspace().deleteSavedQuery(id);
315
+ /**
316
+ * @param deletedBy who deleted it, for the audit trail. Required rather than
317
+ * defaulted, matching `saveQuery` and `updateSavedQuery`: a default would
318
+ * quietly attribute revocations to nobody in every caller that was not
319
+ * updated, and the trail's whole value here is that it names somebody.
320
+ */
321
+ async deleteSavedQuery(id, deletedBy) {
322
+ // Read unconditionally, unlike `updateSavedQuery` which reads only when the
323
+ // flag is in play. A delete carries no statement of intent about `shared`,
324
+ // so there is nothing to branch on — whether this revokes access is a
325
+ // property of the row, and the row is about to stop existing.
326
+ const before = await this.requireWorkspace().getSavedQuery(id);
327
+ const deleted = await this.requireWorkspace().deleteSavedQuery(id);
328
+ // Only when the store says it went, and only when it was reachable from
329
+ // outside beforehand. A delete that removed nothing revoked nothing, and an
330
+ // unshared query's deletion is not an access event.
331
+ if (deleted && before?.shared) {
332
+ (0, catalog_events_1.emitCatalog)('query.shared', {
333
+ savedQueryId: before.id,
334
+ // The name as it last read. Nothing can look it up after this.
335
+ name: before.name,
336
+ shared: false,
337
+ principalId: deletedBy,
338
+ deleted: true,
339
+ });
340
+ }
341
+ return deleted;
233
342
  }
234
343
  /** Runs a saved query, honouring the TTL it was saved with. */
235
344
  async runSavedQuery(id, maxRows) {
@@ -250,20 +359,61 @@ let CatalogService = class CatalogService {
250
359
  throw new common_1.NotFoundException(`No dashboard ${id}`);
251
360
  return found;
252
361
  }
253
- saveDashboard(input, createdBy) {
362
+ /**
363
+ * `shared` is declared here, and that is not cosmetic.
364
+ *
365
+ * The store has always accepted it, so it worked as long as the body reached
366
+ * the store untouched. A host with a whitelisting `ValidationPipe` — the
367
+ * normal, recommended configuration — strips a property no type declares, and
368
+ * the symptom is a dashboard that cannot be shared with no error anywhere:
369
+ * the toggle saves, the response says `shared: false`, and the embed API
370
+ * keeps answering 403 for a board somebody just shared.
371
+ */
372
+ async saveDashboard(input, createdBy) {
254
373
  if (!input?.name?.trim()) {
255
374
  throw new common_1.BadRequestException('A dashboard needs a name.');
256
375
  }
257
- return this.requireWorkspace().saveDashboard(input, createdBy);
376
+ const saved = await this.requireWorkspace().saveDashboard(input, createdBy);
377
+ if (saved.shared) {
378
+ (0, catalog_events_1.emitCatalog)('dashboard.shared', {
379
+ dashboardId: saved.id,
380
+ name: saved.name,
381
+ shared: true,
382
+ principalId: createdBy,
383
+ });
384
+ }
385
+ return saved;
258
386
  }
259
- async updateDashboard(id, input) {
387
+ /** @param changedBy who made the change, for the audit trail. */
388
+ async updateDashboard(id, input, changedBy) {
389
+ const before = input.shared === undefined ? undefined : await this.requireWorkspace().getDashboard(id);
260
390
  const updated = await this.requireWorkspace().updateDashboard(id, input);
261
391
  if (!updated)
262
392
  throw new common_1.NotFoundException(`No dashboard ${id}`);
393
+ if (input.shared !== undefined && before?.shared !== updated.shared) {
394
+ (0, catalog_events_1.emitCatalog)('dashboard.shared', {
395
+ dashboardId: updated.id,
396
+ name: updated.name,
397
+ shared: updated.shared,
398
+ principalId: changedBy,
399
+ });
400
+ }
263
401
  return updated;
264
402
  }
265
- deleteDashboard(id) {
266
- return this.requireWorkspace().deleteDashboard(id);
403
+ /** @param deletedBy who deleted it. See {@link deleteSavedQuery}. */
404
+ async deleteDashboard(id, deletedBy) {
405
+ const before = await this.requireWorkspace().getDashboard(id);
406
+ const deleted = await this.requireWorkspace().deleteDashboard(id);
407
+ if (deleted && before?.shared) {
408
+ (0, catalog_events_1.emitCatalog)('dashboard.shared', {
409
+ dashboardId: before.id,
410
+ name: before.name,
411
+ shared: false,
412
+ principalId: deletedBy,
413
+ deleted: true,
414
+ });
415
+ }
416
+ return deleted;
267
417
  }
268
418
  // ---------------------------------------------------------------------------
269
419
  // Embed: what another application's frontend gets.
@@ -298,8 +448,16 @@ let CatalogService = class CatalogService {
298
448
  })),
299
449
  };
300
450
  }
301
- /** One chart, rendered. */
302
- async embedChart(savedQueryId, layout) {
451
+ /**
452
+ * One chart, rendered.
453
+ *
454
+ * `placement` is what the dashboard card said, and it is honoured rather than
455
+ * merely carried: a card's `title` and `library` exist to override the saved
456
+ * query on THIS board, so an embed that ignored them would show a different
457
+ * heading and a different chart from the console for the same dashboard —
458
+ * silently, with nothing thrown and nothing logged.
459
+ */
460
+ async embedChart(savedQueryId, placement) {
303
461
  const saved = await this.getSavedQuery(savedQueryId);
304
462
  if (!saved.shared) {
305
463
  throw new common_1.ForbiddenException(`"${saved.name}" has not been shared. Mark it shared in the console to make it embeddable.`);
@@ -308,12 +466,15 @@ let CatalogService = class CatalogService {
308
466
  sql: saved.sql,
309
467
  cacheTtlSeconds: saved.cacheTtlSeconds,
310
468
  });
469
+ // A card whose title was cleared falls back to the query's name rather than
470
+ // embedding a blank heading — an empty override is the absence of one.
471
+ const overridden = placement?.title?.trim();
311
472
  return {
312
473
  id: saved.id,
313
- title: saved.name,
474
+ title: overridden ? overridden : saved.name,
314
475
  description: saved.description,
315
- visualization: saved.visualization,
316
- layout,
476
+ visualization: (0, catalog_workspace_1.embeddedVisualization)(saved.visualization, placement?.library),
477
+ layout: placement ? { width: placement.width, position: placement.position } : undefined,
317
478
  columns: result.columns,
318
479
  rows: result.rows,
319
480
  rowCount: result.rowCount,
@@ -336,6 +497,10 @@ let CatalogService = class CatalogService {
336
497
  charts.push(await this.embedChart(card.savedQueryId, {
337
498
  width: card.width,
338
499
  position: card.position,
500
+ // Everything the card says about this chart, not only where it
501
+ // sits. See `EmbeddedChartPlacement`.
502
+ ...(card.title !== undefined ? { title: card.title } : {}),
503
+ ...(card.library !== undefined ? { library: card.library } : {}),
339
504
  }));
340
505
  }
341
506
  catch {
@@ -166,7 +166,13 @@ export interface CatalogObjectPage {
166
166
  size: number;
167
167
  total: number;
168
168
  pages: number;
169
- /** Only the visible, non-redacted columns, in overlay order. */
169
+ /**
170
+ * The visible, non-blob columns, in overlay order.
171
+ *
172
+ * Visible means "not hidden by the overlay". It does **not** mean redacted for
173
+ * a caller: a classified column is here, with its `classification` on it, and
174
+ * dropping it is the host's move — see `readableObjectPage`.
175
+ */
170
176
  columns: Array<{
171
177
  name: string;
172
178
  displayName: string;
@@ -34,8 +34,16 @@ export interface SavedQuery {
34
34
  * relations, so working out "which types does this touch" means parsing the
35
35
  * statement — and a permission derived from a parser is a permission that
36
36
  * silently widens the day the parser meets a query it did not expect. Marking
37
- * it shared is a decision a person made, and it shows up in the audit trail
38
- * as one.
37
+ * it shared is a decision a person made, and it shows up in the audit trail as
38
+ * one: `CatalogService` emits `query.shared` on the transition, in both
39
+ * directions, naming whoever made it. Deleting a shared query is one of those
40
+ * directions — it revokes outside access as surely as the toggle does — and is
41
+ * emitted the same way, with `deleted: true` to say which ending it was.
42
+ *
43
+ * That last sentence was a claim before it was true — the event did not exist
44
+ * and the one act that hands an outside application data left no trace at all.
45
+ * Anything written here about what is recorded should be checkable against
46
+ * `CATALOG_EVENTS` and an emit site.
39
47
  */
40
48
  shared: boolean;
41
49
  }
@@ -71,7 +79,11 @@ export interface Dashboard {
71
79
  createdAt: string;
72
80
  updatedAt: string;
73
81
  cards: DashboardCard[];
74
- /** Fetchable through the embed API by an application with `catalog:embed`. */
82
+ /**
83
+ * Fetchable through the embed API by an application with `catalog:embed`.
84
+ *
85
+ * Audited the same way {@link SavedQuery.shared} is, as `dashboard.shared`.
86
+ */
75
87
  shared: boolean;
76
88
  }
77
89
  export interface DashboardCard {
@@ -225,11 +237,17 @@ export interface CatalogTrace {
225
237
  /**
226
238
  * True when the whole story fits inside one tick of the recorder's clock.
227
239
  *
228
- * Worth saying out loud rather than quietly drawing zero-width bars: with a
229
- * second-resolution timestamp column a fast load has no measurable internal
230
- * timing at all, and a waterfall drawn from it would be a picture of rounding
231
- * error. Ordering is still correct — see the lifecycle rank the store sorts
232
- * by — but proportions are not, and a consumer should say so.
240
+ * Worth saying out loud rather than quietly drawing zero-width bars: when a
241
+ * load finishes inside one tick it has no measurable internal timing at all,
242
+ * and a waterfall drawn from it would be a picture of rounding error.
243
+ * Ordering is still correct — see the lifecycle rank the store sorts by — but
244
+ * proportions are not, and a consumer should say so.
245
+ *
246
+ * How coarse a tick is belongs to the store, not to this field: read
247
+ * `clockResolutionMs` rather than assuming. The bundled MySQL store keeps
248
+ * milliseconds, so this is now true only of loads that really did finish
249
+ * inside one — and of rows written before that column was widened, which
250
+ * collapse onto a whole second and are honestly still coarse.
233
251
  */
234
252
  coarse: boolean;
235
253
  /** Ordered: what started it first, how it ended last. */
@@ -414,11 +432,53 @@ export interface EmbeddedDashboard {
414
432
  charts: EmbeddedChart[];
415
433
  generatedAt: string;
416
434
  }
435
+ /**
436
+ * What the *card* says about a chart, as opposed to what the saved query says.
437
+ *
438
+ * A card carries two kinds of statement and they are easy to conflate. Width
439
+ * and position are a hint about the grid, which a consumer may ignore. `title`
440
+ * and `library` are overrides — the board's answer to a question the query has
441
+ * already answered — and dropping them is not a hint being ignored, it is the
442
+ * embed disagreeing with the console about the same dashboard.
443
+ */
444
+ export interface EmbeddedChartPlacement {
445
+ width: number;
446
+ position: number;
447
+ /** The card's title override. Blank or absent falls back to the query's name. */
448
+ title?: string;
449
+ /** The card's library override. Absent falls back to the query's own. */
450
+ library?: string;
451
+ }
452
+ /**
453
+ * Which library draws an embedded chart, given the two places that can say.
454
+ *
455
+ * The server twin of `visualizationFor` in the React package, and it must stay
456
+ * the same rule: the card wins, then the query, then the built-in renderer. Two
457
+ * different precedences for one field would mean the console and an embedding
458
+ * application draw the same board differently, which is exactly the bug the
459
+ * override exists to prevent.
460
+ *
461
+ * Restated here rather than imported, because a server package must not depend
462
+ * on a React one. Kept as a named function rather than two lines inside
463
+ * `embedChart` for the same reason the React side did: a precedence a test can
464
+ * hold by name cannot drift silently.
465
+ *
466
+ * When neither chose, the key is ABSENT rather than explicitly undefined — this
467
+ * shape is serialised to a consumer, and "the key is there and empty" is a
468
+ * different statement from "nobody chose".
469
+ */
470
+ export declare function embeddedVisualization(saved: QueryVisualization | undefined, cardLibrary: string | undefined): QueryVisualization;
417
471
  export interface CatalogWorkspaceStore {
418
472
  listSavedQueries(): Promise<SavedQuery[]>;
419
473
  getSavedQuery(id: string): Promise<SavedQuery | undefined>;
420
474
  saveQuery(input: SaveQueryInput, createdBy: string): Promise<SavedQuery>;
421
475
  updateSavedQuery(id: string, input: Partial<SaveQueryInput>): Promise<SavedQuery | undefined>;
476
+ /**
477
+ * Unchanged by the audit work above it: the *store* takes no actor, because a
478
+ * store that emitted would emit on every path into it and could not tell a
479
+ * revocation from a cascade. `CatalogService.deleteSavedQuery` reads the row
480
+ * first and decides.
481
+ */
422
482
  deleteSavedQuery(id: string): Promise<boolean>;
423
483
  listDashboards(): Promise<Dashboard[]>;
424
484
  getDashboard(id: string): Promise<Dashboard | undefined>;
@@ -13,6 +13,7 @@ exports.CATALOG_WORKSPACE_STORE = exports.CATALOG_TRACE_STORE = exports.CATALOG_
13
13
  exports.isCatalogTraceOutcome = isCatalogTraceOutcome;
14
14
  exports.traceOutcomeFilter = traceOutcomeFilter;
15
15
  exports.isTraceStore = isTraceStore;
16
+ exports.embeddedVisualization = embeddedVisualization;
16
17
  exports.isWorkspaceStore = isWorkspaceStore;
17
18
  /**
18
19
  * The same events, told as stories instead of as a list.
@@ -79,6 +80,28 @@ function isTraceStore(store) {
79
80
  store !== null &&
80
81
  typeof Reflect.get(store, 'listTraces') === 'function');
81
82
  }
83
+ /**
84
+ * Which library draws an embedded chart, given the two places that can say.
85
+ *
86
+ * The server twin of `visualizationFor` in the React package, and it must stay
87
+ * the same rule: the card wins, then the query, then the built-in renderer. Two
88
+ * different precedences for one field would mean the console and an embedding
89
+ * application draw the same board differently, which is exactly the bug the
90
+ * override exists to prevent.
91
+ *
92
+ * Restated here rather than imported, because a server package must not depend
93
+ * on a React one. Kept as a named function rather than two lines inside
94
+ * `embedChart` for the same reason the React side did: a precedence a test can
95
+ * hold by name cannot drift silently.
96
+ *
97
+ * When neither chose, the key is ABSENT rather than explicitly undefined — this
98
+ * shape is serialised to a consumer, and "the key is there and empty" is a
99
+ * different statement from "nobody chose".
100
+ */
101
+ function embeddedVisualization(saved, cardLibrary) {
102
+ const base = saved ?? { kind: 'table' };
103
+ return cardLibrary ? { ...base, library: cardLibrary } : base;
104
+ }
82
105
  function isWorkspaceStore(store) {
83
106
  return (typeof store === 'object' &&
84
107
  store !== null &&
package/dist/index.d.ts CHANGED
@@ -12,8 +12,8 @@ export * from './catalog.environment';
12
12
  export { QueryCache, toCsv } from './catalog.query-cache';
13
13
  export { SubprocessTransformRunner, type TransformRunnerOptions, } from './transform-runner';
14
14
  export { CatalogService } from './catalog.service';
15
- export { type AuditQuery, CATALOG_TRACE_OUTCOMES, CATALOG_TRACE_STORE, CATALOG_WORKSPACE_STORE, type CatalogAuditEvent, type CatalogTrace, type CatalogTraceList, type CatalogTraceOutcome, type CatalogTraceSpan, type CatalogTraceStore, type CatalogTraceTotals, type CatalogUnlinkedList, type CatalogWorkspaceStore, type Dashboard, type DashboardCard, isCatalogTraceOutcome, isTraceStore, isWorkspaceStore, type QueryVisualization, type SaveQueryInput, type SavedQuery, type TraceQuery, traceOutcomeFilter, } from './catalog.workspace';
16
- 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, StaticKeyPrincipalResolver, } from './catalog.principal';
15
+ export { type AuditQuery, CATALOG_TRACE_OUTCOMES, CATALOG_TRACE_STORE, CATALOG_WORKSPACE_STORE, type CatalogAuditEvent, 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, type TraceQuery, traceOutcomeFilter, } from './catalog.workspace';
16
+ 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';
17
17
  export * from './catalog.access';
18
18
  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';
19
19
  export { MikroOrmReadStore } from './stores/mikro-orm-read.store';
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.CATALOG_PRINCIPAL_RESOLVER = exports.traceOutcomeFilter = exports.isWorkspaceStore = exports.isTraceStore = exports.isCatalogTraceOutcome = exports.CATALOG_WORKSPACE_STORE = exports.CATALOG_TRACE_STORE = exports.CATALOG_TRACE_OUTCOMES = exports.CatalogService = exports.SubprocessTransformRunner = exports.toCsv = exports.QueryCache = exports.workflowRunOrder = exports.workflowGraphHash = 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.isWorkflowNodeKind = exports.isWorkflowNode = exports.isWorkflowExecutionMode = exports.isWorkflowEdge = 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.channelNameFor = exports.catalogEventPhase = 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.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.mayWrite = exports.mayRead = exports.maySeeClassification = exports.PRINCIPAL_ACTOR_SEPARATOR = exports.parsePrincipalId = exports.hasScope = exports.expandScopes = exports.delegatePrincipal = exports.composePrincipalId = void 0;
17
+ exports.traceOutcomeFilter = exports.isWorkspaceStore = exports.isTraceStore = exports.isCatalogTraceOutcome = exports.embeddedVisualization = exports.CATALOG_WORKSPACE_STORE = exports.CATALOG_TRACE_STORE = exports.CATALOG_TRACE_OUTCOMES = exports.CatalogService = exports.SubprocessTransformRunner = exports.toCsv = exports.QueryCache = exports.workflowRunOrder = exports.workflowGraphHash = 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.isWorkflowNodeKind = exports.isWorkflowNode = exports.isWorkflowExecutionMode = exports.isWorkflowEdge = 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.channelNameFor = exports.catalogEventPhase = 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.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 = 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; } });
@@ -78,6 +78,7 @@ var catalog_workspace_1 = require("./catalog.workspace");
78
78
  Object.defineProperty(exports, "CATALOG_TRACE_OUTCOMES", { enumerable: true, get: function () { return catalog_workspace_1.CATALOG_TRACE_OUTCOMES; } });
79
79
  Object.defineProperty(exports, "CATALOG_TRACE_STORE", { enumerable: true, get: function () { return catalog_workspace_1.CATALOG_TRACE_STORE; } });
80
80
  Object.defineProperty(exports, "CATALOG_WORKSPACE_STORE", { enumerable: true, get: function () { return catalog_workspace_1.CATALOG_WORKSPACE_STORE; } });
81
+ Object.defineProperty(exports, "embeddedVisualization", { enumerable: true, get: function () { return catalog_workspace_1.embeddedVisualization; } });
81
82
  Object.defineProperty(exports, "isCatalogTraceOutcome", { enumerable: true, get: function () { return catalog_workspace_1.isCatalogTraceOutcome; } });
82
83
  Object.defineProperty(exports, "isTraceStore", { enumerable: true, get: function () { return catalog_workspace_1.isTraceStore; } });
83
84
  Object.defineProperty(exports, "isWorkspaceStore", { enumerable: true, get: function () { return catalog_workspace_1.isWorkspaceStore; } });
@@ -93,6 +94,7 @@ Object.defineProperty(exports, "PRINCIPAL_ACTOR_SEPARATOR", { enumerable: true,
93
94
  Object.defineProperty(exports, "maySeeClassification", { enumerable: true, get: function () { return catalog_principal_1.maySeeClassification; } });
94
95
  Object.defineProperty(exports, "mayRead", { enumerable: true, get: function () { return catalog_principal_1.mayRead; } });
95
96
  Object.defineProperty(exports, "mayWrite", { enumerable: true, get: function () { return catalog_principal_1.mayWrite; } });
97
+ Object.defineProperty(exports, "readableObjectPage", { enumerable: true, get: function () { return catalog_principal_1.readableObjectPage; } });
96
98
  Object.defineProperty(exports, "StaticKeyPrincipalResolver", { enumerable: true, get: function () { return catalog_principal_1.StaticKeyPrincipalResolver; } });
97
99
  // Everything, deliberately. The last release exported the directory interface
98
100
  // but not the two types its one method takes and returns, so the seam could be
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dudousxd/nestjs-catalog",
3
- "version": "0.5.0",
3
+ "version": "0.6.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",