@vxil/cli 0.35.1 → 0.36.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/vxil-main.js +118 -11
- package/package.json +1 -1
package/dist/vxil-main.js
CHANGED
|
@@ -7260,18 +7260,30 @@ var init_src = __esm({
|
|
|
7260
7260
|
function rulesSummaryOf(r) {
|
|
7261
7261
|
const s = r.body.data?.rules_summary;
|
|
7262
7262
|
if (!isObj(s) || !Array.isArray(s.added) || !Array.isArray(s.removed)) return void 0;
|
|
7263
|
-
|
|
7263
|
+
const dropped = Array.isArray(s.dropped_waiting) ? s.dropped_waiting.filter(isDropped) : [];
|
|
7264
|
+
return { added: s.added.filter(isLine), removed: s.removed.filter(isLine), ...dropped.length ? { dropped_waiting: dropped } : {} };
|
|
7265
|
+
}
|
|
7266
|
+
function droppedWaitingLine(list) {
|
|
7267
|
+
if (!list?.length) return null;
|
|
7268
|
+
const what = list.slice(0, 10).map((d) => `${oneLine(d.kind)} on ${oneLine(d.collection)}${d.quote ? ` ("${oneLine(d.quote)}")` : ""}`).join("; ");
|
|
7269
|
+
const more = list.length > 10 ? `; and ${list.length - 10} more` : "";
|
|
7270
|
+
return `${list.length} ${list.length === 1 ? "rule that was waiting for Apply was" : "rules that were waiting for Apply were"} dropped: ${what}${more}`;
|
|
7264
7271
|
}
|
|
7265
7272
|
function rulesInfoOf(r) {
|
|
7266
7273
|
const s = r.body.data?.rules_info;
|
|
7267
7274
|
return Array.isArray(s) ? s.map((v) => isLine(v) ? v : void 0) : void 0;
|
|
7268
7275
|
}
|
|
7269
7276
|
function formatRulesSummary(s, needsAck = false) {
|
|
7270
|
-
|
|
7277
|
+
const dropped = droppedWaitingLine(s.dropped_waiting);
|
|
7278
|
+
if (!s.added.length && !s.removed.length) {
|
|
7279
|
+
return dropped ? ` rules (server summary): no rule added or removed
|
|
7280
|
+
! ${dropped}` : " rules (server summary): no rule added or removed";
|
|
7281
|
+
}
|
|
7271
7282
|
return [
|
|
7272
7283
|
" rules (server summary):",
|
|
7273
7284
|
...s.added.flatMap((l) => [` + ${oneLine(l.sentence)} ${enforcedTag(l)}`, ...unwrittenLine(l)]),
|
|
7274
|
-
...s.removed.map((l) => ` - ${oneLine(l.sentence)} ${enforcedTag(l)}${needsAck ? NEEDS_ACK : ""}`)
|
|
7285
|
+
...s.removed.map((l) => ` - ${oneLine(l.sentence)} ${enforcedTag(l)}${needsAck ? NEEDS_ACK : ""}`),
|
|
7286
|
+
...dropped ? [` ! ${dropped}`] : []
|
|
7275
7287
|
].join("\n");
|
|
7276
7288
|
}
|
|
7277
7289
|
function configChangeLines(feature, changes, summary, needsAck = false) {
|
|
@@ -7332,7 +7344,7 @@ ${tail}`;
|
|
|
7332
7344
|
return `${head}export default defineConfig(${marked.slice(0, at)}${block}${marked.slice(at + needle.length)});
|
|
7333
7345
|
${tail}`;
|
|
7334
7346
|
}
|
|
7335
|
-
var isObj, isLine, oneLine, enforcedTag, NEEDS_ACK, unwrittenLine, RULES_MARK;
|
|
7347
|
+
var isObj, isLine, oneLine, isDropped, enforcedTag, NEEDS_ACK, unwrittenLine, RULES_MARK;
|
|
7336
7348
|
var init_cmsRulesView = __esm({
|
|
7337
7349
|
"src/cmsRulesView.ts"() {
|
|
7338
7350
|
"use strict";
|
|
@@ -7341,6 +7353,7 @@ var init_cmsRulesView = __esm({
|
|
|
7341
7353
|
isObj = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
7342
7354
|
isLine = (v) => isObj(v) && typeof v.app === "string" && typeof v.kind === "string" && typeof v.collection === "string" && typeof v.sentence === "string" && (v.enforced_by === "app" || v.enforced_by === "server");
|
|
7343
7355
|
oneLine = (s) => s.replace(/[\r\n\u2028\u2029]+/g, " ").trim();
|
|
7356
|
+
isDropped = (v) => isObj(v) && typeof v.kind === "string" && typeof v.collection === "string" && typeof v.quote === "string";
|
|
7344
7357
|
enforcedTag = (l) => l.enforced_by === "server" ? "[enforced_by: server]" : `[enforced_by: app \u2014 only writes through ${oneLine(l.app)}]`;
|
|
7345
7358
|
NEEDS_ACK = " (needs --allow-rule-removal)";
|
|
7346
7359
|
unwrittenLine = (l) => {
|
|
@@ -9019,8 +9032,8 @@ var init_lib = __esm({
|
|
|
9019
9032
|
};
|
|
9020
9033
|
CONFIG_FILENAMES = ["vxil.config.ts", "vxil.config.mjs", "vxil.config.js"];
|
|
9021
9034
|
VXIL_CONFIG_PKG_VERSION = "0.26.1";
|
|
9022
|
-
VXIL_SDK_PKG_VERSION = "0.35.
|
|
9023
|
-
VXIL_CLI_PKG_VERSION = "0.
|
|
9035
|
+
VXIL_SDK_PKG_VERSION = "0.35.2";
|
|
9036
|
+
VXIL_CLI_PKG_VERSION = "0.36.0";
|
|
9024
9037
|
SCAFFOLD_NODE_TYPES_RANGE = "^24.0.0";
|
|
9025
9038
|
SCAFFOLD_TSCONFIG = {
|
|
9026
9039
|
compilerOptions: {
|
|
@@ -19364,6 +19377,7 @@ var EXTRA_KNOWN_FLAGS = [
|
|
|
19364
19377
|
"include-empty",
|
|
19365
19378
|
"include-password-hashes",
|
|
19366
19379
|
"with-password-hashes",
|
|
19380
|
+
"password-hash-column",
|
|
19367
19381
|
"with-oauth-identities",
|
|
19368
19382
|
"keep-source-id",
|
|
19369
19383
|
"keep-timestamps",
|
|
@@ -20458,7 +20472,7 @@ function inferMapping(source, opts = {}) {
|
|
|
20458
20472
|
const cmsNames = [...cmsByName.keys()];
|
|
20459
20473
|
const loadOrder = topoOrder(cmsNames, source.foreignKeys, profile?.table, warnings);
|
|
20460
20474
|
if (source.authUsers?.present) {
|
|
20461
|
-
residuals.push(source.authUsers.hasPasswordHash ? "passwords: hashes are NOT imported by default \u2014 `vxil migrate data --with-password-hashes` carries them (bcrypt, verified and rehashed at each user's first sign-in); without it users re-auth via magic-link/OTP/social/reset on first sign-in" : "auth: credentials do not transfer \u2014 users re-auth via their existing OTP/magic-link/social flow post-cutover");
|
|
20475
|
+
residuals.push(source.authUsers.hasPasswordHash ? "passwords: hashes are NOT imported by default \u2014 `vxil migrate data --with-password-hashes` carries them (bcrypt, verified and rehashed at each user's first sign-in; a generic-pg / csv-json source also names the column with `--password-hash-column <column>`); without it users re-auth via magic-link/OTP/social/reset on first sign-in" : "auth: credentials do not transfer \u2014 users re-auth via their existing OTP/magic-link/social flow post-cutover");
|
|
20462
20476
|
}
|
|
20463
20477
|
for (const chk of source.checks ?? []) {
|
|
20464
20478
|
if (!cmsByName.has(lastSeg(chk.table))) continue;
|
|
@@ -21100,7 +21114,7 @@ function credentialEntry(row2, withHashes) {
|
|
|
21100
21114
|
async function loadCredentials2({ deps, adapter, state, save, opts, delta = false }) {
|
|
21101
21115
|
const result = { table: KEY, read: 0, written: 0, skipped: 0, errors: [], cursor: null };
|
|
21102
21116
|
if (!adapter.readCredentials) {
|
|
21103
|
-
result.errors.push("credentials: this source has no credential reader
|
|
21117
|
+
result.errors.push("credentials: this source has no credential reader \u2014 post the hashes yourself with the SDK `auth.users.import()`, or drop --with-password-hashes / --oidc-issuer");
|
|
21104
21118
|
return result;
|
|
21105
21119
|
}
|
|
21106
21120
|
const cursors = cursorsFor(state, delta);
|
|
@@ -21115,14 +21129,16 @@ async function loadCredentials2({ deps, adapter, state, save, opts, delta = fals
|
|
|
21115
21129
|
const reasons = /* @__PURE__ */ new Map();
|
|
21116
21130
|
let would = deps.dryRun ? {} : null;
|
|
21117
21131
|
let withPassword = 0;
|
|
21132
|
+
let refused = 0;
|
|
21118
21133
|
let withLinks = 0;
|
|
21119
21134
|
let linked = 0;
|
|
21120
|
-
const readOpts = opts.withIdentities ? { identities: true } : void 0;
|
|
21135
|
+
const readOpts = opts.withIdentities || opts.withHashes ? { ...opts.withIdentities ? { identities: true } : {}, ...opts.withHashes ? { hashes: true } : {} } : void 0;
|
|
21121
21136
|
for await (const batch of adapter.readCredentials(cursors[KEY] ?? void 0, readOpts)) {
|
|
21122
21137
|
const entries = [];
|
|
21123
21138
|
const digests = [];
|
|
21124
21139
|
for (const row2 of batch.rows) {
|
|
21125
21140
|
result.read++;
|
|
21141
|
+
if (opts.withHashes && row2.hash_refused) refused++;
|
|
21126
21142
|
const entry = credentialEntry(row2, opts.withHashes);
|
|
21127
21143
|
const h = rowHash({ ...entry, issuer: opts.oidcIssuer ?? null });
|
|
21128
21144
|
if (sent[row2.id] === h) {
|
|
@@ -21204,6 +21220,9 @@ async function loadCredentials2({ deps, adapter, state, save, opts, delta = fals
|
|
|
21204
21220
|
const list = [...reasons].map(([r, n]) => `${r}=${n}`).join(" ");
|
|
21205
21221
|
deps.log(`credentials: ${[...reasons.values()].reduce((a, b2) => a + b2, 0)} user(s) not imported (${list}) \u2014 they sign in once another way (magic link, OTP, a reset); \`not_registered\` means the users step did not load them`);
|
|
21206
21222
|
}
|
|
21223
|
+
if (refused > 0) {
|
|
21224
|
+
deps.log(`credentials: ${refused} password hash(es) are not bcrypt (cost 4\u201310), the only format the import verifies \u2014 ${deps.dryRun ? "they would NOT be sent" : "NOT sent"}; those users are imported without a password and sign in once another way (magic link, OTP, a reset)`);
|
|
21225
|
+
}
|
|
21207
21226
|
result.cursor = deps.dryRun ? cursors[KEY] ?? null : null;
|
|
21208
21227
|
return result;
|
|
21209
21228
|
}
|
|
@@ -22512,7 +22531,7 @@ ${notes.length ? `${notes.join("\n")}
|
|
|
22512
22531
|
`;
|
|
22513
22532
|
}
|
|
22514
22533
|
var STANDING_CAVEATS = [
|
|
22515
|
-
"Passwords: imported only with `vxil migrate data --with-password-hashes` (
|
|
22534
|
+
"Passwords: imported only with `vxil migrate data --with-password-hashes` (bcrypt, verified and replaced at each user's first sign-in \u2014 no forced re-sign-in; generic-pg / csv-json sources also name the hash column with `--password-hash-column <column>`); without it, or for a hash it cannot accept, users re-auth once via magic-link/OTP/social/reset.",
|
|
22516
22535
|
"Push device tokens: vxil has no push provider \u2014 token rows migrate as ordinary owner-scoped cms app data, and sending is a function over egress (the push-notifications blueprint); or skip those tables and let clients re-enroll post-cutover.",
|
|
22517
22536
|
"Subscriptions / entitlements / tier: NEVER seeded (provider-derived truth) \u2014 rebuild from your live provider webhooks after cutover.",
|
|
22518
22537
|
"DB triggers / RPCs / pg_cron / row-level access rules: not auto-migrated \u2014 hand-wire as vxil functions (cms-hook/cron/http triggers; cms-hooks are async post-commit, never in-transaction) + per-collection ownerField.",
|
|
@@ -24892,6 +24911,36 @@ export default defineConfig({
|
|
|
24892
24911
|
import { readFileSync as readFileSync8, readdirSync, existsSync as existsSync8, statSync } from "node:fs";
|
|
24893
24912
|
import { basename as basename3, extname, join as join4, resolve as resolve6 } from "node:path";
|
|
24894
24913
|
|
|
24914
|
+
// src/migrate/adapters/hashImport.ts
|
|
24915
|
+
var BCRYPT_IMPORT_RE = /^\$2[aby]\$(\d{2})\$[./A-Za-z0-9]{53}$/;
|
|
24916
|
+
var BCRYPT_IMPORT_MIN_COST = 4;
|
|
24917
|
+
var BCRYPT_IMPORT_MAX_COST = 10;
|
|
24918
|
+
function importableBcrypt(v) {
|
|
24919
|
+
if (typeof v !== "string") return null;
|
|
24920
|
+
const h = v.trim();
|
|
24921
|
+
const m = BCRYPT_IMPORT_RE.exec(h);
|
|
24922
|
+
if (!m) return null;
|
|
24923
|
+
const cost = Number(m[1]);
|
|
24924
|
+
return cost >= BCRYPT_IMPORT_MIN_COST && cost <= BCRYPT_IMPORT_MAX_COST ? h : null;
|
|
24925
|
+
}
|
|
24926
|
+
function genericCredentialRow(id, raw) {
|
|
24927
|
+
const empty = raw === null || raw === void 0 || typeof raw === "string" && raw.trim() === "";
|
|
24928
|
+
const hash = empty ? null : importableBcrypt(raw);
|
|
24929
|
+
return {
|
|
24930
|
+
id,
|
|
24931
|
+
password_hash: hash,
|
|
24932
|
+
// a generic source has no confirmed-address column vxil can trust
|
|
24933
|
+
email_verified: false,
|
|
24934
|
+
...!empty && hash === null ? { hash_refused: true } : {}
|
|
24935
|
+
};
|
|
24936
|
+
}
|
|
24937
|
+
function missingHashColumnError(from) {
|
|
24938
|
+
return new Error(`--from ${from} --with-password-hashes needs --password-hash-column <column>: the auth table column that holds each user's bcrypt hash (only bcrypt is imported; other formats are reported and not sent)`);
|
|
24939
|
+
}
|
|
24940
|
+
function noIdentitiesError(from) {
|
|
24941
|
+
return new Error(`--with-oauth-identities reads Supabase auth.identities \u2014 a ${from} source has none; drop the flag`);
|
|
24942
|
+
}
|
|
24943
|
+
|
|
24895
24944
|
// src/migrate/adapters/identity.ts
|
|
24896
24945
|
var IDENTITY_COLUMNS = ["id", "email", "display_name", "avatar_url", "raw_user_meta_data"];
|
|
24897
24946
|
function splitIdentityColumns(columns) {
|
|
@@ -25013,11 +25062,13 @@ var CsvJsonAdapter = class {
|
|
|
25013
25062
|
dir;
|
|
25014
25063
|
batchSize;
|
|
25015
25064
|
sampleSize;
|
|
25065
|
+
passwordHashColumn;
|
|
25016
25066
|
cache;
|
|
25017
25067
|
constructor(opts) {
|
|
25018
25068
|
this.dir = resolve6(opts.dir);
|
|
25019
25069
|
this.batchSize = opts.batchSize ?? 500;
|
|
25020
25070
|
this.sampleSize = opts.sampleSize ?? 200;
|
|
25071
|
+
this.passwordHashColumn = opts.passwordHashColumn;
|
|
25021
25072
|
}
|
|
25022
25073
|
load() {
|
|
25023
25074
|
if (this.cache) return this.cache;
|
|
@@ -25264,6 +25315,28 @@ var CsvJsonAdapter = class {
|
|
|
25264
25315
|
};
|
|
25265
25316
|
}
|
|
25266
25317
|
}
|
|
25318
|
+
/** The opt-in credentials read — the authTable's `id` plus the
|
|
25319
|
+
* ONE column the operator named (--password-hash-column), bcrypt only
|
|
25320
|
+
* (hashImport.ts); without --with-password-hashes no hash is read. */
|
|
25321
|
+
async *readCredentials(cursor, opts = {}) {
|
|
25322
|
+
if (opts.identities) throw noIdentitiesError("csv-json");
|
|
25323
|
+
const { schema, tables } = this.load();
|
|
25324
|
+
if (!schema.authUsers?.present || !schema.authUsers.table) {
|
|
25325
|
+
throw new Error("csv-json: no authTable declared in _schema.json \u2014 credentials step unavailable");
|
|
25326
|
+
}
|
|
25327
|
+
const t = tables.get(schema.authUsers.table);
|
|
25328
|
+
const hashCol = opts.hashes ? this.passwordHashColumn : void 0;
|
|
25329
|
+
if (opts.hashes && hashCol === void 0) throw missingHashColumnError("csv-json");
|
|
25330
|
+
if (hashCol !== void 0 && !t.columns.some((c) => c.name === hashCol)) {
|
|
25331
|
+
throw new Error(`--password-hash-column '${hashCol}' is not a column of the authTable '${t.name}'`);
|
|
25332
|
+
}
|
|
25333
|
+
for await (const batch of this.paged(t.rows, cursor)) {
|
|
25334
|
+
yield {
|
|
25335
|
+
rows: batch.rows.filter((r) => r.id !== null && r.id !== void 0 && r.id !== "").map((r) => genericCredentialRow(String(r.id), hashCol !== void 0 ? r[hashCol] : null)),
|
|
25336
|
+
nextCursor: batch.nextCursor
|
|
25337
|
+
};
|
|
25338
|
+
}
|
|
25339
|
+
}
|
|
25267
25340
|
async *paged(all, cursor) {
|
|
25268
25341
|
let offset = 0;
|
|
25269
25342
|
if (cursor !== void 0 && cursor !== "") {
|
|
@@ -25549,6 +25622,7 @@ var GenericPgAdapter = class {
|
|
|
25549
25622
|
schemas;
|
|
25550
25623
|
batchSize;
|
|
25551
25624
|
authTable;
|
|
25625
|
+
passwordHashColumn;
|
|
25552
25626
|
redactedUrl;
|
|
25553
25627
|
/** subclass override point (supabase sets 'supabase'). */
|
|
25554
25628
|
providerName = "generic-pg";
|
|
@@ -25561,6 +25635,7 @@ var GenericPgAdapter = class {
|
|
|
25561
25635
|
this.batchSize = opts.batchSize ?? 500;
|
|
25562
25636
|
this.statementTimeoutMs = Math.trunc(opts.statementTimeoutMs ?? 12e4);
|
|
25563
25637
|
this.authTable = opts.authTable;
|
|
25638
|
+
this.passwordHashColumn = opts.passwordHashColumn;
|
|
25564
25639
|
this.redactedUrl = redactSourceUrl(opts.url);
|
|
25565
25640
|
this.sql = src_default(opts.url, {
|
|
25566
25641
|
max: 1,
|
|
@@ -25858,6 +25933,33 @@ var GenericPgAdapter = class {
|
|
|
25858
25933
|
const t = await this.resolveTable(source.authUsers.table);
|
|
25859
25934
|
yield* this.pagedRead(t, this.identityColumns(t).keep, cursor);
|
|
25860
25935
|
}
|
|
25936
|
+
/** The opt-in credentials read of a generic source — the auth
|
|
25937
|
+
* table's `id` plus the ONE column the operator named
|
|
25938
|
+
* (--password-hash-column), bcrypt only (hashImport.ts). The hashes are
|
|
25939
|
+
* held in memory and sent only in the import body, never logged. Without
|
|
25940
|
+
* --with-password-hashes (an --oidc-issuer-only run) no hash is read. */
|
|
25941
|
+
async *readCredentials(cursor, opts = {}) {
|
|
25942
|
+
if (opts.identities) throw noIdentitiesError(this.providerName);
|
|
25943
|
+
const source = await this.introspect();
|
|
25944
|
+
if (!source.authUsers?.present || !source.authUsers.table) {
|
|
25945
|
+
throw new Error("no auth table configured \u2014 pass --auth-table for generic-pg sources");
|
|
25946
|
+
}
|
|
25947
|
+
const t = await this.resolveTable(source.authUsers.table);
|
|
25948
|
+
const hashCol = opts.hashes ? this.passwordHashColumn : void 0;
|
|
25949
|
+
if (opts.hashes && hashCol === void 0) throw missingHashColumnError(this.providerName);
|
|
25950
|
+
if (hashCol !== void 0 && !t.columns.some((c) => c.name === hashCol)) {
|
|
25951
|
+
throw new Error(`--password-hash-column '${hashCol}' is not a column of the auth table '${t.name}'`);
|
|
25952
|
+
}
|
|
25953
|
+
if (!t.columns.some((c) => c.name === "id")) throw new Error(`the auth table '${t.name}' has no id column`);
|
|
25954
|
+
const pk = t.columns.filter((c) => c.isPk).map((c) => c.name);
|
|
25955
|
+
const cols = [.../* @__PURE__ */ new Set(["id", ...hashCol !== void 0 ? [hashCol] : [], ...pk.length === 1 ? pk : []])];
|
|
25956
|
+
for await (const batch of this.pagedRead(t, cols, cursor)) {
|
|
25957
|
+
yield {
|
|
25958
|
+
rows: batch.rows.filter((r) => r.id !== null && r.id !== void 0 && r.id !== "").map((r) => genericCredentialRow(String(r.id), hashCol !== void 0 ? r[hashCol] : null)),
|
|
25959
|
+
nextCursor: batch.nextCursor
|
|
25960
|
+
};
|
|
25961
|
+
}
|
|
25962
|
+
}
|
|
25861
25963
|
async close() {
|
|
25862
25964
|
await this.sql.end({ timeout: 5 });
|
|
25863
25965
|
}
|
|
@@ -26128,6 +26230,7 @@ function pgOpts(opts) {
|
|
|
26128
26230
|
url: requireUrl(opts),
|
|
26129
26231
|
...opts.schemas !== void 0 ? { schemas: opts.schemas } : {},
|
|
26130
26232
|
...opts.authTable !== void 0 ? { authTable: opts.authTable } : {},
|
|
26233
|
+
...opts.passwordHashColumn !== void 0 ? { passwordHashColumn: opts.passwordHashColumn } : {},
|
|
26131
26234
|
...opts.batchSize !== void 0 ? { batchSize: opts.batchSize } : {},
|
|
26132
26235
|
...opts.statementTimeoutMs !== void 0 ? { statementTimeoutMs: opts.statementTimeoutMs } : {}
|
|
26133
26236
|
};
|
|
@@ -26142,6 +26245,7 @@ var registry = /* @__PURE__ */ new Map([
|
|
|
26142
26245
|
if (!opts.dir) throw new Error("--from csv-json needs --dir <export-directory>");
|
|
26143
26246
|
return new CsvJsonAdapter({
|
|
26144
26247
|
dir: opts.dir,
|
|
26248
|
+
...opts.passwordHashColumn !== void 0 ? { passwordHashColumn: opts.passwordHashColumn } : {},
|
|
26145
26249
|
...opts.batchSize !== void 0 ? { batchSize: opts.batchSize } : {}
|
|
26146
26250
|
});
|
|
26147
26251
|
}]
|
|
@@ -30257,7 +30361,8 @@ function migrateUsage() {
|
|
|
30257
30361
|
step on the server: created/kept/skipped by reason, nothing written) \xB7 [--file-links shared-link] stored
|
|
30258
30362
|
public file URLs become stable shared links instead of object ids
|
|
30259
30363
|
\xB7 [--with-oauth-identities] carry the Google/Apple/GitHub/Facebook sign-in links (needs
|
|
30260
|
-
--with-password-hashes in the same run) \xB7
|
|
30364
|
+
--with-password-hashes in the same run) \xB7 generic-pg / csv-json: --with-password-hashes
|
|
30365
|
+
--password-hash-column <column> (bcrypt only; other formats are reported, not sent) \xB7 [--keep-timestamps] keep each row's source
|
|
30261
30366
|
created_at / updated_at (cms creates; server key only)
|
|
30262
30367
|
\xB7 [--files-owner <user id>] the owner of every migrated file (default: the path's first
|
|
30263
30368
|
segment) \xB7 [--files-org-from-prefix] the path's first segment is the WORKSPACE (org_id):
|
|
@@ -30280,6 +30385,7 @@ ${migrateUsage()}`);
|
|
|
30280
30385
|
const url = flag("url");
|
|
30281
30386
|
const dir = flag("dir");
|
|
30282
30387
|
const authTable = flag("auth-table");
|
|
30388
|
+
const passwordHashColumn = flag("password-hash-column");
|
|
30283
30389
|
const schemas = flag("schemas");
|
|
30284
30390
|
const batch = flag("batch");
|
|
30285
30391
|
const sbUrl = process.env.SUPABASE_URL;
|
|
@@ -30289,6 +30395,7 @@ ${migrateUsage()}`);
|
|
|
30289
30395
|
...url !== void 0 ? { url } : {},
|
|
30290
30396
|
...dir !== void 0 ? { dir } : {},
|
|
30291
30397
|
...authTable !== void 0 ? { authTable } : {},
|
|
30398
|
+
...passwordHashColumn !== void 0 ? { passwordHashColumn } : {},
|
|
30292
30399
|
...schemas !== void 0 ? { schemas: schemas.split(",").map((s) => s.trim()).filter(Boolean) } : {},
|
|
30293
30400
|
...batch !== void 0 ? { batchSize: Number(batch) } : {},
|
|
30294
30401
|
...from === "supabase" && sbUrl && sbKey ? { storage: { url: sbUrl, serviceKey: sbKey } } : {}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vxil/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.36.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The vxil CLI — init, quickstart, push, gen, secrets, keys, migrate, doctor, diff, functions, payments; installs the `vxil` command (npm i -g @vxil/cli).",
|
|
6
6
|
"license": "MIT",
|