@palbase/backend 24.0.1 → 24.1.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/bin/palbase-backend.cjs +75 -18
- package/dist/bin/palbase-backend.cjs.map +1 -1
- package/dist/bin/palbase-backend.js +2 -2
- package/dist/{chunk-T5IOSOE5.js → chunk-ERDL5VAE.js} +2 -2
- package/dist/{chunk-YSQBC2VL.js → chunk-HPUSV4AZ.js} +71 -20
- package/dist/chunk-HPUSV4AZ.js.map +1 -0
- package/dist/{chunk-H3JAISUY.js → chunk-UWSYTUGM.js} +11 -1
- package/dist/{chunk-H3JAISUY.js.map → chunk-UWSYTUGM.js.map} +1 -1
- package/dist/db/index.d.cts +2 -2
- package/dist/db/index.d.ts +2 -2
- package/dist/engine/index.cjs +75 -18
- package/dist/engine/index.cjs.map +1 -1
- package/dist/engine/index.d.cts +4 -4
- package/dist/engine/index.d.ts +4 -4
- package/dist/engine/index.js +2 -2
- package/dist/{index-BOS_rFBO.d.ts → index-ByBMibIJ.d.ts} +1 -1
- package/dist/{index-dJNhDZ7j.d.ts → index-C0PMn5jl.d.ts} +3 -3
- package/dist/{index-MoQ31B6M.d.cts → index-D4rts8T7.d.cts} +1 -1
- package/dist/{index-C84bLgeO.d.cts → index-DAwHMppB.d.cts} +3 -3
- package/dist/index.cjs +8 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -9
- package/dist/index.d.ts +23 -9
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/openapi/index.cjs.map +1 -1
- package/dist/openapi/index.d.cts +2 -2
- package/dist/openapi/index.d.ts +2 -2
- package/dist/openapi/index.js +2 -2
- package/dist/{registry-CEod_5sz.d.ts → registry-B8pld3fj.d.ts} +1 -1
- package/dist/{registry-1X-skBNu.d.cts → registry-CgJvDYUW.d.cts} +1 -1
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.d.cts +1 -1
- package/dist/test/index.d.ts +1 -1
- package/dist/test/index.js.map +1 -1
- package/docs/README.md +5 -1
- package/docs/llms-full.txt +5 -1
- package/package.json +1 -1
- package/template/AGENTS.md +34 -22
- package/template/tsconfig.json +6 -0
- package/dist/chunk-YSQBC2VL.js.map +0 -1
- package/dist/{chunk-T5IOSOE5.js.map → chunk-ERDL5VAE.js.map} +0 -0
- package/dist/{endpoint-CcQ1a36a.d.cts → endpoint-BSGw1pTu.d.cts} +16 -16
- package/dist/{endpoint-0_DGBajf.d.ts → endpoint-DMwJjEHQ.d.ts} +16 -16
|
@@ -635,6 +635,14 @@ var Realtime = makeServiceProxy("Realtime");
|
|
|
635
635
|
|
|
636
636
|
// src/errors.ts
|
|
637
637
|
var HTTP_ERROR_BRAND = /* @__PURE__ */ Symbol.for("palbase.backend.httpError");
|
|
638
|
+
var ENGINE_RAISED = /* @__PURE__ */ Symbol.for("palbase.backend.engineRaised");
|
|
639
|
+
function markEngineRaised(e) {
|
|
640
|
+
e[ENGINE_RAISED] = true;
|
|
641
|
+
return e;
|
|
642
|
+
}
|
|
643
|
+
function isEngineRaised(e) {
|
|
644
|
+
return typeof e === "object" && e !== null && e[ENGINE_RAISED] === true;
|
|
645
|
+
}
|
|
638
646
|
function isHttpError(err) {
|
|
639
647
|
if (typeof err !== "object" || err === null) return false;
|
|
640
648
|
const e = err;
|
|
@@ -1156,7 +1164,14 @@ function asTableRows(table, rows) {
|
|
|
1156
1164
|
const transforms = transformsOf(currentSchema, table);
|
|
1157
1165
|
return rows.map((row) => applyFromDb(reviveVectors(asWireRow(row), vectorCols), transforms));
|
|
1158
1166
|
}
|
|
1159
|
-
function asBindParams(table, cols, data) {
|
|
1167
|
+
function asBindParams(table, cols, data, caller) {
|
|
1168
|
+
for (const c of cols) {
|
|
1169
|
+
if (data[c] === void 0) {
|
|
1170
|
+
throw new Error(
|
|
1171
|
+
`${caller}(${table}): "${c}" de\u011Feri undefined \u2014 bu bir yazma de\u011Feri de\u011Fil. Kolonu bo\u015Faltmak istiyorsan null yaz; kolonu de\u011Fi\u015Ftirmek istemiyorsan nesneye hi\xE7 koyma (bir eksik istek alan\u0131 sessizce NULL yaz\u0131yordu \u2014 FR-016).`
|
|
1172
|
+
);
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1160
1175
|
const vectorCols = vectorColumnsOf(currentSchema, table);
|
|
1161
1176
|
const transforms = transformsOf(currentSchema, table);
|
|
1162
1177
|
return cols.map((c) => {
|
|
@@ -1383,23 +1398,49 @@ function compileWhere(table, colSet, where, add, caller = "search") {
|
|
|
1383
1398
|
if (colSet !== null && !colSet.has(col)) {
|
|
1384
1399
|
throw new Error(`${caller}(${table}): where kolonu "${col}" tabloda yok (FR-016)`);
|
|
1385
1400
|
}
|
|
1401
|
+
if (cond === void 0) {
|
|
1402
|
+
throw new Error(
|
|
1403
|
+
`${caller}(${table}): where.${col} de\u011Feri undefined \u2014 bu bir filtre de\u011Feri de\u011Fil. Ba\u011Flan\u0131nca NULL olur ve '= NULL' hi\xE7bir sat\u0131ra uymaz, yani sorgu sessizce bo\u015F sonu\xE7 d\xF6nerdi. De\u011Fer yoksa anahtar\u0131 filtreye hi\xE7 koymay\u0131n.`
|
|
1404
|
+
);
|
|
1405
|
+
}
|
|
1386
1406
|
const q = `t.${quoteIdent(col)}`;
|
|
1387
1407
|
const bind = bindFor(col);
|
|
1388
1408
|
if (cond !== null && typeof cond === "object" && !Array.isArray(cond)) {
|
|
1409
|
+
if (Object.keys(cond).length === 0) {
|
|
1410
|
+
throw new Error(
|
|
1411
|
+
`${caller}(${table}): where.${col} bo\u015F bir operat\xF6r nesnesi ({}) \u2014 hi\xE7bir ko\u015Ful \xFCretmez, yani bu alan filtreden sessizce D\xDC\u015EERD\u0130. Ko\u015Ful kurulmayacaksa anahtar\u0131 filtreye hi\xE7 koymay\u0131n (D-21).`
|
|
1412
|
+
);
|
|
1413
|
+
}
|
|
1389
1414
|
for (const [op, v] of Object.entries(cond)) {
|
|
1390
1415
|
if (op === "in") {
|
|
1391
1416
|
if (!Array.isArray(v)) throw new Error(`${caller}(${table}): where.${col}.in bir dizi olmal\u0131`);
|
|
1417
|
+
if (v.some((x) => x === void 0)) {
|
|
1418
|
+
throw new Error(
|
|
1419
|
+
`${caller}(${table}): where.${col}.in listesinde undefined var \u2014 sessizce NULL'a ba\u011Flan\u0131r ve o eleman hi\xE7bir sat\u0131rla e\u015Fle\u015Fmez. Listeyi kurarken eleyin.`
|
|
1420
|
+
);
|
|
1421
|
+
}
|
|
1392
1422
|
if (v.length === 0) {
|
|
1393
1423
|
parts.push("false");
|
|
1394
1424
|
continue;
|
|
1395
1425
|
}
|
|
1396
1426
|
parts.push(`${q} IN (${v.map((x) => bind(x)).join(", ")})`);
|
|
1397
1427
|
} else if (op in WHERE_OPS) {
|
|
1428
|
+
if (v === void 0) {
|
|
1429
|
+
throw new Error(
|
|
1430
|
+
`${caller}(${table}): where.${col}.${op} de\u011Feri undefined \u2014 kar\u015F\u0131la\u015Ft\u0131rman\u0131n sa\u011F taraf\u0131 NULL olur ve sonu\xE7 hi\xE7bir sat\u0131ra uymaz. Ko\u015Fulu kurmay\u0131n.`
|
|
1431
|
+
);
|
|
1432
|
+
}
|
|
1433
|
+
if (v === null && (op === "neq" || op === "eq")) {
|
|
1434
|
+
parts.push(`${q} IS ${op === "neq" ? "NOT " : ""}NULL`);
|
|
1435
|
+
continue;
|
|
1436
|
+
}
|
|
1398
1437
|
parts.push(`${q} ${WHERE_OPS[op]} ${bind(v)}`);
|
|
1399
1438
|
} else {
|
|
1400
1439
|
throw new Error(`${caller}(${table}): where.${col} bilinmeyen operat\xF6r "${op}" (gt/gte/lt/lte/neq/in)`);
|
|
1401
1440
|
}
|
|
1402
1441
|
}
|
|
1442
|
+
} else if (cond === null) {
|
|
1443
|
+
parts.push(`${q} IS NULL`);
|
|
1403
1444
|
} else {
|
|
1404
1445
|
parts.push(`${q} = ${bind(cond)}`);
|
|
1405
1446
|
}
|
|
@@ -1492,7 +1533,7 @@ function createOps(tx) {
|
|
|
1492
1533
|
if (cols.length === 0) throw new Error(`insert into ${table}: no columns given`);
|
|
1493
1534
|
const placeholders = cols.map((_, i) => `$${i + 1}`).join(", ");
|
|
1494
1535
|
const sql = `INSERT INTO ${quoteIdent(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${placeholders}) RETURNING *`;
|
|
1495
|
-
const rows = await (await at()).unsafe(sql, asBindParams(table, cols, data));
|
|
1536
|
+
const rows = await (await at()).unsafe(sql, asBindParams(table, cols, data, "insert"));
|
|
1496
1537
|
const inserted = rows[0];
|
|
1497
1538
|
if (!inserted) {
|
|
1498
1539
|
throw new Error(
|
|
@@ -1526,7 +1567,7 @@ function createOps(tx) {
|
|
|
1526
1567
|
const ph = cols.map((_, i) => `$${i + 1}`).join(", ");
|
|
1527
1568
|
const insertSql = `INSERT INTO ${quoteIdent(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${ph}) ON CONFLICT (${conflict.map(quoteIdent).join(", ")}) WHERE "valid_to" IS NULL DO NOTHING RETURNING *`;
|
|
1528
1569
|
const live = await at();
|
|
1529
|
-
const bindData = asBindParams(table, cols, data);
|
|
1570
|
+
const bindData = asBindParams(table, cols, data, "upsert");
|
|
1530
1571
|
const first = await live.unsafe(insertSql, bindData);
|
|
1531
1572
|
if (first[0]) return asTableRow(table, first[0]);
|
|
1532
1573
|
const condSql = conflict.map((c, i) => `${quoteIdent(c)} = $${i + 1}`).join(" AND ");
|
|
@@ -1560,7 +1601,7 @@ function createOps(tx) {
|
|
|
1560
1601
|
const assignments = cols.filter((c) => !conflictSet.has(c)).map((c) => `${quoteIdent(c)} = EXCLUDED.${quoteIdent(c)}`);
|
|
1561
1602
|
const action = assignments.length ? `DO UPDATE SET ${assignments.join(", ")}` : `DO UPDATE SET ${quoteIdent(conflict[0])} = EXCLUDED.${quoteIdent(conflict[0])}`;
|
|
1562
1603
|
const sql = `INSERT INTO ${quoteIdent(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${placeholders}) ON CONFLICT (${conflict.map(quoteIdent).join(", ")}) ${action} RETURNING *`;
|
|
1563
|
-
const rows = await (await at()).unsafe(sql, asBindParams(table, cols, data));
|
|
1604
|
+
const rows = await (await at()).unsafe(sql, asBindParams(table, cols, data, "upsert"));
|
|
1564
1605
|
const row = rows[0];
|
|
1565
1606
|
if (!row) {
|
|
1566
1607
|
throw new Error(
|
|
@@ -1574,7 +1615,7 @@ function createOps(tx) {
|
|
|
1574
1615
|
if (cols.length === 0) return ops.findById(table, id);
|
|
1575
1616
|
const assignments = cols.map((c, i) => `${quoteIdent(c)} = $${i + 1}`).join(", ");
|
|
1576
1617
|
const sql = `UPDATE ${quoteIdent(table)} SET ${assignments} WHERE id = $${cols.length + 1} RETURNING *`;
|
|
1577
|
-
const rows = await (await at()).unsafe(sql, [...asBindParams(table, cols, data), id]);
|
|
1618
|
+
const rows = await (await at()).unsafe(sql, [...asBindParams(table, cols, data, "update"), id]);
|
|
1578
1619
|
return rows[0] ? asTableRow(table, rows[0]) : null;
|
|
1579
1620
|
},
|
|
1580
1621
|
async delete(table, id) {
|
|
@@ -1605,13 +1646,20 @@ function createOps(tx) {
|
|
|
1605
1646
|
`updateMany(${table}): nothing to set. An update with no columns is not a no-op worth pretending happened \u2014 pass the columns to write.`
|
|
1606
1647
|
);
|
|
1607
1648
|
}
|
|
1649
|
+
const known = schemaColumns(table);
|
|
1650
|
+
if (known !== null) {
|
|
1651
|
+
for (const c of cols) {
|
|
1652
|
+
if (!known.has(c)) {
|
|
1653
|
+
throw new Error(`updateMany(${table}): set kolonu "${c}" tabloda yok (FR-016)`);
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1608
1657
|
const params = [];
|
|
1609
1658
|
const add = (v) => {
|
|
1610
1659
|
params.push(v);
|
|
1611
1660
|
return `$${params.length}`;
|
|
1612
1661
|
};
|
|
1613
|
-
const assignments = cols.map((c) => `${quoteIdent(c)} = ${add(asBindParams(table, [c], set)[0])}`).join(", ");
|
|
1614
|
-
const known = schemaColumns(table);
|
|
1662
|
+
const assignments = cols.map((c) => `${quoteIdent(c)} = ${add(asBindParams(table, [c], set, "updateMany")[0])}`).join(", ");
|
|
1615
1663
|
const whereSql = compileWhere(table, known, where, add, "updateMany");
|
|
1616
1664
|
assertHasPredicate(whereSql, "updateMany", table);
|
|
1617
1665
|
const sql = `UPDATE ${quoteIdent(table)} AS t SET ${assignments} WHERE true${whereSql} RETURNING *`;
|
|
@@ -2083,7 +2131,7 @@ function createOps(tx) {
|
|
|
2083
2131
|
const placeholders = cols.map((_, i) => `$${i + 1}`).join(", ");
|
|
2084
2132
|
const rows = await sp.unsafe(
|
|
2085
2133
|
`INSERT INTO ${quoteIdent(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${placeholders}) RETURNING *`,
|
|
2086
|
-
asBindParams(table, cols, data)
|
|
2134
|
+
asBindParams(table, cols, data, "supersede")
|
|
2087
2135
|
);
|
|
2088
2136
|
if (!rows[0]) {
|
|
2089
2137
|
throw new Error(
|
|
@@ -2223,7 +2271,7 @@ function diagnosingDriver(sql, surface = "service") {
|
|
|
2223
2271
|
);
|
|
2224
2272
|
}
|
|
2225
2273
|
if (isUniqueViolation(e)) {
|
|
2226
|
-
return new UniqueViolation(constraintOf(e));
|
|
2274
|
+
return markEngineRaised(new UniqueViolation(constraintOf(e)));
|
|
2227
2275
|
}
|
|
2228
2276
|
if (surface === "service" && isForeignKeyViolation(e)) {
|
|
2229
2277
|
return new Error(
|
|
@@ -2295,7 +2343,7 @@ function isRef(v) {
|
|
|
2295
2343
|
function isExpr(v) {
|
|
2296
2344
|
return typeof v === "object" && v !== null && "$expr" in v;
|
|
2297
2345
|
}
|
|
2298
|
-
function renderValue(value, column, args, results, vectorCols) {
|
|
2346
|
+
function renderValue(value, column, args, results, vectorCols, transforms) {
|
|
2299
2347
|
if (isRef(value)) {
|
|
2300
2348
|
const source = results[value.$ref.op];
|
|
2301
2349
|
const row = source?.rows[0];
|
|
@@ -2304,15 +2352,15 @@ function renderValue(value, column, args, results, vectorCols) {
|
|
|
2304
2352
|
error_code: "tx_ref_unresolved"
|
|
2305
2353
|
});
|
|
2306
2354
|
}
|
|
2307
|
-
return bindMaybeVector(args, column, vectorCols, row[value.$ref.field]);
|
|
2355
|
+
return bindMaybeVector(args, column, vectorCols, row[value.$ref.field], transforms);
|
|
2308
2356
|
}
|
|
2309
2357
|
if (isExpr(value)) {
|
|
2310
2358
|
const fn = value.$expr;
|
|
2311
2359
|
if (fn.fn === "now") return "now()";
|
|
2312
2360
|
const operator = fn.fn === "inc" ? "+" : "-";
|
|
2313
|
-
return `${quoteIdent(column)} ${operator} ${bindMaybeVector(args, column, vectorCols, fn.by)}`;
|
|
2361
|
+
return `${quoteIdent(column)} ${operator} ${bindMaybeVector(args, column, vectorCols, fn.by, transforms)}`;
|
|
2314
2362
|
}
|
|
2315
|
-
return bindMaybeVector(args, column, vectorCols, value);
|
|
2363
|
+
return bindMaybeVector(args, column, vectorCols, value, transforms);
|
|
2316
2364
|
}
|
|
2317
2365
|
function renderWhere(where, args, results) {
|
|
2318
2366
|
const cols = Object.keys(where ?? {});
|
|
@@ -2324,21 +2372,26 @@ function renderWhere(where, args, results) {
|
|
|
2324
2372
|
});
|
|
2325
2373
|
return ` WHERE ${terms.join(" AND ")}`;
|
|
2326
2374
|
}
|
|
2327
|
-
function bindMaybeVector(args, column, vectorCols, value) {
|
|
2375
|
+
function bindMaybeVector(args, column, vectorCols, value, transforms) {
|
|
2328
2376
|
if (column !== void 0 && vectorCols?.has(column) && Array.isArray(value)) {
|
|
2329
2377
|
return args.bind(toVectorLiteral(value));
|
|
2330
2378
|
}
|
|
2379
|
+
const t = column !== void 0 ? transforms?.get(column) : void 0;
|
|
2380
|
+
if (t?.toDb !== void 0 && value !== null && value !== void 0) {
|
|
2381
|
+
return args.bind(t.toDb(value));
|
|
2382
|
+
}
|
|
2331
2383
|
return args.bind(value);
|
|
2332
2384
|
}
|
|
2333
2385
|
async function runPlanOp(sp, op, results) {
|
|
2334
2386
|
const opVectorCols = vectorColumnsOf(currentSchema, op.table);
|
|
2387
|
+
const opTransforms = transformsOf(currentSchema, op.table);
|
|
2335
2388
|
const args = new Args();
|
|
2336
2389
|
const table = quoteIdent(op.table);
|
|
2337
2390
|
let sql;
|
|
2338
2391
|
switch (op.op) {
|
|
2339
2392
|
case "insert": {
|
|
2340
2393
|
const cols = Object.keys(op.values ?? {});
|
|
2341
|
-
const rendered = cols.map((c) => renderValue(op.values[c], c, args, results, opVectorCols));
|
|
2394
|
+
const rendered = cols.map((c) => renderValue(op.values[c], c, args, results, opVectorCols, opTransforms));
|
|
2342
2395
|
sql = cols.length ? `INSERT INTO ${table} (${cols.map(quoteIdent).join(", ")}) VALUES (${rendered.join(", ")}) RETURNING *` : `INSERT INTO ${table} DEFAULT VALUES RETURNING *`;
|
|
2343
2396
|
break;
|
|
2344
2397
|
}
|
|
@@ -2351,7 +2404,7 @@ async function runPlanOp(sp, op, results) {
|
|
|
2351
2404
|
});
|
|
2352
2405
|
}
|
|
2353
2406
|
const rendered = cols.map(
|
|
2354
|
-
(c) => renderValue(op.values[c], c, args, results, opVectorCols)
|
|
2407
|
+
(c) => renderValue(op.values[c], c, args, results, opVectorCols, opTransforms)
|
|
2355
2408
|
);
|
|
2356
2409
|
sql = `INSERT INTO ${table} (${cols.map(quoteIdent).join(", ")}) VALUES (${rendered.join(", ")}) ${onConflictTail(cols, conflict, "update")} RETURNING *`;
|
|
2357
2410
|
break;
|
|
@@ -2361,7 +2414,7 @@ async function runPlanOp(sp, op, results) {
|
|
|
2361
2414
|
if (rows.length === 0 || !rows[0]) return [];
|
|
2362
2415
|
const cols = Object.keys(rows[0]);
|
|
2363
2416
|
const tuples = rows.map(
|
|
2364
|
-
(r) => `(${cols.map((c) => renderValue(r[c], c, args, results, opVectorCols)).join(", ")})`
|
|
2417
|
+
(r) => `(${cols.map((c) => renderValue(r[c], c, args, results, opVectorCols, opTransforms)).join(", ")})`
|
|
2365
2418
|
);
|
|
2366
2419
|
const conflictCols = op.onConflict ?? [];
|
|
2367
2420
|
const tail = op.action !== void 0 && conflictCols.length > 0 ? ` ${onConflictTail(cols, conflictCols, op.action)}` : "";
|
|
@@ -2372,7 +2425,7 @@ async function runPlanOp(sp, op, results) {
|
|
|
2372
2425
|
const cols = Object.keys(op.set ?? {});
|
|
2373
2426
|
if (cols.length === 0) throw new Error(`update ${op.table}: nothing to set`);
|
|
2374
2427
|
const assignments = cols.map(
|
|
2375
|
-
(c) => `${quoteIdent(c)} = ${renderValue(op.set[c], c, args, results, opVectorCols)}`
|
|
2428
|
+
(c) => `${quoteIdent(c)} = ${renderValue(op.set[c], c, args, results, opVectorCols, opTransforms)}`
|
|
2376
2429
|
);
|
|
2377
2430
|
sql = `UPDATE ${table} SET ${assignments.join(", ")}${renderWhere(op.where, args, results)} RETURNING *`;
|
|
2378
2431
|
break;
|
|
@@ -2674,6 +2727,7 @@ async function defaultSqlDriver(config) {
|
|
|
2674
2727
|
}
|
|
2675
2728
|
return new g.Bun.SQL({ url: config.databaseUrl, max: config.poolMax });
|
|
2676
2729
|
}
|
|
2730
|
+
var AUTHOR_ANSWERED = /* @__PURE__ */ new Set([400, 401, 403, 404, 409, 429]);
|
|
2677
2731
|
async function createApp(opts) {
|
|
2678
2732
|
const { config, controllers } = opts;
|
|
2679
2733
|
setSchema(opts.schema ?? {});
|
|
@@ -3059,6 +3113,9 @@ async function createApp(opts) {
|
|
|
3059
3113
|
} catch (err) {
|
|
3060
3114
|
await db.rollback(err);
|
|
3061
3115
|
if (isHttpError(err)) {
|
|
3116
|
+
if (isEngineRaised(err) || !AUTHOR_ANSWERED.has(err.status)) {
|
|
3117
|
+
log.error(`[engine] unhandled ${err.error} in ${hit.entry.id}`, err);
|
|
3118
|
+
}
|
|
3062
3119
|
return envelope(
|
|
3063
3120
|
err.error,
|
|
3064
3121
|
err.errorDescription,
|