@palbase/backend 24.0.2 → 24.1.1
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 +86 -9
- package/dist/bin/palbase-backend.cjs.map +1 -1
- package/dist/bin/palbase-backend.js +3 -2
- package/dist/bin/palbase-backend.js.map +1 -1
- package/dist/{chunk-RPZNHY7J.js → chunk-2A62DDVO.js} +36 -11
- package/dist/chunk-2A62DDVO.js.map +1 -0
- package/dist/{chunk-T5IOSOE5.js → chunk-ERDL5VAE.js} +2 -2
- package/dist/{chunk-H3JAISUY.js → chunk-UWSYTUGM.js} +11 -1
- package/dist/{chunk-H3JAISUY.js.map → chunk-UWSYTUGM.js.map} +1 -1
- package/dist/chunk-XABBC7JP.js +55 -0
- package/dist/chunk-XABBC7JP.js.map +1 -0
- package/dist/db/index.d.cts +2 -2
- package/dist/db/index.d.ts +2 -2
- package/dist/engine/index.cjs +86 -9
- 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 +3 -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 +58 -0
- 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 +12 -0
- 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/dist/chunk-RPZNHY7J.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;
|
|
@@ -1029,6 +1037,56 @@ function makeMemoryCache(opts = {}) {
|
|
|
1029
1037
|
};
|
|
1030
1038
|
}
|
|
1031
1039
|
|
|
1040
|
+
// src/db/input-guards.ts
|
|
1041
|
+
var KNOWN_OPS = /* @__PURE__ */ new Set(["gt", "gte", "lt", "lte", "neq", "eq", "in"]);
|
|
1042
|
+
function assertUsableFilter(caller, table, where) {
|
|
1043
|
+
if (!where) return;
|
|
1044
|
+
for (const [col, cond] of Object.entries(where)) {
|
|
1045
|
+
if (cond === void 0) {
|
|
1046
|
+
throw new Error(
|
|
1047
|
+
`${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.`
|
|
1048
|
+
);
|
|
1049
|
+
}
|
|
1050
|
+
if (cond === null || typeof cond !== "object" || Array.isArray(cond)) continue;
|
|
1051
|
+
const entries = Object.entries(cond);
|
|
1052
|
+
if (entries.length === 0) {
|
|
1053
|
+
throw new Error(
|
|
1054
|
+
`${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).`
|
|
1055
|
+
);
|
|
1056
|
+
}
|
|
1057
|
+
for (const [op, v] of entries) {
|
|
1058
|
+
if (op === "in") {
|
|
1059
|
+
if (!Array.isArray(v)) throw new Error(`${caller}(${table}): where.${col}.in bir dizi olmal\u0131`);
|
|
1060
|
+
if (v.some((x) => x === void 0)) {
|
|
1061
|
+
throw new Error(
|
|
1062
|
+
`${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.`
|
|
1063
|
+
);
|
|
1064
|
+
}
|
|
1065
|
+
continue;
|
|
1066
|
+
}
|
|
1067
|
+
if (!KNOWN_OPS.has(op)) {
|
|
1068
|
+
throw new Error(
|
|
1069
|
+
`${caller}(${table}): where.${col} bilinmeyen operat\xF6r "${op}" (gt/gte/lt/lte/neq/in)`
|
|
1070
|
+
);
|
|
1071
|
+
}
|
|
1072
|
+
if (v === void 0) {
|
|
1073
|
+
throw new Error(
|
|
1074
|
+
`${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.`
|
|
1075
|
+
);
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
function assertUsableWriteValues(caller, table, cols, data) {
|
|
1081
|
+
for (const c of cols) {
|
|
1082
|
+
if (data[c] === void 0) {
|
|
1083
|
+
throw new Error(
|
|
1084
|
+
`${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).`
|
|
1085
|
+
);
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1032
1090
|
// src/engine/db.ts
|
|
1033
1091
|
function quoteIdent(name) {
|
|
1034
1092
|
return `"${name.replace(/"/g, '""')}"`;
|
|
@@ -1156,7 +1214,8 @@ function asTableRows(table, rows) {
|
|
|
1156
1214
|
const transforms = transformsOf(currentSchema, table);
|
|
1157
1215
|
return rows.map((row) => applyFromDb(reviveVectors(asWireRow(row), vectorCols), transforms));
|
|
1158
1216
|
}
|
|
1159
|
-
function asBindParams(table, cols, data) {
|
|
1217
|
+
function asBindParams(table, cols, data, caller) {
|
|
1218
|
+
assertUsableWriteValues(caller, table, cols, data);
|
|
1160
1219
|
const vectorCols = vectorColumnsOf(currentSchema, table);
|
|
1161
1220
|
const transforms = transformsOf(currentSchema, table);
|
|
1162
1221
|
return cols.map((c) => {
|
|
@@ -1379,6 +1438,7 @@ function compileWhere(table, colSet, where, add, caller = "search") {
|
|
|
1379
1438
|
const t = transforms.get(col);
|
|
1380
1439
|
return t?.toDb === void 0 ? add : (v) => add(v === null || v === void 0 ? v : t.toDb(v));
|
|
1381
1440
|
};
|
|
1441
|
+
assertUsableFilter(caller, table, where);
|
|
1382
1442
|
for (const [col, cond] of Object.entries(where)) {
|
|
1383
1443
|
if (colSet !== null && !colSet.has(col)) {
|
|
1384
1444
|
throw new Error(`${caller}(${table}): where kolonu "${col}" tabloda yok (FR-016)`);
|
|
@@ -1395,11 +1455,17 @@ function compileWhere(table, colSet, where, add, caller = "search") {
|
|
|
1395
1455
|
}
|
|
1396
1456
|
parts.push(`${q} IN (${v.map((x) => bind(x)).join(", ")})`);
|
|
1397
1457
|
} else if (op in WHERE_OPS) {
|
|
1458
|
+
if (v === null && (op === "neq" || op === "eq")) {
|
|
1459
|
+
parts.push(`${q} IS ${op === "neq" ? "NOT " : ""}NULL`);
|
|
1460
|
+
continue;
|
|
1461
|
+
}
|
|
1398
1462
|
parts.push(`${q} ${WHERE_OPS[op]} ${bind(v)}`);
|
|
1399
1463
|
} else {
|
|
1400
1464
|
throw new Error(`${caller}(${table}): where.${col} bilinmeyen operat\xF6r "${op}" (gt/gte/lt/lte/neq/in)`);
|
|
1401
1465
|
}
|
|
1402
1466
|
}
|
|
1467
|
+
} else if (cond === null) {
|
|
1468
|
+
parts.push(`${q} IS NULL`);
|
|
1403
1469
|
} else {
|
|
1404
1470
|
parts.push(`${q} = ${bind(cond)}`);
|
|
1405
1471
|
}
|
|
@@ -1492,7 +1558,7 @@ function createOps(tx) {
|
|
|
1492
1558
|
if (cols.length === 0) throw new Error(`insert into ${table}: no columns given`);
|
|
1493
1559
|
const placeholders = cols.map((_, i) => `$${i + 1}`).join(", ");
|
|
1494
1560
|
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));
|
|
1561
|
+
const rows = await (await at()).unsafe(sql, asBindParams(table, cols, data, "insert"));
|
|
1496
1562
|
const inserted = rows[0];
|
|
1497
1563
|
if (!inserted) {
|
|
1498
1564
|
throw new Error(
|
|
@@ -1526,7 +1592,7 @@ function createOps(tx) {
|
|
|
1526
1592
|
const ph = cols.map((_, i) => `$${i + 1}`).join(", ");
|
|
1527
1593
|
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
1594
|
const live = await at();
|
|
1529
|
-
const bindData = asBindParams(table, cols, data);
|
|
1595
|
+
const bindData = asBindParams(table, cols, data, "upsert");
|
|
1530
1596
|
const first = await live.unsafe(insertSql, bindData);
|
|
1531
1597
|
if (first[0]) return asTableRow(table, first[0]);
|
|
1532
1598
|
const condSql = conflict.map((c, i) => `${quoteIdent(c)} = $${i + 1}`).join(" AND ");
|
|
@@ -1560,7 +1626,7 @@ function createOps(tx) {
|
|
|
1560
1626
|
const assignments = cols.filter((c) => !conflictSet.has(c)).map((c) => `${quoteIdent(c)} = EXCLUDED.${quoteIdent(c)}`);
|
|
1561
1627
|
const action = assignments.length ? `DO UPDATE SET ${assignments.join(", ")}` : `DO UPDATE SET ${quoteIdent(conflict[0])} = EXCLUDED.${quoteIdent(conflict[0])}`;
|
|
1562
1628
|
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));
|
|
1629
|
+
const rows = await (await at()).unsafe(sql, asBindParams(table, cols, data, "upsert"));
|
|
1564
1630
|
const row = rows[0];
|
|
1565
1631
|
if (!row) {
|
|
1566
1632
|
throw new Error(
|
|
@@ -1574,7 +1640,7 @@ function createOps(tx) {
|
|
|
1574
1640
|
if (cols.length === 0) return ops.findById(table, id);
|
|
1575
1641
|
const assignments = cols.map((c, i) => `${quoteIdent(c)} = $${i + 1}`).join(", ");
|
|
1576
1642
|
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]);
|
|
1643
|
+
const rows = await (await at()).unsafe(sql, [...asBindParams(table, cols, data, "update"), id]);
|
|
1578
1644
|
return rows[0] ? asTableRow(table, rows[0]) : null;
|
|
1579
1645
|
},
|
|
1580
1646
|
async delete(table, id) {
|
|
@@ -1605,13 +1671,20 @@ function createOps(tx) {
|
|
|
1605
1671
|
`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
1672
|
);
|
|
1607
1673
|
}
|
|
1674
|
+
const known = schemaColumns(table);
|
|
1675
|
+
if (known !== null) {
|
|
1676
|
+
for (const c of cols) {
|
|
1677
|
+
if (!known.has(c)) {
|
|
1678
|
+
throw new Error(`updateMany(${table}): set kolonu "${c}" tabloda yok (FR-016)`);
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1608
1682
|
const params = [];
|
|
1609
1683
|
const add = (v) => {
|
|
1610
1684
|
params.push(v);
|
|
1611
1685
|
return `$${params.length}`;
|
|
1612
1686
|
};
|
|
1613
|
-
const assignments = cols.map((c) => `${quoteIdent(c)} = ${add(asBindParams(table, [c], set)[0])}`).join(", ");
|
|
1614
|
-
const known = schemaColumns(table);
|
|
1687
|
+
const assignments = cols.map((c) => `${quoteIdent(c)} = ${add(asBindParams(table, [c], set, "updateMany")[0])}`).join(", ");
|
|
1615
1688
|
const whereSql = compileWhere(table, known, where, add, "updateMany");
|
|
1616
1689
|
assertHasPredicate(whereSql, "updateMany", table);
|
|
1617
1690
|
const sql = `UPDATE ${quoteIdent(table)} AS t SET ${assignments} WHERE true${whereSql} RETURNING *`;
|
|
@@ -2083,7 +2156,7 @@ function createOps(tx) {
|
|
|
2083
2156
|
const placeholders = cols.map((_, i) => `$${i + 1}`).join(", ");
|
|
2084
2157
|
const rows = await sp.unsafe(
|
|
2085
2158
|
`INSERT INTO ${quoteIdent(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${placeholders}) RETURNING *`,
|
|
2086
|
-
asBindParams(table, cols, data)
|
|
2159
|
+
asBindParams(table, cols, data, "supersede")
|
|
2087
2160
|
);
|
|
2088
2161
|
if (!rows[0]) {
|
|
2089
2162
|
throw new Error(
|
|
@@ -2223,7 +2296,7 @@ function diagnosingDriver(sql, surface = "service") {
|
|
|
2223
2296
|
);
|
|
2224
2297
|
}
|
|
2225
2298
|
if (isUniqueViolation(e)) {
|
|
2226
|
-
return new UniqueViolation(constraintOf(e));
|
|
2299
|
+
return markEngineRaised(new UniqueViolation(constraintOf(e)));
|
|
2227
2300
|
}
|
|
2228
2301
|
if (surface === "service" && isForeignKeyViolation(e)) {
|
|
2229
2302
|
return new Error(
|
|
@@ -2679,6 +2752,7 @@ async function defaultSqlDriver(config) {
|
|
|
2679
2752
|
}
|
|
2680
2753
|
return new g.Bun.SQL({ url: config.databaseUrl, max: config.poolMax });
|
|
2681
2754
|
}
|
|
2755
|
+
var AUTHOR_ANSWERED = /* @__PURE__ */ new Set([400, 401, 403, 404, 409, 429]);
|
|
2682
2756
|
async function createApp(opts) {
|
|
2683
2757
|
const { config, controllers } = opts;
|
|
2684
2758
|
setSchema(opts.schema ?? {});
|
|
@@ -3064,6 +3138,9 @@ async function createApp(opts) {
|
|
|
3064
3138
|
} catch (err) {
|
|
3065
3139
|
await db.rollback(err);
|
|
3066
3140
|
if (isHttpError(err)) {
|
|
3141
|
+
if (isEngineRaised(err) || !AUTHOR_ANSWERED.has(err.status)) {
|
|
3142
|
+
log.error(`[engine] unhandled ${err.error} in ${hit.entry.id}`, err);
|
|
3143
|
+
}
|
|
3067
3144
|
return envelope(
|
|
3068
3145
|
err.error,
|
|
3069
3146
|
err.errorDescription,
|