clivly 0.10.6 → 0.10.7

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.
@@ -6,6 +6,7 @@ require("./deprecate-subpath-B9ngvizt.cjs").warnDeprecatedSubpath("clivly/core/e
6
6
  exports.TARGET_CONCEPTS = require_internal_entity_heuristics.TARGET_CONCEPTS;
7
7
  exports.hasDefiningColumn = require_internal_entity_heuristics.hasDefiningColumn;
8
8
  exports.hasSensitiveColumns = require_internal_entity_heuristics.hasSensitiveColumns;
9
+ exports.isFrameworkTable = require_internal_entity_heuristics.isFrameworkTable;
9
10
  exports.matchesConcept = require_internal_entity_heuristics.matchesConcept;
10
11
  exports.requiredFieldsFor = require_internal_entity_heuristics.requiredFieldsFor;
11
12
  exports.scoreConcepts = require_internal_entity_heuristics.scoreConcepts;
@@ -1,3 +1,3 @@
1
1
  import { p as DiscoveredColumnMeta } from "./entity-config-w8oMBWf8.cjs";
2
- import { FieldSuggestion, RelationshipSuggestion, ScoredTable, SuggestedVia, TARGET_CONCEPTS, TargetConcept, hasDefiningColumn, hasSensitiveColumns, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping } from "./internal-entity-heuristics.cjs";
3
- export { type DiscoveredColumnMeta, FieldSuggestion, RelationshipSuggestion, ScoredTable, SuggestedVia, TARGET_CONCEPTS, TargetConcept, hasDefiningColumn, hasSensitiveColumns, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping };
2
+ import { FieldSuggestion, RelationshipSuggestion, ScoredTable, SuggestedVia, TARGET_CONCEPTS, TargetConcept, hasDefiningColumn, hasSensitiveColumns, isFrameworkTable, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping } from "./internal-entity-heuristics.cjs";
3
+ export { type DiscoveredColumnMeta, FieldSuggestion, RelationshipSuggestion, ScoredTable, SuggestedVia, TARGET_CONCEPTS, TargetConcept, hasDefiningColumn, hasSensitiveColumns, isFrameworkTable, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping };
@@ -1,3 +1,3 @@
1
1
  import { p as DiscoveredColumnMeta } from "./entity-config-w8oMBWf8.mjs";
2
- import { FieldSuggestion, RelationshipSuggestion, ScoredTable, SuggestedVia, TARGET_CONCEPTS, TargetConcept, hasDefiningColumn, hasSensitiveColumns, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping } from "./internal-entity-heuristics.mjs";
3
- export { type DiscoveredColumnMeta, FieldSuggestion, RelationshipSuggestion, ScoredTable, SuggestedVia, TARGET_CONCEPTS, TargetConcept, hasDefiningColumn, hasSensitiveColumns, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping };
2
+ import { FieldSuggestion, RelationshipSuggestion, ScoredTable, SuggestedVia, TARGET_CONCEPTS, TargetConcept, hasDefiningColumn, hasSensitiveColumns, isFrameworkTable, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping } from "./internal-entity-heuristics.mjs";
3
+ export { type DiscoveredColumnMeta, FieldSuggestion, RelationshipSuggestion, ScoredTable, SuggestedVia, TARGET_CONCEPTS, TargetConcept, hasDefiningColumn, hasSensitiveColumns, isFrameworkTable, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping };
@@ -1,6 +1,6 @@
1
- import { TARGET_CONCEPTS, hasDefiningColumn, hasSensitiveColumns, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping } from "./internal-entity-heuristics.mjs";
1
+ import { TARGET_CONCEPTS, hasDefiningColumn, hasSensitiveColumns, isFrameworkTable, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping } from "./internal-entity-heuristics.mjs";
2
2
  import { t as warnDeprecatedSubpath } from "./deprecate-subpath-CmvZtCpE.mjs";
3
3
  //#region src/core-entity-heuristics.ts
4
4
  warnDeprecatedSubpath("clivly/core/entity-heuristics", "clivly/internal/entity-heuristics");
5
5
  //#endregion
6
- export { TARGET_CONCEPTS, hasDefiningColumn, hasSensitiveColumns, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping };
6
+ export { TARGET_CONCEPTS, hasDefiningColumn, hasSensitiveColumns, isFrameworkTable, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping };
package/index.cjs CHANGED
@@ -1657,13 +1657,14 @@ function writeCredentials(options, credentials) {
1657
1657
  const entries = credentialEntries(credentials);
1658
1658
  const result = upsertEnvValues(deps.readEnv(options.cwd), entries, { force: options.force });
1659
1659
  deps.writeEnv(options.cwd, result.contents);
1660
+ const envFile = deps.envFileName?.(options.cwd) ?? ".env";
1660
1661
  deps.out("\nLogin successful.\n");
1661
1662
  const valuesByKey = {
1662
1663
  [SECRET_KEY_ENV]: credentials.apiKey,
1663
1664
  CLIVLY_SYNC_TRIGGER_SECRET: credentials.triggerSecret
1664
1665
  };
1665
1666
  for (const entry of entries) if (result.skipped.includes(entry.key)) deps.out(` • ${entry.key} already set — skipped (pass --force to overwrite)`);
1666
- else deps.out(` ✓ ${entry.key}=${maskSecret(valuesByKey[entry.key] ?? "")} written to .env`);
1667
+ else deps.out(` ✓ ${entry.key}=${maskSecret(valuesByKey[entry.key] ?? "")} written to ${envFile}`);
1667
1668
  }
1668
1669
  async function runLogin(options) {
1669
1670
  const { deps } = options;
@@ -1706,7 +1707,10 @@ function rankCandidates$1(tables, concept) {
1706
1707
  m: require_internal_entity_heuristics.matchesConcept(t.tableName, concept)
1707
1708
  })).filter((c) => Boolean(c.m)).sort((a, b) => {
1708
1709
  const usable = Number(require_internal_entity_heuristics.hasDefiningColumn(concept, columnNames(b.t))) - Number(require_internal_entity_heuristics.hasDefiningColumn(concept, columnNames(a.t)));
1709
- return usable === 0 ? Number(b.m.exact) - Number(a.m.exact) : usable;
1710
+ if (usable !== 0) return usable;
1711
+ const exact = Number(b.m.exact) - Number(a.m.exact);
1712
+ if (exact !== 0) return exact;
1713
+ return Number(require_internal_entity_heuristics.isFrameworkTable(a.t.tableName)) - Number(require_internal_entity_heuristics.isFrameworkTable(b.t.tableName));
1710
1714
  }).map((c) => c.t);
1711
1715
  }
1712
1716
  function selectEntities(tables) {
@@ -1949,7 +1953,14 @@ export async function register() {
1949
1953
  return;
1950
1954
  }
1951
1955
  try {
1952
- const { default: clivly } = await import("${importPath}");
1956
+ // Built at runtime so the bundler cannot statically trace it. Next
1957
+ // compiles this file for BOTH runtimes, and the guard above only runs on
1958
+ // the edge — it does not stop the edge BUILD from following a literal
1959
+ // import into your config, and from there into your database driver. A
1960
+ // node-postgres app fails that pass on \`require('path')\` and every route
1961
+ // 500s before Clivly is ever reached.
1962
+ const specifier = "${importPath}";
1963
+ const { default: clivly } = await import(/* webpackIgnore: true */ specifier);
1953
1964
  await clivly.start();
1954
1965
  } catch (error) {
1955
1966
  console.warn("[clivly] could not check in:", error);
@@ -2757,7 +2768,14 @@ function reportSchema(report, out) {
2757
2768
  const updated = report.mappings.filter((m) => m.updated);
2758
2769
  if (created.length > 0) out(` ✅ Mapped ${countOf(created.length, "entity", "entities")}: ${created.map((m) => m.entityKey).join(", ")}.\n`);
2759
2770
  if (updated.length > 0) out(` ✅ Updated ${countOf(updated.length, "mapping")}: ${updated.map((m) => m.entityKey).join(", ")}.\n`);
2760
- if (report.mappings.length > 0 && created.length === 0 && updated.length === 0) out(` ✅ ${countOf(report.mappings.length, "mapping")} already match your config.\n`);
2771
+ const skipped = report.mappings.filter((m) => m.skipped === "dashboard-owned");
2772
+ if (skipped.length > 0) {
2773
+ out(` ↩︎ Kept the dashboard's version of ${countOf(skipped.length, "entity", "entities")}: ${skipped.map((m) => m.entityKey).join(", ")}.\n`);
2774
+ out(" The dashboard owns these mappings, so clivly.config did not change them.\n");
2775
+ out(" To let your config own one, delete it in Integrations → Mapping, then push again.\n");
2776
+ }
2777
+ const settled = report.mappings.length - skipped.length;
2778
+ if (settled > 0 && created.length === 0 && updated.length === 0) out(` ✅ ${countOf(settled, "mapping")} already match your config.\n`);
2761
2779
  }
2762
2780
  async function runPushSchema(options) {
2763
2781
  const out = options.out ?? ((line) => process.stdout.write(line));
@@ -4333,7 +4351,8 @@ function defaultLoginDeps() {
4333
4351
  sleep: (ms) => new Promise((resolve) => {
4334
4352
  setTimeout(resolve, ms);
4335
4353
  }),
4336
- writeEnv: defaultWriteEnv
4354
+ writeEnv: defaultWriteEnv,
4355
+ envFileName: (cwd) => (0, node_path.basename)(resolveEnvPath(cwd))
4337
4356
  };
4338
4357
  }
4339
4358
  function runInitFromArgv(argv, cwd) {
package/index.mjs CHANGED
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as CANONICAL_FIELDS } from "./entity-config-bC3DX9f1.mjs";
3
3
  import "./mapping-score-C68uAqGB.mjs";
4
- import { hasDefiningColumn, matchesConcept, requiredFieldsFor, scoreFieldMap, scoreRelationships, suggestCursorField, toFieldMap } from "./internal-entity-heuristics.mjs";
4
+ import { hasDefiningColumn, isFrameworkTable, matchesConcept, requiredFieldsFor, scoreFieldMap, scoreRelationships, suggestCursorField, toFieldMap } from "./internal-entity-heuristics.mjs";
5
5
  import { s as isPlaceholderUrl, t as createClivlySDK } from "./sdk-BTzaM8bF.mjs";
6
6
  import { createRequire } from "node:module";
7
7
  import { spawn } from "node:child_process";
8
8
  import { accessSync, constants, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, statSync, watch, writeFileSync } from "node:fs";
9
9
  import { homedir, hostname } from "node:os";
10
- import { delimiter, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
10
+ import { basename, delimiter, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
11
11
  import { createInterface } from "node:readline/promises";
12
12
  import { createJiti } from "jiti";
13
13
  import { fileURLToPath, pathToFileURL } from "node:url";
@@ -1656,13 +1656,14 @@ function writeCredentials(options, credentials) {
1656
1656
  const entries = credentialEntries(credentials);
1657
1657
  const result = upsertEnvValues(deps.readEnv(options.cwd), entries, { force: options.force });
1658
1658
  deps.writeEnv(options.cwd, result.contents);
1659
+ const envFile = deps.envFileName?.(options.cwd) ?? ".env";
1659
1660
  deps.out("\nLogin successful.\n");
1660
1661
  const valuesByKey = {
1661
1662
  [SECRET_KEY_ENV]: credentials.apiKey,
1662
1663
  CLIVLY_SYNC_TRIGGER_SECRET: credentials.triggerSecret
1663
1664
  };
1664
1665
  for (const entry of entries) if (result.skipped.includes(entry.key)) deps.out(` • ${entry.key} already set — skipped (pass --force to overwrite)`);
1665
- else deps.out(` ✓ ${entry.key}=${maskSecret(valuesByKey[entry.key] ?? "")} written to .env`);
1666
+ else deps.out(` ✓ ${entry.key}=${maskSecret(valuesByKey[entry.key] ?? "")} written to ${envFile}`);
1666
1667
  }
1667
1668
  async function runLogin(options) {
1668
1669
  const { deps } = options;
@@ -1705,7 +1706,10 @@ function rankCandidates$1(tables, concept) {
1705
1706
  m: matchesConcept(t.tableName, concept)
1706
1707
  })).filter((c) => Boolean(c.m)).sort((a, b) => {
1707
1708
  const usable = Number(hasDefiningColumn(concept, columnNames(b.t))) - Number(hasDefiningColumn(concept, columnNames(a.t)));
1708
- return usable === 0 ? Number(b.m.exact) - Number(a.m.exact) : usable;
1709
+ if (usable !== 0) return usable;
1710
+ const exact = Number(b.m.exact) - Number(a.m.exact);
1711
+ if (exact !== 0) return exact;
1712
+ return Number(isFrameworkTable(a.t.tableName)) - Number(isFrameworkTable(b.t.tableName));
1709
1713
  }).map((c) => c.t);
1710
1714
  }
1711
1715
  function selectEntities(tables) {
@@ -1948,7 +1952,14 @@ export async function register() {
1948
1952
  return;
1949
1953
  }
1950
1954
  try {
1951
- const { default: clivly } = await import("${importPath}");
1955
+ // Built at runtime so the bundler cannot statically trace it. Next
1956
+ // compiles this file for BOTH runtimes, and the guard above only runs on
1957
+ // the edge — it does not stop the edge BUILD from following a literal
1958
+ // import into your config, and from there into your database driver. A
1959
+ // node-postgres app fails that pass on \`require('path')\` and every route
1960
+ // 500s before Clivly is ever reached.
1961
+ const specifier = "${importPath}";
1962
+ const { default: clivly } = await import(/* webpackIgnore: true */ specifier);
1952
1963
  await clivly.start();
1953
1964
  } catch (error) {
1954
1965
  console.warn("[clivly] could not check in:", error);
@@ -2756,7 +2767,14 @@ function reportSchema(report, out) {
2756
2767
  const updated = report.mappings.filter((m) => m.updated);
2757
2768
  if (created.length > 0) out(` ✅ Mapped ${countOf(created.length, "entity", "entities")}: ${created.map((m) => m.entityKey).join(", ")}.\n`);
2758
2769
  if (updated.length > 0) out(` ✅ Updated ${countOf(updated.length, "mapping")}: ${updated.map((m) => m.entityKey).join(", ")}.\n`);
2759
- if (report.mappings.length > 0 && created.length === 0 && updated.length === 0) out(` ✅ ${countOf(report.mappings.length, "mapping")} already match your config.\n`);
2770
+ const skipped = report.mappings.filter((m) => m.skipped === "dashboard-owned");
2771
+ if (skipped.length > 0) {
2772
+ out(` ↩︎ Kept the dashboard's version of ${countOf(skipped.length, "entity", "entities")}: ${skipped.map((m) => m.entityKey).join(", ")}.\n`);
2773
+ out(" The dashboard owns these mappings, so clivly.config did not change them.\n");
2774
+ out(" To let your config own one, delete it in Integrations → Mapping, then push again.\n");
2775
+ }
2776
+ const settled = report.mappings.length - skipped.length;
2777
+ if (settled > 0 && created.length === 0 && updated.length === 0) out(` ✅ ${countOf(settled, "mapping")} already match your config.\n`);
2760
2778
  }
2761
2779
  async function runPushSchema(options) {
2762
2780
  const out = options.out ?? ((line) => process.stdout.write(line));
@@ -4332,7 +4350,8 @@ function defaultLoginDeps() {
4332
4350
  sleep: (ms) => new Promise((resolve) => {
4333
4351
  setTimeout(resolve, ms);
4334
4352
  }),
4335
- writeEnv: defaultWriteEnv
4353
+ writeEnv: defaultWriteEnv,
4354
+ envFileName: (cwd) => basename(resolveEnvPath(cwd))
4336
4355
  };
4337
4356
  }
4338
4357
  function runInitFromArgv(argv, cwd) {
@@ -283,6 +283,54 @@ const SENSITIVE_COLUMNS = /* @__PURE__ */ new Set([
283
283
  function hasSensitiveColumns(columns) {
284
284
  return columns.some((column) => SENSITIVE_COLUMNS.has(column.toLowerCase().replaceAll("-", "_")));
285
285
  }
286
+ /**
287
+ * Table names the supported auth libraries create.
288
+ *
289
+ * `hasSensitiveColumns` cannot catch these. Better Auth's `organization` table
290
+ * is `{id, name, slug, logo}` — no credential column anywhere, a real `name`,
291
+ * and "organizations" is in the company vocabulary above. It is, by every
292
+ * signal this module has, an excellent company candidate. On `vue-academy`
293
+ * `clivly init` duly chose it over `campuses`, the actual business table that
294
+ * every student row points at, and the first sync exported rows nothing could
295
+ * receive.
296
+ *
297
+ * Matched on name, deliberately, and this is the inverse of the rule above:
298
+ * withholding a table on a wrong guess is a real loss, so that is decided on
299
+ * columns; *ranking* one below another is cheap to get wrong, so a name match
300
+ * is enough. These are fixed names the plugins create, and an app whose own
301
+ * business table is called `member` still ranks — just after its rivals.
302
+ */
303
+ const FRAMEWORK_TABLE_NAMES = /* @__PURE__ */ new Set([
304
+ "account",
305
+ "session",
306
+ "user",
307
+ "verification",
308
+ "invitation",
309
+ "member",
310
+ "organization",
311
+ "team",
312
+ "team_member",
313
+ "apikey",
314
+ "api_key",
315
+ "jwks",
316
+ "passkey",
317
+ "rate_limit",
318
+ "ratelimit",
319
+ "two_factor",
320
+ "twofactor",
321
+ "__drizzle_migrations",
322
+ "drizzle_migrations"
323
+ ]);
324
+ /**
325
+ * Is this table one your auth library created, rather than one you wrote?
326
+ *
327
+ * Used to rank such tables below the developer's own when both could serve a
328
+ * concept. Never to exclude them: mapping `user` as the contact entity is
329
+ * legitimate for plenty of apps, and it stays selectable.
330
+ */
331
+ function isFrameworkTable(name) {
332
+ return FRAMEWORK_TABLE_NAMES.has(name.toLowerCase().replaceAll("-", "_"));
333
+ }
286
334
  function metaFor(table, column) {
287
335
  return table.columnsMeta?.find((c) => c.name === column);
288
336
  }
@@ -497,6 +545,7 @@ function toFieldMap(scored) {
497
545
  exports.TARGET_CONCEPTS = TARGET_CONCEPTS;
498
546
  exports.hasDefiningColumn = hasDefiningColumn;
499
547
  exports.hasSensitiveColumns = hasSensitiveColumns;
548
+ exports.isFrameworkTable = isFrameworkTable;
500
549
  exports.matchesConcept = matchesConcept;
501
550
  exports.requiredFieldsFor = requiredFieldsFor;
502
551
  exports.scoreConcepts = scoreConcepts;
@@ -19,6 +19,14 @@ interface ScoredTable {
19
19
  * They stay manually selectable — an explicit, informed choice is legitimate.
20
20
  */
21
21
  declare function hasSensitiveColumns(columns: string[]): boolean;
22
+ /**
23
+ * Is this table one your auth library created, rather than one you wrote?
24
+ *
25
+ * Used to rank such tables below the developer's own when both could serve a
26
+ * concept. Never to exclude them: mapping `user` as the contact entity is
27
+ * legitimate for plenty of apps, and it stays selectable.
28
+ */
29
+ declare function isFrameworkTable(name: string): boolean;
22
30
  declare function hasDefiningColumn(concept: TargetConcept, columns: string[]): boolean;
23
31
  declare function scoreConcepts(table: ScoredTable): Scored<TargetConcept>[];
24
32
  declare function topConcept(table: ScoredTable): {
@@ -61,4 +69,4 @@ interface FieldSuggestion {
61
69
  declare function scoreFieldMap(concept: TargetConcept, table: ScoredTable): Scored<FieldSuggestion>[];
62
70
  declare function toFieldMap(scored: Scored<FieldSuggestion>[]): Record<string, string>;
63
71
  //#endregion
64
- export { type DiscoveredColumnMeta, FieldSuggestion, RelationshipSuggestion, ScoredTable, SuggestedVia, TARGET_CONCEPTS, TargetConcept, hasDefiningColumn, hasSensitiveColumns, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping };
72
+ export { type DiscoveredColumnMeta, FieldSuggestion, RelationshipSuggestion, ScoredTable, SuggestedVia, TARGET_CONCEPTS, TargetConcept, hasDefiningColumn, hasSensitiveColumns, isFrameworkTable, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping };
@@ -19,6 +19,14 @@ interface ScoredTable {
19
19
  * They stay manually selectable — an explicit, informed choice is legitimate.
20
20
  */
21
21
  declare function hasSensitiveColumns(columns: string[]): boolean;
22
+ /**
23
+ * Is this table one your auth library created, rather than one you wrote?
24
+ *
25
+ * Used to rank such tables below the developer's own when both could serve a
26
+ * concept. Never to exclude them: mapping `user` as the contact entity is
27
+ * legitimate for plenty of apps, and it stays selectable.
28
+ */
29
+ declare function isFrameworkTable(name: string): boolean;
22
30
  declare function hasDefiningColumn(concept: TargetConcept, columns: string[]): boolean;
23
31
  declare function scoreConcepts(table: ScoredTable): Scored<TargetConcept>[];
24
32
  declare function topConcept(table: ScoredTable): {
@@ -61,4 +69,4 @@ interface FieldSuggestion {
61
69
  declare function scoreFieldMap(concept: TargetConcept, table: ScoredTable): Scored<FieldSuggestion>[];
62
70
  declare function toFieldMap(scored: Scored<FieldSuggestion>[]): Record<string, string>;
63
71
  //#endregion
64
- export { type DiscoveredColumnMeta, FieldSuggestion, RelationshipSuggestion, ScoredTable, SuggestedVia, TARGET_CONCEPTS, TargetConcept, hasDefiningColumn, hasSensitiveColumns, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping };
72
+ export { type DiscoveredColumnMeta, FieldSuggestion, RelationshipSuggestion, ScoredTable, SuggestedVia, TARGET_CONCEPTS, TargetConcept, hasDefiningColumn, hasSensitiveColumns, isFrameworkTable, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping };
@@ -282,6 +282,54 @@ const SENSITIVE_COLUMNS = /* @__PURE__ */ new Set([
282
282
  function hasSensitiveColumns(columns) {
283
283
  return columns.some((column) => SENSITIVE_COLUMNS.has(column.toLowerCase().replaceAll("-", "_")));
284
284
  }
285
+ /**
286
+ * Table names the supported auth libraries create.
287
+ *
288
+ * `hasSensitiveColumns` cannot catch these. Better Auth's `organization` table
289
+ * is `{id, name, slug, logo}` — no credential column anywhere, a real `name`,
290
+ * and "organizations" is in the company vocabulary above. It is, by every
291
+ * signal this module has, an excellent company candidate. On `vue-academy`
292
+ * `clivly init` duly chose it over `campuses`, the actual business table that
293
+ * every student row points at, and the first sync exported rows nothing could
294
+ * receive.
295
+ *
296
+ * Matched on name, deliberately, and this is the inverse of the rule above:
297
+ * withholding a table on a wrong guess is a real loss, so that is decided on
298
+ * columns; *ranking* one below another is cheap to get wrong, so a name match
299
+ * is enough. These are fixed names the plugins create, and an app whose own
300
+ * business table is called `member` still ranks — just after its rivals.
301
+ */
302
+ const FRAMEWORK_TABLE_NAMES = /* @__PURE__ */ new Set([
303
+ "account",
304
+ "session",
305
+ "user",
306
+ "verification",
307
+ "invitation",
308
+ "member",
309
+ "organization",
310
+ "team",
311
+ "team_member",
312
+ "apikey",
313
+ "api_key",
314
+ "jwks",
315
+ "passkey",
316
+ "rate_limit",
317
+ "ratelimit",
318
+ "two_factor",
319
+ "twofactor",
320
+ "__drizzle_migrations",
321
+ "drizzle_migrations"
322
+ ]);
323
+ /**
324
+ * Is this table one your auth library created, rather than one you wrote?
325
+ *
326
+ * Used to rank such tables below the developer's own when both could serve a
327
+ * concept. Never to exclude them: mapping `user` as the contact entity is
328
+ * legitimate for plenty of apps, and it stays selectable.
329
+ */
330
+ function isFrameworkTable(name) {
331
+ return FRAMEWORK_TABLE_NAMES.has(name.toLowerCase().replaceAll("-", "_"));
332
+ }
285
333
  function metaFor(table, column) {
286
334
  return table.columnsMeta?.find((c) => c.name === column);
287
335
  }
@@ -493,4 +541,4 @@ function toFieldMap(scored) {
493
541
  return map;
494
542
  }
495
543
  //#endregion
496
- export { TARGET_CONCEPTS, hasDefiningColumn, hasSensitiveColumns, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping };
544
+ export { TARGET_CONCEPTS, hasDefiningColumn, hasSensitiveColumns, isFrameworkTable, matchesConcept, requiredFieldsFor, scoreConcepts, scoreFieldMap, scoreRelationships, suggestCursorField, suggestDiscriminatorColumns, toFieldMap, topConcept, validateMapping };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clivly",
3
- "version": "0.10.6",
3
+ "version": "0.10.7",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Clivly CLI — scaffold a CRM into your app (clivly init).",