tina4-nodejs 3.13.125 → 3.13.131

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.
@@ -1186,8 +1186,8 @@ function hashPassword(password, salt, iterations = 26e4) {
1186
1186
  }
1187
1187
  function checkPassword(password, hash) {
1188
1188
  try {
1189
- const delimiter4 = hash.includes("$") ? "$" : ":";
1190
- const parts = hash.split(delimiter4);
1189
+ const delimiter5 = hash.includes("$") ? "$" : ":";
1190
+ const parts = hash.split(delimiter5);
1191
1191
  if (parts.length !== 4 || parts[0] !== "pbkdf2_sha256") return false;
1192
1192
  const iterations = parseInt(parts[1], 10);
1193
1193
  const salt = parts[2];
@@ -8872,6 +8872,7 @@ var init_mssql = __esm({
8872
8872
  translated = SQLTranslator.concatPipesToFunc(translated);
8873
8873
  translated = SQLTranslator.ilikeToLike(translated);
8874
8874
  translated = SQLTranslator.autoIncrementSyntax(translated, "mssql");
8875
+ translated = SQLTranslator.booleanToInt(translated);
8875
8876
  translated = SQLTranslator.ddlTypes(translated, "mssql");
8876
8877
  return translated;
8877
8878
  }
@@ -12593,7 +12594,7 @@ async function removeMigrationRecord(name) {
12593
12594
  [name]
12594
12595
  );
12595
12596
  }
12596
- async function rollback(migrationsDir, delimiter4) {
12597
+ async function rollback(migrationsDir, delimiter5) {
12597
12598
  if (migrationsDir instanceof Map) {
12598
12599
  const downFunctions = migrationsDir;
12599
12600
  const migrations2 = await getLastBatchMigrations();
@@ -12612,7 +12613,7 @@ async function rollback(migrationsDir, delimiter4) {
12612
12613
  return rolledBack2;
12613
12614
  }
12614
12615
  const dir = resolve5(migrationsDir ?? "migrations");
12615
- const delim = delimiter4 ?? ";";
12616
+ const delim = delimiter5 ?? ";";
12616
12617
  const db = getAdapter();
12617
12618
  const migrations = await getLastBatchMigrations();
12618
12619
  const rolledBack = [];
@@ -12663,12 +12664,12 @@ function parseSetTerm(statement) {
12663
12664
  const m = statement.trim().match(SET_TERM_RE);
12664
12665
  return m ? m[1] : null;
12665
12666
  }
12666
- function splitStatements(sql, delimiter4 = ";") {
12667
+ function splitStatements(sql, delimiter5 = ";") {
12667
12668
  sql = normalizeQuotes(sql);
12668
12669
  const statements = [];
12669
12670
  let current = "";
12670
12671
  const n = sql.length;
12671
- let dlen = delimiter4.length;
12672
+ let dlen = delimiter5.length;
12672
12673
  let i = 0;
12673
12674
  let inDollarBlock = false;
12674
12675
  let inSlashBlock = false;
@@ -12737,15 +12738,15 @@ function splitStatements(sql, delimiter4 = ";") {
12737
12738
  }
12738
12739
  continue;
12739
12740
  }
12740
- if (dlen > 0 && sql.startsWith(delimiter4, i)) {
12741
+ if (dlen > 0 && sql.startsWith(delimiter5, i)) {
12741
12742
  i += dlen;
12742
12743
  const stmt2 = current.trim();
12743
12744
  current = "";
12744
12745
  if (stmt2) {
12745
12746
  const newTerm = parseSetTerm(stmt2);
12746
12747
  if (newTerm !== null) {
12747
- delimiter4 = newTerm;
12748
- dlen = delimiter4.length;
12748
+ delimiter5 = newTerm;
12749
+ dlen = delimiter5.length;
12749
12750
  } else {
12750
12751
  statements.push(stmt2);
12751
12752
  }
@@ -12784,7 +12785,7 @@ function warnUnprefixedMigrations(files) {
12784
12785
  async function migrate(adapter, options) {
12785
12786
  const db = adapter ?? getAdapter();
12786
12787
  const dir = resolve5(options?.migrationsDir ?? "migrations");
12787
- const delimiter4 = options?.delimiter ?? ";";
12788
+ const delimiter5 = options?.delimiter ?? ";";
12788
12789
  const result = { applied: [], skipped: [], failed: [] };
12789
12790
  if (!existsSync6(dir)) {
12790
12791
  return result;
@@ -12827,7 +12828,7 @@ async function migrate(adapter, options) {
12827
12828
  result.skipped.push(file);
12828
12829
  continue;
12829
12830
  }
12830
- const statements = splitStatements(sqlContent, delimiter4);
12831
+ const statements = splitStatements(sqlContent, delimiter5);
12831
12832
  try {
12832
12833
  await adapterStartTransaction(db);
12833
12834
  for (const stmt of statements) {
@@ -15456,7 +15457,7 @@ function mulberry32(seed) {
15456
15457
  return ((t ^ t >>> 14) >>> 0) / 4294967296;
15457
15458
  };
15458
15459
  }
15459
- var FIRST_NAMES, LAST_NAMES, DOMAINS, WORDS, CITIES, COUNTRIES, STREETS, JOB_TITLES, CURRENCIES, FakeData;
15460
+ var FIRST_NAMES, LAST_NAMES, DOMAINS, WORDS, CITIES, COUNTRIES, STREETS, JOB_TITLES, CURRENCIES, PRODUCT_ADJECTIVES, PRODUCT_NOUNS, FakeData;
15460
15461
  var init_fakeData = __esm({
15461
15462
  "../core/src/fakeData.ts"() {
15462
15463
  "use strict";
@@ -15718,6 +15719,59 @@ var init_fakeData = __esm({
15718
15719
  "ZAR",
15719
15720
  "INR"
15720
15721
  ];
15722
+ PRODUCT_ADJECTIVES = [
15723
+ "Wireless",
15724
+ "Organic",
15725
+ "Premium",
15726
+ "Classic",
15727
+ "Eco",
15728
+ "Smart",
15729
+ "Portable",
15730
+ "Deluxe",
15731
+ "Compact",
15732
+ "Rustic",
15733
+ "Handcrafted",
15734
+ "Vintage",
15735
+ "Modern",
15736
+ "Ergonomic",
15737
+ "Stainless",
15738
+ "Bamboo",
15739
+ "Recycled",
15740
+ "Artisan",
15741
+ "Professional",
15742
+ "Ultra",
15743
+ "Insulated",
15744
+ "Lightweight",
15745
+ "Adjustable",
15746
+ "Foldable"
15747
+ ];
15748
+ PRODUCT_NOUNS = [
15749
+ "Keyboard",
15750
+ "Coffee Beans",
15751
+ "Backpack",
15752
+ "Water Bottle",
15753
+ "Desk Lamp",
15754
+ "Headphones",
15755
+ "Notebook",
15756
+ "Sneakers",
15757
+ "Sunglasses",
15758
+ "Wallet",
15759
+ "Mug",
15760
+ "Chair",
15761
+ "Blender",
15762
+ "Speaker",
15763
+ "Charger",
15764
+ "Umbrella",
15765
+ "Toothbrush",
15766
+ "Jacket",
15767
+ "Watch",
15768
+ "Kettle",
15769
+ "Picture Frame",
15770
+ "Planter",
15771
+ "Cutlery Set",
15772
+ "Yoga Mat",
15773
+ "Phone Case"
15774
+ ];
15721
15775
  FakeData = class _FakeData {
15722
15776
  rng;
15723
15777
  seeded;
@@ -15789,6 +15843,16 @@ var init_fakeData = __esm({
15789
15843
  jobTitle() {
15790
15844
  return this.pick(JOB_TITLES);
15791
15845
  }
15846
+ /**
15847
+ * A plausible product name, e.g. "Wireless Keyboard" or "Organic Coffee
15848
+ * Beans" — an adjective + noun from the product vocabulary. Deterministic
15849
+ * under a seed like every other generator (draws from the same instance
15850
+ * PRNG). Used to seed a generic `name` column on a product-ish table instead
15851
+ * of a person name (see the ORM FakeData `forField` heuristic).
15852
+ */
15853
+ product() {
15854
+ return `${this.pick(PRODUCT_ADJECTIVES)} ${this.pick(PRODUCT_NOUNS)}`;
15855
+ }
15792
15856
  paragraph(sentences = 4) {
15793
15857
  const parts = [];
15794
15858
  for (let i = 0; i < sentences; i++) {
@@ -15912,11 +15976,27 @@ var init_fakeData = __esm({
15912
15976
  });
15913
15977
 
15914
15978
  // ../orm/src/fakeData.ts
15915
- var FakeData2;
15979
+ function isProductTable(table2) {
15980
+ const t = (table2 ?? "").toLowerCase();
15981
+ return PRODUCT_TABLE_HINTS.some((hint) => t.includes(hint));
15982
+ }
15983
+ var PRODUCT_TABLE_HINTS, FakeData2;
15916
15984
  var init_fakeData2 = __esm({
15917
15985
  "../orm/src/fakeData.ts"() {
15918
15986
  "use strict";
15919
15987
  init_fakeData();
15988
+ PRODUCT_TABLE_HINTS = [
15989
+ "product",
15990
+ "item",
15991
+ "catalog",
15992
+ "inventory",
15993
+ "goods",
15994
+ "merchandise",
15995
+ "sku",
15996
+ "listing",
15997
+ "stock",
15998
+ "ware"
15999
+ ];
15920
16000
  FakeData2 = class extends FakeData {
15921
16001
  constructor(seed) {
15922
16002
  super(seed);
@@ -15938,8 +16018,11 @@ var init_fakeData2 = __esm({
15938
16018
  *
15939
16019
  * @param fieldDef - An ORM FieldDefinition object
15940
16020
  * @param columnName - Optional column name for heuristic matching (e.g. "email", "phone")
16021
+ * @param table - Optional table/model name. A generic `name`/`full_name`
16022
+ * column on a product-ish table (see {@link isProductTable}) gets a
16023
+ * product name; with no table context it stays a person name (back-compat).
15941
16024
  */
15942
- forField(fieldDef, columnName) {
16025
+ forField(fieldDef, columnName, table2) {
15943
16026
  if (fieldDef.primaryKey && fieldDef.autoIncrement) {
15944
16027
  return void 0;
15945
16028
  }
@@ -15949,7 +16032,9 @@ var init_fakeData2 = __esm({
15949
16032
  const col = (columnName ?? "").toLowerCase();
15950
16033
  if (col.includes("email")) return this.email();
15951
16034
  if (col.includes("phone") || col.includes("mobile") || col.includes("tel")) return this.phone();
15952
- if (col === "name" || col === "full_name" || col === "fullname") return this.name();
16035
+ if (col === "name" || col === "full_name" || col === "fullname") {
16036
+ return isProductTable(table2) ? this.product() : this.name();
16037
+ }
15953
16038
  if (col === "first_name" || col === "firstname") return this.firstName();
15954
16039
  if (col === "last_name" || col === "lastname" || col === "surname") return this.lastName();
15955
16040
  if (col.includes("address")) return this.address();
@@ -16036,7 +16121,7 @@ async function autoFieldMap(db, table2, fake = new FakeData2()) {
16036
16121
  continue;
16037
16122
  }
16038
16123
  const fieldType = sqlTypeToFieldType(sqlType);
16039
- fieldMap[name] = () => fake.forField({ type: fieldType }, name);
16124
+ fieldMap[name] = () => fake.forField({ type: fieldType }, name, table2);
16040
16125
  }
16041
16126
  return fieldMap;
16042
16127
  }
@@ -16182,7 +16267,7 @@ async function seedOrm(ormClass, count = 10, overrides, seed, opts, fkPools) {
16182
16267
  } else if (pools[name] && pools[name].length > 0) {
16183
16268
  attrs[name] = fake.choice(pools[name]);
16184
16269
  } else {
16185
- attrs[name] = fake.forField(def, name);
16270
+ attrs[name] = fake.forField(def, name, modelName);
16186
16271
  }
16187
16272
  }
16188
16273
  validateTypes(fields, attrs, modelName);
@@ -21217,14 +21302,14 @@ function extractBoundary(contentType) {
21217
21302
  function parseMultipart(body, boundary) {
21218
21303
  const fields = {};
21219
21304
  const files = {};
21220
- const delimiter4 = Buffer.from(`--${boundary}`);
21305
+ const delimiter5 = Buffer.from(`--${boundary}`);
21221
21306
  const closeDelimiter = Buffer.from(`--${boundary}--`);
21222
21307
  const crlf = Buffer.from("\r\n");
21223
21308
  const doubleCrlf = Buffer.from("\r\n\r\n");
21224
21309
  let offset = 0;
21225
- const firstIdx = bufferIndexOf(body, delimiter4, offset);
21310
+ const firstIdx = bufferIndexOf(body, delimiter5, offset);
21226
21311
  if (firstIdx === -1) return { fields, files };
21227
- offset = firstIdx + delimiter4.length;
21312
+ offset = firstIdx + delimiter5.length;
21228
21313
  if (body[offset] === 13 && body[offset + 1] === 10) {
21229
21314
  offset += 2;
21230
21315
  }
@@ -21233,7 +21318,7 @@ function parseMultipart(body, boundary) {
21233
21318
  if (headersEnd === -1) break;
21234
21319
  const headersStr = body.subarray(offset, headersEnd).toString("utf-8");
21235
21320
  offset = headersEnd + doubleCrlf.length;
21236
- const nextDelimIdx = bufferIndexOf(body, delimiter4, offset);
21321
+ const nextDelimIdx = bufferIndexOf(body, delimiter5, offset);
21237
21322
  if (nextDelimIdx === -1) break;
21238
21323
  const contentEnd = nextDelimIdx - crlf.length;
21239
21324
  const content = body.subarray(offset, contentEnd);
@@ -21256,7 +21341,7 @@ function parseMultipart(body, boundary) {
21256
21341
  } else if (disposition.name) {
21257
21342
  fields[disposition.name] = content.toString("utf-8");
21258
21343
  }
21259
- offset = nextDelimIdx + delimiter4.length;
21344
+ offset = nextDelimIdx + delimiter5.length;
21260
21345
  if (body[offset] === 45 && body[offset + 1] === 45) {
21261
21346
  break;
21262
21347
  }
@@ -24429,6 +24514,7 @@ __export(generate_exports, {
24429
24514
  parseEvery: () => parseEvery,
24430
24515
  parseFields: () => parseFields,
24431
24516
  pluralizeReserved: () => pluralizeReserved,
24517
+ resolveTable: () => resolveTable,
24432
24518
  toPascal: () => toPascal,
24433
24519
  toSnake: () => toSnake,
24434
24520
  toTableName: () => toTableName
@@ -24471,12 +24557,35 @@ function toTableName(name) {
24471
24557
  from: raw,
24472
24558
  to: safe,
24473
24559
  reason: `SQL reserved word '${raw}' would break CREATE TABLE`,
24474
- override: `--table ${raw} --quote (requires quoted-identifier mode, not yet implemented)`
24560
+ override: `--table-name <name> (table names interpolate unquoted; forcing a reserved name is yours to quote in raw SQL)`
24475
24561
  });
24476
24562
  return safe;
24477
24563
  }
24478
24564
  return raw;
24479
24565
  }
24566
+ function resolveTable(name, flags, opts = {}) {
24567
+ const announce = opts.announce ?? false;
24568
+ const override = (flags ?? {})["table-name"];
24569
+ if (typeof override === "string" && override) {
24570
+ if (announce && SQL_RESERVED_TABLE_NAMES.has(toSnake(override))) {
24571
+ console.error(
24572
+ ` ! table_name '${override}' is a SQL reserved word. Tina4 interpolates table names UNQUOTED, so the ORM's generated SQL will fail on it -- quote it yourself in raw SQL and migrations.`
24573
+ );
24574
+ }
24575
+ return override;
24576
+ }
24577
+ const bare = toSnake(name);
24578
+ if (!SQL_RESERVED_TABLE_NAMES.has(bare)) {
24579
+ return bare;
24580
+ }
24581
+ const table2 = toTableName(name);
24582
+ if (announce) {
24583
+ console.error(
24584
+ ` \xB7 '${bare}' is a SQL reserved word; using table_name '${table2}' (Tina4 interpolates table names unquoted). Override with --table-name <name>.`
24585
+ );
24586
+ }
24587
+ return table2;
24588
+ }
24480
24589
  function resetResolution(target, input, opts) {
24481
24590
  __resolution.target = target;
24482
24591
  __resolution.input = input;
@@ -24575,10 +24684,11 @@ function printResolution() {
24575
24684
  lines.push(` migration ${b.migration_path}`);
24576
24685
  }
24577
24686
  const reserved = b.transformations.find((t) => t.kind === "reserved_word_pluralize");
24578
- if (reserved && reserved.from && reserved.override) {
24687
+ if (reserved && reserved.from) {
24579
24688
  lines.push("");
24580
- lines.push(` To keep the raw name '${reserved.from}' as the table:`);
24581
- lines.push(` tina4nodejs generate ${__resolution.target} ${__resolution.input.name} ${reserved.override}`);
24689
+ lines.push(` To set the table name yourself:`);
24690
+ lines.push(` tina4nodejs generate ${__resolution.target} ${__resolution.input.name} --table-name <name>`);
24691
+ lines.push(` Tina4 interpolates table names unquoted; if you force the reserved '${reserved.from}', you own the quoting in raw SQL.`);
24582
24692
  }
24583
24693
  if (b.test_paths && b.test_paths.length > 0) {
24584
24694
  lines.push("");
@@ -24714,6 +24824,7 @@ async function generate(what, name, extraArgs = []) {
24714
24824
  console.error(" Usage: tina4nodejs generate <what> <name> [options]");
24715
24825
  console.error(` Generators: ${GENERATOR_LIST}`);
24716
24826
  console.error(' Options: --fields "name:string,price:float" --model ModelName');
24827
+ console.error(" --table-name <name> force the model's table name (else derived; reserved words auto-pluralise)");
24717
24828
  console.error(" --public open a route's writes (default: secure)");
24718
24829
  console.error(' --every 5m | --cron "\u2026" service schedule');
24719
24830
  console.error(" --json emit machine-readable resolution envelope on stdout");
@@ -24764,7 +24875,7 @@ async function generateProgrammatic(what, name, extraArgs = []) {
24764
24875
  }
24765
24876
  function generateModel(name, flags, emitTest = true) {
24766
24877
  const fields = fieldsOrDefault(flags.fields || "");
24767
- const table2 = toTableName(name);
24878
+ const table2 = resolveTable(name, flags, { announce: true });
24768
24879
  const dir = resolve11("src/models");
24769
24880
  ensureDir(dir);
24770
24881
  const path8 = join21(dir, `${name}.ts`);
@@ -24815,7 +24926,7 @@ function generateRoute(name, flags, emitTest = true) {
24815
24926
  if (__resolution.target === "route") {
24816
24927
  setResolutionField("file_path", `src/routes/api/${routePath}/get.ts`);
24817
24928
  }
24818
- const table2 = model ? toTableName(model) : "";
24929
+ const table2 = model ? resolveTable(model, flags, { announce: false }) : "";
24819
24930
  const modelImportBase = model ? `import ${model} from "../../../models/${model}.js";
24820
24931
  ` : "";
24821
24932
  const modelImportId = model ? `import ${model} from "../../../../models/${model}.js";
@@ -25036,7 +25147,7 @@ ${aiFill(`delete_${singular}`, {
25036
25147
  }
25037
25148
  }
25038
25149
  function generateCrud(name, flags) {
25039
- const table2 = toTableName(name);
25150
+ const table2 = resolveTable(name, flags, { announce: false });
25040
25151
  const routeName = toPlural(table2);
25041
25152
  const isPublic = Boolean(flags.public);
25042
25153
  if (!__resolution.jsonMode) console.log(`
@@ -25063,7 +25174,7 @@ function generateMigration(name, flags, fieldsOverride, tableOverride, emitTest
25063
25174
  table2 = tableOverride;
25064
25175
  } else {
25065
25176
  const raw = name.replace(/^create_/, "").replace(/^add_/, "").replace(/^drop_/, "");
25066
- table2 = toTableName(raw);
25177
+ table2 = resolveTable(raw, flags, { announce: false });
25067
25178
  }
25068
25179
  if (__resolution.target === "migration") {
25069
25180
  setResolutionField("table_name", table2);
@@ -25289,7 +25400,7 @@ void test${titleName};
25289
25400
  }
25290
25401
  function generateForm(name, flags) {
25291
25402
  const fields = fieldsOrDefault(flags.fields || "");
25292
- const table2 = toTableName(name);
25403
+ const table2 = resolveTable(name, flags, { announce: false });
25293
25404
  const routeName = toPlural(table2);
25294
25405
  const inputTypes = {
25295
25406
  string: "text",
@@ -25355,7 +25466,7 @@ function generateForm(name, flags) {
25355
25466
  }
25356
25467
  function generateView(name, flags) {
25357
25468
  const fields = fieldsOrDefault(flags.fields || "");
25358
- const table2 = toTableName(name);
25469
+ const table2 = resolveTable(name, flags, { announce: false });
25359
25470
  const routeName = toPlural(table2);
25360
25471
  const cols = fields.map(([f]) => f);
25361
25472
  const dir = resolve11("src/templates/pages");
@@ -25710,8 +25821,8 @@ ${rules} validator.required("name"); // starter rule (matches the model's def
25710
25821
  writeFileSafe(path8, content);
25711
25822
  emitValidatorTest(name, toSnake(name), toPascal(name));
25712
25823
  }
25713
- function generateSeeder(name, _flags) {
25714
- const table2 = toTableName(name);
25824
+ function generateSeeder(name, flags) {
25825
+ const table2 = resolveTable(name, flags, { announce: false });
25715
25826
  const dir = resolve11("src/seeds");
25716
25827
  ensureDir(dir);
25717
25828
  const path8 = join21(dir, `${table2}_seeder.ts`);
@@ -26336,7 +26447,7 @@ var init_generate = __esm({
26336
26447
  TINA4_EDIT_MARKER = /^\s*(?:\/\/|--|\{#|#)\s*tina4:edit\s+(.+?)(?:\s*#\})?\s*$/;
26337
26448
  DEFAULT_FIELDS = [["name", "string"]];
26338
26449
  GENERATORS = {
26339
- model: { handler: generateModel, usage: '<Name> [--fields "name:string,price:float"]', summary: "ORM model + matching migration" },
26450
+ model: { handler: generateModel, usage: '<Name> [--fields "name:string,price:float"] [--table-name <name>]', summary: "ORM model + matching migration" },
26340
26451
  route: { handler: generateRoute, usage: "<name> [--model Name] [--public]", summary: "CRUD route file, secure by default (--public opens writes)" },
26341
26452
  crud: { handler: generateCrud, usage: '<Name> [--fields "..."] [--public]', summary: "Model + migration + routes + form + view + test" },
26342
26453
  migration: { handler: (n, f) => generateMigration(n, f, void 0, void 0, !f["no-test"]), usage: "<description>", summary: "Timestamped migration file (UP/DOWN)" },
@@ -37033,23 +37144,23 @@ var init_devAdmin = __esm({
37033
37144
  });
37034
37145
  };
37035
37146
  handleDevAdminJs = async (_req, res) => {
37036
- const { readFileSync: readFileSync29, existsSync: existsSync36 } = await import("node:fs");
37037
- const { dirname: dirname17, join: join39, resolve: resolve29 } = await import("node:path");
37147
+ const { readFileSync: readFileSync30, existsSync: existsSync37 } = await import("node:fs");
37148
+ const { dirname: dirname18, join: join40, resolve: resolve29 } = await import("node:path");
37038
37149
  const { fileURLToPath: fileURLToPath10 } = await import("node:url");
37039
- const dir = dirname17(fileURLToPath10(import.meta.url));
37150
+ const dir = dirname18(fileURLToPath10(import.meta.url));
37040
37151
  const candidates = [
37041
- join39(dir, "..", "public", "js", "tina4-dev-admin.min.js"),
37152
+ join40(dir, "..", "public", "js", "tina4-dev-admin.min.js"),
37042
37153
  // src/../public/js/
37043
- join39(dir, "..", "..", "public", "js", "tina4-dev-admin.min.js"),
37154
+ join40(dir, "..", "..", "public", "js", "tina4-dev-admin.min.js"),
37044
37155
  // deeper nesting
37045
37156
  resolve29(process.cwd(), "node_modules", "tina4-nodejs", "packages", "core", "public", "js", "tina4-dev-admin.min.js"),
37046
37157
  resolve29(process.cwd(), "public", "js", "tina4-dev-admin.min.js")
37047
37158
  // project public/
37048
37159
  ];
37049
37160
  for (const jsPath of candidates) {
37050
- if (existsSync36(jsPath)) {
37161
+ if (existsSync37(jsPath)) {
37051
37162
  try {
37052
- const content = readFileSync29(jsPath, "utf-8");
37163
+ const content = readFileSync30(jsPath, "utf-8");
37053
37164
  res.raw.writeHead(200, { "Content-Type": "application/javascript; charset=utf-8", "Cache-Control": "no-cache" });
37054
37165
  res.raw.end(content);
37055
37166
  return;
@@ -40926,23 +41037,23 @@ function guessContentType(filename) {
40926
41037
  }
40927
41038
  function buildMultipartBody(boundary, fieldName, filename, fileContent, contentType, extraFields) {
40928
41039
  const crlf = "\r\n";
40929
- const delimiter4 = `--${boundary}`;
41040
+ const delimiter5 = `--${boundary}`;
40930
41041
  const parts = [];
40931
41042
  if (extraFields) {
40932
41043
  for (const [key, value] of Object.entries(extraFields)) {
40933
- parts.push(Buffer.from(delimiter4 + crlf, "utf-8"));
41044
+ parts.push(Buffer.from(delimiter5 + crlf, "utf-8"));
40934
41045
  parts.push(Buffer.from(`Content-Disposition: form-data; name="${key}"` + crlf + crlf, "utf-8"));
40935
41046
  parts.push(Buffer.from(String(value) + crlf, "utf-8"));
40936
41047
  }
40937
41048
  }
40938
- parts.push(Buffer.from(delimiter4 + crlf, "utf-8"));
41049
+ parts.push(Buffer.from(delimiter5 + crlf, "utf-8"));
40939
41050
  parts.push(
40940
41051
  Buffer.from(`Content-Disposition: form-data; name="${fieldName}"; filename="${filename}"` + crlf, "utf-8")
40941
41052
  );
40942
41053
  parts.push(Buffer.from(`Content-Type: ${contentType}` + crlf + crlf, "utf-8"));
40943
41054
  parts.push(fileContent);
40944
41055
  parts.push(Buffer.from(crlf, "utf-8"));
40945
- parts.push(Buffer.from(delimiter4 + "--" + crlf, "utf-8"));
41056
+ parts.push(Buffer.from(delimiter5 + "--" + crlf, "utf-8"));
40946
41057
  return Buffer.concat(parts);
40947
41058
  }
40948
41059
  async function* parseLineStream(chunks) {
@@ -47499,8 +47610,8 @@ async function runTests(testPath) {
47499
47610
  console.log(` Found ${testFiles.length} test file(s)
47500
47611
  `);
47501
47612
  for (const file of testFiles) {
47502
- const relative11 = file.replace(cwd + "/", "");
47503
- console.log(` Running: ${relative11}`);
47613
+ const relative12 = file.replace(cwd + "/", "");
47614
+ console.log(` Running: ${relative12}`);
47504
47615
  try {
47505
47616
  execSync3(`npx tsx "${file}"`, { cwd, stdio: "inherit" });
47506
47617
  } catch {
@@ -47510,19 +47621,233 @@ async function runTests(testPath) {
47510
47621
  process.exit(inlineFailed || fileFailed ? 1 : 0);
47511
47622
  }
47512
47623
 
47624
+ // src/commands/lint.ts
47625
+ import { existsSync as existsSync33, readdirSync as readdirSync20, readFileSync as readFileSync28, statSync as statSync20, writeFileSync as writeFileSync20 } from "node:fs";
47626
+ import { createRequire as createRequire9 } from "node:module";
47627
+ import { delimiter as delimiter2, dirname as dirname16, join as join35, relative as relative11 } from "node:path";
47628
+ import { spawnSync as spawnSync3 } from "node:child_process";
47629
+ var LINT_EXTENSIONS = [".ts", ".mts", ".cts", ".js", ".mjs", ".cjs"];
47630
+ var JS_EXTENSIONS = [".js", ".mjs", ".cjs"];
47631
+ var SKIP_DIRS3 = /* @__PURE__ */ new Set(["node_modules", "dist", ".git"]);
47632
+ function isLintFile(name) {
47633
+ if (name.endsWith(".d.ts")) return false;
47634
+ return LINT_EXTENSIONS.some((ext) => name.endsWith(ext));
47635
+ }
47636
+ function walkSource2(dir, out) {
47637
+ let entries;
47638
+ try {
47639
+ entries = readdirSync20(dir);
47640
+ } catch {
47641
+ return;
47642
+ }
47643
+ for (const name of entries) {
47644
+ if (SKIP_DIRS3.has(name)) continue;
47645
+ const full = join35(dir, name);
47646
+ let st;
47647
+ try {
47648
+ st = statSync20(full);
47649
+ } catch {
47650
+ continue;
47651
+ }
47652
+ if (st.isDirectory()) {
47653
+ walkSource2(full, out);
47654
+ } else if (isLintFile(name)) {
47655
+ out.push(full);
47656
+ }
47657
+ }
47658
+ }
47659
+ function collectAppFiles(cwd) {
47660
+ const files = [];
47661
+ const srcDir = join35(cwd, "src");
47662
+ try {
47663
+ if (statSync20(srcDir).isDirectory()) walkSource2(srcDir, files);
47664
+ } catch {
47665
+ }
47666
+ for (const entry of ["app.ts", "app.mts", "app.js", "app.mjs"]) {
47667
+ const p = join35(cwd, entry);
47668
+ try {
47669
+ if (statSync20(p).isFile()) files.push(p);
47670
+ } catch {
47671
+ }
47672
+ }
47673
+ return files;
47674
+ }
47675
+ var ESLINT_FLAT_CONFIGS = [
47676
+ "eslint.config.js",
47677
+ "eslint.config.mjs",
47678
+ "eslint.config.cjs",
47679
+ "eslint.config.ts",
47680
+ "eslint.config.mts",
47681
+ "eslint.config.cts"
47682
+ ];
47683
+ var ESLINT_SCAFFOLD_FILE = "eslint.config.js";
47684
+ var ESLINT_SCAFFOLD = `import js from "@eslint/js";
47685
+ import tseslint from "typescript-eslint";
47686
+ export default [js.configs.recommended, ...tseslint.configs.recommended];
47687
+ `;
47688
+ function findEslintConfig(cwd) {
47689
+ for (const name of ESLINT_FLAT_CONFIGS) {
47690
+ const p = join35(cwd, name);
47691
+ if (existsSync33(p)) return p;
47692
+ }
47693
+ return null;
47694
+ }
47695
+ function resolvePackageBin(cwd, pkg, binRelative) {
47696
+ const direct = join35(cwd, "node_modules", pkg, binRelative);
47697
+ if (existsSync33(direct)) return direct;
47698
+ const require3 = createRequire9(join35(cwd, "package.json"));
47699
+ let entry;
47700
+ try {
47701
+ entry = require3.resolve(pkg);
47702
+ } catch {
47703
+ return null;
47704
+ }
47705
+ let dir = dirname16(entry);
47706
+ for (let i = 0; i < 8; i++) {
47707
+ const pkgJson = join35(dir, "package.json");
47708
+ if (existsSync33(pkgJson)) {
47709
+ try {
47710
+ if (JSON.parse(readFileSync28(pkgJson, "utf-8")).name === pkg) {
47711
+ const bin = join35(dir, binRelative);
47712
+ return existsSync33(bin) ? bin : null;
47713
+ }
47714
+ } catch {
47715
+ }
47716
+ }
47717
+ const parent = dirname16(dir);
47718
+ if (parent === dir) break;
47719
+ dir = parent;
47720
+ }
47721
+ return null;
47722
+ }
47723
+ function resolveEslintBin(cwd) {
47724
+ return resolvePackageBin(cwd, "eslint", "bin/eslint.js");
47725
+ }
47726
+ function hasPackage(cwd, pkg) {
47727
+ return existsSync33(join35(cwd, "node_modules", ...pkg.split("/"), "package.json"));
47728
+ }
47729
+ function resolveNpm() {
47730
+ const windows = process.platform === "win32";
47731
+ const names = windows ? ["npm.cmd", "npm.exe", "npm"] : ["npm"];
47732
+ for (const dir of (process.env.PATH ?? "").split(delimiter2)) {
47733
+ if (!dir) continue;
47734
+ for (const name of names) {
47735
+ const candidate = join35(dir, name);
47736
+ try {
47737
+ if (statSync20(candidate).isFile()) return candidate;
47738
+ } catch {
47739
+ }
47740
+ }
47741
+ }
47742
+ return null;
47743
+ }
47744
+ function runLint(args) {
47745
+ const fix = args.includes("--fix");
47746
+ const noInstall = args.includes("--no-install");
47747
+ const cwd = process.cwd();
47748
+ const files = collectAppFiles(cwd);
47749
+ if (files.length === 0) {
47750
+ console.log(" lint: nothing to lint (no src/ or app.ts).");
47751
+ process.exit(0);
47752
+ }
47753
+ let eslintBin = resolveEslintBin(cwd);
47754
+ let eslintConfig = findEslintConfig(cwd);
47755
+ if (!noInstall && (!eslintBin || !eslintConfig)) {
47756
+ const npm = resolveNpm();
47757
+ if (!npm) {
47758
+ console.log(" \xB7 npm not found \u2014 using the zero-dependency baseline.");
47759
+ } else {
47760
+ if (!eslintBin) {
47761
+ console.log(" \xB7 installing eslint (npm i -D eslint @eslint/js typescript-eslint)...");
47762
+ const rc = spawnSync3(npm, ["install", "-D", "eslint", "@eslint/js", "typescript-eslint"], {
47763
+ cwd,
47764
+ stdio: "inherit"
47765
+ }).status;
47766
+ if (rc === 0) {
47767
+ eslintBin = resolveEslintBin(cwd);
47768
+ } else {
47769
+ console.log(" \xB7 could not install eslint \u2014 using the zero-dependency baseline.");
47770
+ }
47771
+ }
47772
+ if (eslintBin && !eslintConfig && hasPackage(cwd, "@eslint/js") && hasPackage(cwd, "typescript-eslint")) {
47773
+ const scaffold = join35(cwd, ESLINT_SCAFFOLD_FILE);
47774
+ try {
47775
+ writeFileSync20(scaffold, ESLINT_SCAFFOLD, "utf-8");
47776
+ eslintConfig = scaffold;
47777
+ console.log(` \xB7 scaffolded ${ESLINT_SCAFFOLD_FILE} (@eslint/js + typescript-eslint recommended).`);
47778
+ } catch (err) {
47779
+ console.log(
47780
+ ` \xB7 could not scaffold ${ESLINT_SCAFFOLD_FILE} (${err instanceof Error ? err.message : String(err)}).`
47781
+ );
47782
+ }
47783
+ }
47784
+ }
47785
+ }
47786
+ if (eslintBin && eslintConfig) {
47787
+ const label = fix ? "eslint --fix" : "eslint";
47788
+ const eslintArgs = [eslintBin, ...files, ...fix ? ["--fix"] : []];
47789
+ const code = spawnSync3(process.execPath, eslintArgs, { cwd, stdio: "inherit" }).status ?? 1;
47790
+ if (code !== 0) {
47791
+ console.log(` \u2717 lint failed \u2014 ${files.length} file(s) [${label}]`);
47792
+ process.exit(1);
47793
+ }
47794
+ console.log(` \u2713 lint clean \u2014 ${files.length} file(s) [${label}]`);
47795
+ process.exit(0);
47796
+ }
47797
+ if (fix) {
47798
+ console.log(" \xB7 --fix needs eslint \u2014 the baseline check has no autofix.");
47799
+ }
47800
+ const hasTsconfig = existsSync33(join35(cwd, "tsconfig.json"));
47801
+ const tscBin = hasTsconfig ? resolvePackageBin(cwd, "typescript", "bin/tsc") : null;
47802
+ if (tscBin) {
47803
+ const code = spawnSync3(process.execPath, [tscBin, "--noEmit"], { cwd, stdio: "inherit" }).status ?? 1;
47804
+ if (code !== 0) {
47805
+ console.log(` \u2717 lint failed \u2014 ${files.length} file(s) [tsc]`);
47806
+ process.exit(1);
47807
+ }
47808
+ console.log(` \u2713 lint clean \u2014 ${files.length} file(s) [tsc]`);
47809
+ process.exit(0);
47810
+ }
47811
+ const jsFiles = files.filter((f) => JS_EXTENSIONS.some((ext) => f.endsWith(ext)));
47812
+ if (jsFiles.length === 0) {
47813
+ console.log(
47814
+ " lint: no JavaScript files to check \u2014 add tsconfig.json + typescript to type-check .ts files."
47815
+ );
47816
+ process.exit(0);
47817
+ }
47818
+ let syntaxErrors = 0;
47819
+ for (const file of jsFiles) {
47820
+ const result = spawnSync3(process.execPath, ["--check", file], { cwd, encoding: "utf-8" });
47821
+ if ((result.status ?? 1) !== 0) {
47822
+ const stderr = (result.stderr || "").trim();
47823
+ const detail = stderr.split("\n").reverse().find((line) => line.includes("Error:")) || "syntax error";
47824
+ console.log(` \u2717 ${relative11(cwd, file)}: ${detail.trim()}`);
47825
+ syntaxErrors++;
47826
+ }
47827
+ }
47828
+ if (syntaxErrors > 0) {
47829
+ console.log(
47830
+ ` \u2717 lint failed \u2014 ${syntaxErrors} syntax error(s) in ${jsFiles.length} file(s) [node --check]`
47831
+ );
47832
+ process.exit(1);
47833
+ }
47834
+ console.log(` \u2713 lint clean \u2014 ${jsFiles.length} file(s) [node --check]`);
47835
+ process.exit(0);
47836
+ }
47837
+
47513
47838
  // src/bin.ts
47514
47839
  init_generate();
47515
47840
 
47516
47841
  // src/commands/seed.ts
47517
- import { existsSync as existsSync33, readdirSync as readdirSync20 } from "node:fs";
47518
- import { resolve as resolve28, join as join35 } from "node:path";
47842
+ import { existsSync as existsSync34, readdirSync as readdirSync21 } from "node:fs";
47843
+ import { resolve as resolve28, join as join36 } from "node:path";
47519
47844
  import { execSync as execSync4 } from "node:child_process";
47520
47845
  async function runSeeds(seedPath) {
47521
47846
  const cwd = process.cwd();
47522
47847
  const seedDir = resolve28(cwd, "src/seeds");
47523
47848
  if (seedPath) {
47524
47849
  const file = resolve28(seedPath);
47525
- if (!existsSync33(file)) {
47850
+ if (!existsSync34(file)) {
47526
47851
  console.error(` Error: Seed file not found: ${seedPath}`);
47527
47852
  process.exit(1);
47528
47853
  }
@@ -47535,14 +47860,14 @@ async function runSeeds(seedPath) {
47535
47860
  }
47536
47861
  return;
47537
47862
  }
47538
- if (!existsSync33(seedDir)) {
47863
+ if (!existsSync34(seedDir)) {
47539
47864
  console.log(" No seeds directory found.");
47540
47865
  console.log(" Create seed files in src/seeds/ (e.g. src/seeds/001-users.ts)");
47541
47866
  return;
47542
47867
  }
47543
47868
  let seedFiles;
47544
47869
  try {
47545
- seedFiles = readdirSync20(seedDir).filter((f) => f.endsWith(".ts")).sort().map((f) => join35(seedDir, f));
47870
+ seedFiles = readdirSync21(seedDir).filter((f) => f.endsWith(".ts")).sort().map((f) => join36(seedDir, f));
47546
47871
  } catch {
47547
47872
  console.log(" Could not read src/seeds/ directory.");
47548
47873
  return;
@@ -47555,8 +47880,8 @@ async function runSeeds(seedPath) {
47555
47880
  `);
47556
47881
  let failed = false;
47557
47882
  for (const file of seedFiles) {
47558
- const relative11 = file.replace(cwd + "/", "");
47559
- console.log(` Seeding: ${relative11}`);
47883
+ const relative12 = file.replace(cwd + "/", "");
47884
+ console.log(` Seeding: ${relative12}`);
47560
47885
  try {
47561
47886
  execSync4(`npx tsx "${file}"`, { cwd, stdio: "inherit" });
47562
47887
  } catch {
@@ -47573,8 +47898,8 @@ async function runSeeds(seedPath) {
47573
47898
  // src/commands/queue.ts
47574
47899
  init_dotenv();
47575
47900
  init_queue();
47576
- import { readdirSync as readdirSync21, statSync as statSync20 } from "node:fs";
47577
- import { extname as extname8, join as join36 } from "node:path";
47901
+ import { readdirSync as readdirSync22, statSync as statSync21 } from "node:fs";
47902
+ import { extname as extname8, join as join37 } from "node:path";
47578
47903
  import { pathToFileURL as pathToFileURL3 } from "node:url";
47579
47904
  var BOOLEAN_FLAGS = /* @__PURE__ */ new Set(["once", "json"]);
47580
47905
  function parseFlags(args) {
@@ -47605,8 +47930,8 @@ function parseFlags(args) {
47605
47930
  async function resolveQueueHandler(servicesDir, topic) {
47606
47931
  let entries;
47607
47932
  try {
47608
- if (!statSync20(servicesDir).isDirectory()) return null;
47609
- entries = readdirSync21(servicesDir);
47933
+ if (!statSync21(servicesDir).isDirectory()) return null;
47934
+ entries = readdirSync22(servicesDir);
47610
47935
  } catch {
47611
47936
  return null;
47612
47937
  }
@@ -47614,9 +47939,9 @@ async function resolveQueueHandler(servicesDir, topic) {
47614
47939
  if (entry.startsWith("_")) continue;
47615
47940
  const ext = extname8(entry);
47616
47941
  if (ext !== ".ts" && ext !== ".js") continue;
47617
- const fullPath = join36(servicesDir, entry);
47942
+ const fullPath = join37(servicesDir, entry);
47618
47943
  try {
47619
- if (!statSync20(fullPath).isFile()) continue;
47944
+ if (!statSync21(fullPath).isFile()) continue;
47620
47945
  const mod = await import(pathToFileURL3(fullPath).href);
47621
47946
  const config = mod.default ?? mod;
47622
47947
  if (config && typeof config === "object" && config.topic === topic && typeof config.handle === "function") {
@@ -47766,9 +48091,9 @@ async function queueCommand(args = []) {
47766
48091
  }
47767
48092
 
47768
48093
  // src/commands/build.ts
47769
- import { accessSync as accessSync2, constants as constants2, existsSync as existsSync34, statSync as statSync21 } from "node:fs";
47770
- import { basename as basename8, delimiter as delimiter2, join as join37 } from "node:path";
47771
- import { spawnSync as spawnSync3 } from "node:child_process";
48094
+ import { accessSync as accessSync2, constants as constants2, existsSync as existsSync35, statSync as statSync22 } from "node:fs";
48095
+ import { basename as basename8, delimiter as delimiter3, join as join38 } from "node:path";
48096
+ import { spawnSync as spawnSync4 } from "node:child_process";
47772
48097
  function parseFlags2(args) {
47773
48098
  const flags = {};
47774
48099
  let i = 0;
@@ -47793,13 +48118,13 @@ function whichDocker() {
47793
48118
  const pathValue = process.env.PATH || process.env.Path || "";
47794
48119
  if (!pathValue) return null;
47795
48120
  const exts = process.platform === "win32" ? (process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM").split(";") : [""];
47796
- for (const dir of pathValue.split(delimiter2)) {
48121
+ for (const dir of pathValue.split(delimiter3)) {
47797
48122
  if (!dir) continue;
47798
48123
  for (const ext of exts) {
47799
- const candidate = join37(dir, `docker${ext}`);
48124
+ const candidate = join38(dir, `docker${ext}`);
47800
48125
  try {
47801
48126
  accessSync2(candidate, constants2.X_OK);
47802
- if (statSync21(candidate).isFile()) return candidate;
48127
+ if (statSync22(candidate).isFile()) return candidate;
47803
48128
  } catch {
47804
48129
  }
47805
48130
  }
@@ -47814,7 +48139,7 @@ function buildImage(args) {
47814
48139
  tag = `${dirName || "tina4app"}:latest`;
47815
48140
  }
47816
48141
  const dockerfile = typeof flags.file === "string" && flags.file ? flags.file : "Dockerfile";
47817
- if (!existsSync34(dockerfile) || !statSync21(dockerfile).isFile()) {
48142
+ if (!existsSync35(dockerfile) || !statSync22(dockerfile).isFile()) {
47818
48143
  console.log(` \u2717 No ${dockerfile} found.`);
47819
48144
  console.log(" A Tina4 app deploys as a container. Scaffold a Dockerfile first:");
47820
48145
  console.log(" tina4 deploy docker (or: tina4nodejs init)");
@@ -47828,7 +48153,7 @@ function buildImage(args) {
47828
48153
  process.exit(1);
47829
48154
  }
47830
48155
  console.log(` Building image ${tag} from ${dockerfile} ...`);
47831
- const result = spawnSync3(docker, ["build", "-t", tag, "-f", dockerfile, "."], {
48156
+ const result = spawnSync4(docker, ["build", "-t", tag, "-f", dockerfile, "."], {
47832
48157
  stdio: "inherit"
47833
48158
  });
47834
48159
  const code = result.status ?? 1;
@@ -47841,22 +48166,22 @@ function buildImage(args) {
47841
48166
  }
47842
48167
 
47843
48168
  // src/bin.ts
47844
- import { spawnSync as spawnSync4 } from "node:child_process";
47845
- import { existsSync as existsSync35, readFileSync as readFileSync28, statSync as statSync22 } from "node:fs";
47846
- import { delimiter as delimiter3, dirname as dirname16, join as join38 } from "node:path";
48169
+ import { spawnSync as spawnSync5 } from "node:child_process";
48170
+ import { existsSync as existsSync36, readFileSync as readFileSync29, statSync as statSync23 } from "node:fs";
48171
+ import { delimiter as delimiter4, dirname as dirname17, join as join39 } from "node:path";
47847
48172
  import { fileURLToPath as fileURLToPath9, pathToFileURL as pathToFileURL4 } from "node:url";
47848
48173
  function readCliVersion() {
47849
- let dir = dirname16(fileURLToPath9(import.meta.url));
48174
+ let dir = dirname17(fileURLToPath9(import.meta.url));
47850
48175
  for (let i = 0; i < 6; i++) {
47851
- const pkgPath = join38(dir, "package.json");
47852
- if (existsSync35(pkgPath)) {
48176
+ const pkgPath = join39(dir, "package.json");
48177
+ if (existsSync36(pkgPath)) {
47853
48178
  try {
47854
- const pkg = JSON.parse(readFileSync28(pkgPath, "utf-8"));
48179
+ const pkg = JSON.parse(readFileSync29(pkgPath, "utf-8"));
47855
48180
  if (typeof pkg.version === "string" && pkg.version) return pkg.version;
47856
48181
  } catch {
47857
48182
  }
47858
48183
  }
47859
- const parent = dirname16(dir);
48184
+ const parent = dirname17(dir);
47860
48185
  if (parent === dir) break;
47861
48186
  dir = parent;
47862
48187
  }
@@ -48072,6 +48397,13 @@ var COMMANDS = {
48072
48397
  usage: "[file]",
48073
48398
  summary: "Run project tests"
48074
48399
  },
48400
+ lint: {
48401
+ handler: (a) => {
48402
+ runLint(a);
48403
+ },
48404
+ usage: "[--fix] [--no-install]",
48405
+ summary: "Lint the project (eslint, installed dev-only on demand; else tsc/node --check baseline)"
48406
+ },
48075
48407
  queue: {
48076
48408
  handler: async (a) => {
48077
48409
  await queueCommand(a);
@@ -48146,12 +48478,12 @@ var CLIENT_INSTALL_HINT = " Install it: curl -fsSL https://tina4.com/install.s
48146
48478
  function findClient() {
48147
48479
  const windows = process.platform === "win32";
48148
48480
  const names = windows ? [`${CLIENT_BINARY}.exe`, `${CLIENT_BINARY}.cmd`, `${CLIENT_BINARY}.bat`] : [CLIENT_BINARY];
48149
- for (const dir of (process.env.PATH ?? "").split(delimiter3)) {
48481
+ for (const dir of (process.env.PATH ?? "").split(delimiter4)) {
48150
48482
  if (!dir) continue;
48151
48483
  for (const name of names) {
48152
- const candidate = join38(dir, name);
48484
+ const candidate = join39(dir, name);
48153
48485
  try {
48154
- if (statSync22(candidate).isFile()) return candidate;
48486
+ if (statSync23(candidate).isFile()) return candidate;
48155
48487
  } catch {
48156
48488
  }
48157
48489
  }
@@ -48179,7 +48511,7 @@ ${CLIENT_INSTALL_HINT}
48179
48511
  );
48180
48512
  return EXIT_CLIENT_UNAVAILABLE;
48181
48513
  }
48182
- const result = spawnSync4(client, [command, ...args], {
48514
+ const result = spawnSync5(client, [command, ...args], {
48183
48515
  stdio: "inherit",
48184
48516
  env: { ...process.env, [DELEGATION_GUARD_ENV]: command }
48185
48517
  });