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.
- package/core-entity-heuristics.cjs +1 -0
- package/core-entity-heuristics.d.cts +2 -2
- package/core-entity-heuristics.d.mts +2 -2
- package/core-entity-heuristics.mjs +2 -2
- package/index.cjs +24 -5
- package/index.mjs +26 -7
- package/internal-entity-heuristics.cjs +49 -0
- package/internal-entity-heuristics.d.cts +9 -1
- package/internal-entity-heuristics.d.mts +9 -1
- package/internal-entity-heuristics.mjs +49 -1
- package/package.json +1 -1
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 };
|