@palbase/backend 30.0.1 → 33.0.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 +210 -24
- package/dist/bin/palbase-backend.cjs.map +1 -1
- package/dist/bin/palbase-backend.js +7 -7
- package/dist/{chunk-TWX6JTGJ.js → chunk-26GH54D2.js} +3 -5
- package/dist/{chunk-TWX6JTGJ.js.map → chunk-26GH54D2.js.map} +1 -1
- package/dist/{chunk-VVMJEVQP.js → chunk-BRLJOXWS.js} +2 -2
- package/dist/{chunk-3TUJWHC2.js → chunk-C4ZA5AT2.js} +378 -19
- package/dist/chunk-C4ZA5AT2.js.map +1 -0
- package/dist/{chunk-RADVOY7Y.js → chunk-DCDHAKF3.js} +147 -33
- package/dist/chunk-DCDHAKF3.js.map +1 -0
- package/dist/{chunk-ENZ2RFFJ.js → chunk-GOPZPM2A.js} +3 -310
- package/dist/chunk-GOPZPM2A.js.map +1 -0
- package/dist/{chunk-CGNN2PUH.js → chunk-KATPXCJ5.js} +37 -4
- package/dist/{chunk-CGNN2PUH.js.map → chunk-KATPXCJ5.js.map} +1 -1
- package/dist/{chunk-YRVIWHJC.js → chunk-N54QZER3.js} +23 -323
- package/dist/chunk-N54QZER3.js.map +1 -0
- package/dist/chunk-QMFOL2K6.js +371 -0
- package/dist/chunk-QMFOL2K6.js.map +1 -0
- package/dist/chunk-XOX6RFPZ.js +383 -0
- package/dist/chunk-XOX6RFPZ.js.map +1 -0
- package/dist/db/index.cjs +41 -2
- package/dist/db/index.cjs.map +1 -1
- package/dist/db/index.d.cts +1 -1
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.js +12 -13
- package/dist/engine/index.cjs +210 -24
- package/dist/engine/index.cjs.map +1 -1
- package/dist/engine/index.d.cts +3 -3
- package/dist/engine/index.d.ts +3 -3
- package/dist/engine/index.js +7 -7
- package/dist/{index-DtCgaZAg.d.cts → index-BWgnGj68.d.cts} +185 -35
- package/dist/{index-b-Q3l7W5.d.ts → index-Bi74dcOu.d.ts} +9 -2
- package/dist/{index-8qy3kIuA.d.ts → index-Dg10RnZO.d.ts} +185 -35
- package/dist/{index-Zi7MptvP.d.cts → index-g6iQyYci.d.cts} +9 -2
- package/dist/index.cjs +135 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -23
- package/dist/index.d.ts +6 -23
- package/dist/index.js +48 -48
- package/dist/index.js.map +1 -1
- package/dist/openapi/index.d.cts +2 -2
- package/dist/openapi/index.d.ts +2 -2
- package/dist/openapi/index.js +3 -4
- package/dist/openapi/index.js.map +1 -1
- package/dist/{registry-CEYLH-Iz.d.cts → registry-6VT5RPeO.d.cts} +1 -1
- package/dist/{registry-BGJ-Al6F.d.ts → registry-B-sxJJN0.d.ts} +1 -1
- package/dist/test/index.cjs +733 -17
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.d.cts +59 -4
- package/dist/test/index.d.ts +59 -4
- package/dist/test/index.js +56 -16
- package/dist/test/index.js.map +1 -1
- package/docs/README.md +1 -1
- package/docs/auth.md +102 -20
- package/docs/database.md +54 -0
- package/docs/llms-full.txt +215 -21
- package/docs/schema.md +58 -0
- package/package.json +1 -1
- package/template/db/public.ts +23 -0
- package/template/package.json +1 -1
- package/dist/chunk-3TUJWHC2.js.map +0 -1
- package/dist/chunk-ENZ2RFFJ.js.map +0 -1
- package/dist/chunk-RADVOY7Y.js.map +0 -1
- package/dist/chunk-SG4UTNOP.js +0 -374
- package/dist/chunk-SG4UTNOP.js.map +0 -1
- package/dist/chunk-VXPNPVAG.js +0 -40
- package/dist/chunk-VXPNPVAG.js.map +0 -1
- package/dist/chunk-YRVIWHJC.js.map +0 -1
- /package/dist/{chunk-VVMJEVQP.js.map → chunk-BRLJOXWS.js.map} +0 -0
package/dist/db/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { h as AnyColumn, n as ColumnBuilder, o as ColumnDef, p as ColumnMap, q as ColumnType, v as EXTENSION_DEPENDENCIES, w as EmbeddingModelRef, E as EnvServiceDatabase, z as EnvTypedDatabase, V as InsertShape, $ as Materialized, a6 as OnDeleteAction, a8 as PALBASE_EXTENSIONS, aI as PalbaseExtension, bF as PolicyBuilder, bG as PolicyCommand, bH as PolicyDef, bK as PolicyMode, bN as RawConstraintDef, bP as Ref, bR as RowShape, S as SchemaDef, b_ as TABLE_META, b$ as TableDef, c0 as TableHandle, c1 as TableInput, c3 as TxColumnExpr, c4 as TxInsertShape, c6 as TxNow, c7 as TxPlan, T as TxPlanBody, c8 as TxPlanError, c9 as TxPlanHandle, ca as TxPlanOpResult, cb as TxPlanRejection, c as TxPlanResponse, cc as TxRefError, cd as TxRow, ce as TxRows, cf as TxSelectOptions, cg as TxSetShape, ci as TxTable, cj as TxTables, ck as TxWhere, cq as TypedDB, cr as TypedTable, cs as TypedTx, cD as bigint, cE as boolean, cG as dec, cJ as defineSchema, cK as defineTable, cL as enumType, cN as inc, cQ as installationRef, cR as integer, cS as isPalbaseExtension, cU as jsonb, cV as makeTypedDB, cW as now, c_ as openai, c$ as ownedByUser, d0 as policy, d1 as raw, d3 as text, d4 as timestamp, d5 as userRef, d6 as uuid, d7 as vector } from '../index-BWgnGj68.cjs';
|
|
2
2
|
import './env.cjs';
|
|
3
3
|
import '../stack.cjs';
|
|
4
4
|
import 'zod';
|
package/dist/db/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { h as AnyColumn, n as ColumnBuilder, o as ColumnDef, p as ColumnMap, q as ColumnType, v as EXTENSION_DEPENDENCIES, w as EmbeddingModelRef, E as EnvServiceDatabase, z as EnvTypedDatabase, V as InsertShape, $ as Materialized, a6 as OnDeleteAction, a8 as PALBASE_EXTENSIONS, aI as PalbaseExtension, bF as PolicyBuilder, bG as PolicyCommand, bH as PolicyDef, bK as PolicyMode, bN as RawConstraintDef, bP as Ref, bR as RowShape, S as SchemaDef, b_ as TABLE_META, b$ as TableDef, c0 as TableHandle, c1 as TableInput, c3 as TxColumnExpr, c4 as TxInsertShape, c6 as TxNow, c7 as TxPlan, T as TxPlanBody, c8 as TxPlanError, c9 as TxPlanHandle, ca as TxPlanOpResult, cb as TxPlanRejection, c as TxPlanResponse, cc as TxRefError, cd as TxRow, ce as TxRows, cf as TxSelectOptions, cg as TxSetShape, ci as TxTable, cj as TxTables, ck as TxWhere, cq as TypedDB, cr as TypedTable, cs as TypedTx, cD as bigint, cE as boolean, cG as dec, cJ as defineSchema, cK as defineTable, cL as enumType, cN as inc, cQ as installationRef, cR as integer, cS as isPalbaseExtension, cU as jsonb, cV as makeTypedDB, cW as now, c_ as openai, c$ as ownedByUser, d0 as policy, d1 as raw, d3 as text, d4 as timestamp, d5 as userRef, d6 as uuid, d7 as vector } from '../index-Dg10RnZO.js';
|
|
2
2
|
import './env.js';
|
|
3
3
|
import '../stack.js';
|
|
4
4
|
import 'zod';
|
package/dist/db/index.js
CHANGED
|
@@ -3,37 +3,36 @@ import {
|
|
|
3
3
|
PALBASE_EXTENSIONS,
|
|
4
4
|
PolicyBuilder,
|
|
5
5
|
TABLE_META,
|
|
6
|
-
bigint,
|
|
7
|
-
boolean,
|
|
8
6
|
defineSchema,
|
|
9
7
|
defineTable,
|
|
8
|
+
isPalbaseExtension,
|
|
9
|
+
openai,
|
|
10
|
+
policy,
|
|
11
|
+
raw
|
|
12
|
+
} from "../chunk-GOPZPM2A.js";
|
|
13
|
+
import {
|
|
14
|
+
bigint,
|
|
15
|
+
boolean,
|
|
10
16
|
enumType,
|
|
11
17
|
installationRef,
|
|
12
18
|
integer,
|
|
13
|
-
isPalbaseExtension,
|
|
14
19
|
jsonb,
|
|
15
|
-
openai,
|
|
16
20
|
ownedByUser,
|
|
17
|
-
policy,
|
|
18
|
-
raw,
|
|
19
21
|
text,
|
|
20
22
|
timestamp,
|
|
21
23
|
userRef,
|
|
22
24
|
uuid,
|
|
23
25
|
vector
|
|
24
|
-
} from "../chunk-
|
|
25
|
-
import {
|
|
26
|
-
makeTypedDB
|
|
27
|
-
} from "../chunk-SG4UTNOP.js";
|
|
26
|
+
} from "../chunk-XOX6RFPZ.js";
|
|
28
27
|
import {
|
|
29
28
|
TxPlanError,
|
|
30
29
|
TxRefError,
|
|
31
30
|
dec,
|
|
32
31
|
inc,
|
|
32
|
+
makeTypedDB,
|
|
33
33
|
now
|
|
34
|
-
} from "../chunk-
|
|
35
|
-
import "../chunk-
|
|
36
|
-
import "../chunk-VXPNPVAG.js";
|
|
34
|
+
} from "../chunk-C4ZA5AT2.js";
|
|
35
|
+
import "../chunk-KATPXCJ5.js";
|
|
37
36
|
export {
|
|
38
37
|
EXTENSION_DEPENDENCIES,
|
|
39
38
|
PALBASE_EXTENSIONS,
|
package/dist/engine/index.cjs
CHANGED
|
@@ -863,7 +863,11 @@ function qualifiedTableKey(schemaName, tableName) {
|
|
|
863
863
|
__name(qualifiedTableKey, "qualifiedTableKey");
|
|
864
864
|
|
|
865
865
|
// src/runtime.ts
|
|
866
|
-
var
|
|
866
|
+
var REQUEST_ALS = /* @__PURE__ */ Symbol.for("palbase.backend.requestALS");
|
|
867
|
+
var __requestALS = (() => {
|
|
868
|
+
const g = globalThis;
|
|
869
|
+
return g[REQUEST_ALS] ??= new import_node_async_hooks.AsyncLocalStorage();
|
|
870
|
+
})();
|
|
867
871
|
var runtime = null;
|
|
868
872
|
function __runWithRuntime(services, fn) {
|
|
869
873
|
return __requestALS.run({
|
|
@@ -871,9 +875,29 @@ function __runWithRuntime(services, fn) {
|
|
|
871
875
|
}, fn);
|
|
872
876
|
}
|
|
873
877
|
__name(__runWithRuntime, "__runWithRuntime");
|
|
878
|
+
var REQUIRED_SERVICES = [
|
|
879
|
+
"Database",
|
|
880
|
+
"Auth",
|
|
881
|
+
"Secrets",
|
|
882
|
+
"Documents",
|
|
883
|
+
"Storage",
|
|
884
|
+
"Cache",
|
|
885
|
+
"Log",
|
|
886
|
+
"Notifications",
|
|
887
|
+
"Flags",
|
|
888
|
+
"Realtime"
|
|
889
|
+
];
|
|
890
|
+
function refuseIncompleteBox(services) {
|
|
891
|
+
const missing = REQUIRED_SERVICES.filter((k) => services[k] === void 0);
|
|
892
|
+
if (missing.length > 0) {
|
|
893
|
+
throw new Error(`the request scope is missing ${missing.join(", ")} \u2014 this box was most likely written by a DIFFERENT @palbase/backend major sharing the same process (the request store is a process-wide well-known Symbol, deliberately, so two bundles of ONE version can share it). Align the versions, or pass every service when building the scope yourself.`);
|
|
894
|
+
}
|
|
895
|
+
return services;
|
|
896
|
+
}
|
|
897
|
+
__name(refuseIncompleteBox, "refuseIncompleteBox");
|
|
874
898
|
function __getRuntime() {
|
|
875
899
|
const scoped = __requestALS.getStore();
|
|
876
|
-
if (scoped) return scoped.runtime;
|
|
900
|
+
if (scoped) return refuseIncompleteBox(scoped.runtime);
|
|
877
901
|
if (runtime === null) {
|
|
878
902
|
throw new Error("Palbase services accessed outside a request scope. The Database/Documents/\u2026 singletons are only available inside an endpoint handler (or after the runtime has called __runWithRuntime / __setRuntime).");
|
|
879
903
|
}
|
|
@@ -996,7 +1020,12 @@ function makeTypedSurface(raw) {
|
|
|
996
1020
|
$findById: /* @__PURE__ */ __name((table, id) => raw.findById(table, id), "$findById"),
|
|
997
1021
|
$findMany: /* @__PURE__ */ __name((table, query, opts) => raw.findMany(table, query, opts), "$findMany"),
|
|
998
1022
|
$put: /* @__PURE__ */ __name((table, data, opts) => raw.put(table, data, opts), "$put"),
|
|
999
|
-
|
|
1023
|
+
// `opts` İLETİLİR. Düşürüldüğü sürece `Database.$updateMany(t, w, s,
|
|
1024
|
+
// { returning: false })` sessizce SATIRLARI döndürüyordu, sayıyı değil —
|
|
1025
|
+
// ve `if (n === 0) throw new Conflict(...)` guard'ı HİÇ çalışmıyordu,
|
|
1026
|
+
// çünkü `[] === 0` yanlıştır. Komşu forwarder'lar (`$findMany`, `$put`)
|
|
1027
|
+
// kendi opsiyonlarını zaten iletiyordu; bu biri unutulmuştu.
|
|
1028
|
+
$updateMany: /* @__PURE__ */ __name((table, where, set, opts) => raw.updateMany(table, where, set, opts), "$updateMany"),
|
|
1000
1029
|
$deleteMany: /* @__PURE__ */ __name((table, where) => raw.deleteMany(table, where), "$deleteMany"),
|
|
1001
1030
|
$count: /* @__PURE__ */ __name((table, where) => raw.count(table, where), "$count"),
|
|
1002
1031
|
$search: /* @__PURE__ */ __name((table, params) => raw.search(table, params), "$search"),
|
|
@@ -1127,10 +1156,23 @@ var Flags = Object.assign({
|
|
|
1127
1156
|
* Lazily resolve the runtime's cross-user sibling on each call. We do NOT
|
|
1128
1157
|
* cache it: `rawFlags.asService()` reads the CURRENT request scope through
|
|
1129
1158
|
* the runtime proxy, so caching would leak one request's sibling into
|
|
1130
|
-
* another concurrent request. Mirrors `Database
|
|
1159
|
+
* another concurrent request. Mirrors `Database.$asService()`.
|
|
1131
1160
|
*/
|
|
1132
|
-
asService() {
|
|
1161
|
+
$asService() {
|
|
1133
1162
|
return rawFlags.asService();
|
|
1163
|
+
},
|
|
1164
|
+
/**
|
|
1165
|
+
* The name this member carried before 32.0.0.
|
|
1166
|
+
*
|
|
1167
|
+
* It does NOT work silently. A retired member that quietly keeps returning
|
|
1168
|
+
* is how a rename becomes a mystery: the old call site goes on compiling,
|
|
1169
|
+
* the new name never spreads, and the two live side by side until somebody
|
|
1170
|
+
* greps for one and misses half the codebase. `Database` made this split
|
|
1171
|
+
* first (`$asService`), and this JSDoc promised "exactly like
|
|
1172
|
+
* Database.$asService()" while the promise went unkept.
|
|
1173
|
+
*/
|
|
1174
|
+
asService() {
|
|
1175
|
+
throw new Error("Flags.asService() was renamed to Flags.$asService() in 32.0.0 \u2014 system members carry the `$` prefix, like Database.$asService().");
|
|
1134
1176
|
}
|
|
1135
1177
|
});
|
|
1136
1178
|
var Realtime = makeServiceProxy("Realtime");
|
|
@@ -1503,6 +1545,37 @@ function makeMemoryCache(opts = {}) {
|
|
|
1503
1545
|
}
|
|
1504
1546
|
__name(makeMemoryCache, "makeMemoryCache");
|
|
1505
1547
|
|
|
1548
|
+
// src/db/columns.ts
|
|
1549
|
+
var CODECS = {
|
|
1550
|
+
// Exact-precision column → JS number. Safe below 2^53; a value above it is
|
|
1551
|
+
// not representable and the author wants `asDecimal()` instead.
|
|
1552
|
+
number: {
|
|
1553
|
+
fromDb: /* @__PURE__ */ __name((v) => Number(v), "fromDb"),
|
|
1554
|
+
// YAZMA YOLUNDA SESSİZ BOZULMA YOK. `toDb(9007199254740993)` bir zamanlar
|
|
1555
|
+
// "9007199254740992" yazıyordu: uygulamanın tuttuğundan BAŞKA bir sayı
|
|
1556
|
+
// kolona gidiyordu ve hiçbir şey söylemiyordu. `asNumber()`'ın JSDoc'u
|
|
1557
|
+
// "2^53'ün altında güvenli" diyordu ama bunu uygulayan bir şey yoktu.
|
|
1558
|
+
toDb: /* @__PURE__ */ __name((v) => {
|
|
1559
|
+
if (typeof v === "number" && !Number.isSafeInteger(v)) {
|
|
1560
|
+
throw new Error(`asNumber() cannot write ${v}: it is outside the safe integer range and would be stored as a different number. Declare .asDecimal() and hand this column a string.`);
|
|
1561
|
+
}
|
|
1562
|
+
return String(v);
|
|
1563
|
+
}, "toDb"),
|
|
1564
|
+
tsType: "number"
|
|
1565
|
+
},
|
|
1566
|
+
// Exact-precision column → the string Postgres sent. It exists so the
|
|
1567
|
+
// DECLARATION is explicit: "this column is a decimal I handle as text",
|
|
1568
|
+
// rather than the ABSENCE of a declaration meaning the same thing by default.
|
|
1569
|
+
// NULL güvencesi ÇİFTİN KENDİSİNDE. Motor NULL'ı zaten atlıyor (üç ayrı
|
|
1570
|
+
// yerde), ama bir değişmez, onu koruyan üç `if`'in DIŞINDA yazılmalı: biri
|
|
1571
|
+
// düşerse `String(null)` kolonu "null" dizesine çevirirdi.
|
|
1572
|
+
decimal: {
|
|
1573
|
+
fromDb: /* @__PURE__ */ __name((v) => v === null || v === void 0 ? v : String(v), "fromDb"),
|
|
1574
|
+
toDb: /* @__PURE__ */ __name((v) => v === null || v === void 0 ? v : String(v), "toDb"),
|
|
1575
|
+
tsType: "string"
|
|
1576
|
+
}
|
|
1577
|
+
};
|
|
1578
|
+
|
|
1506
1579
|
// src/db/env-gen.ts
|
|
1507
1580
|
function forwardName(column) {
|
|
1508
1581
|
return column.endsWith("_id") ? column.slice(0, -3) : column;
|
|
@@ -1716,6 +1789,15 @@ function transformsOf(schema, table) {
|
|
|
1716
1789
|
if (def) {
|
|
1717
1790
|
for (const [col, c] of Object.entries(def.columns ?? {})) {
|
|
1718
1791
|
const d = c !== null && typeof c === "object" && "_def" in c ? c._def : c;
|
|
1792
|
+
const codec = d?.codec;
|
|
1793
|
+
if (typeof codec === "string" && codec in CODECS) {
|
|
1794
|
+
const c2 = CODECS[codec];
|
|
1795
|
+
out.set(col, {
|
|
1796
|
+
fromDb: c2.fromDb,
|
|
1797
|
+
toDb: c2.toDb
|
|
1798
|
+
});
|
|
1799
|
+
continue;
|
|
1800
|
+
}
|
|
1719
1801
|
const t = d?.transform;
|
|
1720
1802
|
if (t !== null && typeof t === "object") {
|
|
1721
1803
|
out.set(col, t);
|
|
@@ -2051,6 +2133,29 @@ function selectClause(table, known, select) {
|
|
|
2051
2133
|
}).join(", ");
|
|
2052
2134
|
}
|
|
2053
2135
|
__name(selectClause, "selectClause");
|
|
2136
|
+
function quoteLiteral(v) {
|
|
2137
|
+
return `'${v.replace(/'/g, "''")}'`;
|
|
2138
|
+
}
|
|
2139
|
+
__name(quoteLiteral, "quoteLiteral");
|
|
2140
|
+
function orderClauseFor(table, known, orderBy, alias) {
|
|
2141
|
+
if (orderBy === void 0 || orderBy === null) return "";
|
|
2142
|
+
const items = Array.isArray(orderBy) ? orderBy : [
|
|
2143
|
+
orderBy
|
|
2144
|
+
];
|
|
2145
|
+
if (items.length === 0) return "";
|
|
2146
|
+
const rendered = items.map((o) => {
|
|
2147
|
+
const col = o.column;
|
|
2148
|
+
const shapeOK = /^[A-Za-z_][A-Za-z0-9_]*$/.test(col);
|
|
2149
|
+
if (known !== null ? !known.has(col) : !shapeOK) {
|
|
2150
|
+
throw new Error(`with(${table}): orderBy kolonu "${col}" tabloda yok`);
|
|
2151
|
+
}
|
|
2152
|
+
const dir = o.direction === "desc" ? "DESC" : "ASC";
|
|
2153
|
+
const nulls = o.nulls === "first" ? " NULLS FIRST" : o.nulls === "last" ? " NULLS LAST" : "";
|
|
2154
|
+
return `${alias}.${quoteIdent(col)} ${dir}${nulls}`;
|
|
2155
|
+
});
|
|
2156
|
+
return ` ORDER BY ${rendered.join(", ")}`;
|
|
2157
|
+
}
|
|
2158
|
+
__name(orderClauseFor, "orderClauseFor");
|
|
2054
2159
|
function orderClause(table, known, orderBy) {
|
|
2055
2160
|
if (!orderBy) return "";
|
|
2056
2161
|
const items = Array.isArray(orderBy) ? orderBy : [
|
|
@@ -2354,6 +2459,65 @@ function aggregateExpr(table, fn, col, alias) {
|
|
|
2354
2459
|
return t !== null && NUMERIC_PG_TYPES.has(t) && t !== "integer" ? `${fn}(${q})::text AS ${quoteIdent(alias)}` : `${fn}(${q}) AS ${quoteIdent(alias)}`;
|
|
2355
2460
|
}
|
|
2356
2461
|
__name(aggregateExpr, "aggregateExpr");
|
|
2462
|
+
function jsonObjectFor(table, cols, alias) {
|
|
2463
|
+
const pairs = cols.map((c) => {
|
|
2464
|
+
const t = columnTypeOf(table, c);
|
|
2465
|
+
const expr = t !== null && (t === "numeric" || t === "bigint") ? `${alias}.${quoteIdent(c)}::text` : `${alias}.${quoteIdent(c)}`;
|
|
2466
|
+
return `${quoteLiteral(c)}, ${expr}`;
|
|
2467
|
+
});
|
|
2468
|
+
return `json_build_object(${pairs.join(", ")})`;
|
|
2469
|
+
}
|
|
2470
|
+
__name(jsonObjectFor, "jsonObjectFor");
|
|
2471
|
+
function withClauses(table, spec, add, caller) {
|
|
2472
|
+
const rels = currentRelations.get(table) ?? [];
|
|
2473
|
+
const select = [];
|
|
2474
|
+
const joins = [];
|
|
2475
|
+
let i = 0;
|
|
2476
|
+
for (const [name, opt] of Object.entries(spec)) {
|
|
2477
|
+
if (opt === false || opt === void 0) continue;
|
|
2478
|
+
const rel = rels.find((r) => r.name === name);
|
|
2479
|
+
if (rel === void 0) {
|
|
2480
|
+
const known = rels.map((r) => r.name).sort();
|
|
2481
|
+
throw new Error(`${caller}(${table}): with.${name} diye bir ili\u015Fki yok` + (known.length > 0 ? ` (bilinenler: ${known.join(", ")})` : `. Bu tablo hi\xE7 yabanc\u0131 anahtar bildirmiyor ve ili\u015Fkiler onlardan T\xDCRET\u0130L\u0130R`) + `. \u0130li\u015Fkiler references(() => <tablo>.<kolon>) ile bildirilir.`);
|
|
2482
|
+
}
|
|
2483
|
+
const ourCol = rel.kind === "many" ? primaryKeyOf(table) : rel.via;
|
|
2484
|
+
const theirCol = rel.kind === "many" ? rel.via : primaryKeyOf(rel.to);
|
|
2485
|
+
if (ourCol === null || theirCol === null) {
|
|
2486
|
+
throw new Error(`${caller}(${table}): with.${name} birincil anahtar bilmeden kurulamaz \u2014 ili\u015Fkinin bir ucu tablonun PK's\u0131 ve bu tablo tek kolonlu bir PK bildirmiyor.`);
|
|
2487
|
+
}
|
|
2488
|
+
const o = typeof opt === "object" && opt !== null ? opt : {};
|
|
2489
|
+
const childAlias = `w${++i}`;
|
|
2490
|
+
const childKnown = schemaColumns(rel.to);
|
|
2491
|
+
const childCols = Array.isArray(o["select"]) && o["select"].length > 0 ? o["select"] : childKnown !== null ? [
|
|
2492
|
+
...childKnown
|
|
2493
|
+
] : [];
|
|
2494
|
+
if (childCols.length === 0) {
|
|
2495
|
+
throw new Error(`${caller}(${table}): with.${name} i\xE7in "${rel.to}" tablosunun kolonlar\u0131 bilinmiyor \u2014 select ile hangi kolonlar\u0131 istedi\u011Finizi yaz\u0131n.`);
|
|
2496
|
+
}
|
|
2497
|
+
for (const c of childCols) {
|
|
2498
|
+
if (childKnown !== null && !childKnown.has(c)) {
|
|
2499
|
+
throw new Error(`${caller}(${table}): with.${name}.select kolonu "${c}" "${rel.to}" tablosunda yok`);
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
const obj = jsonObjectFor(rel.to, childCols, childAlias);
|
|
2503
|
+
const innerWhere = o["where"] !== void 0 && o["where"] !== null ? compileWhereBare(rel.to, childKnown, o["where"], add, caller, childAlias, i) : "";
|
|
2504
|
+
const link = `${childAlias}.${quoteIdent(theirCol)} = t.${quoteIdent(ourCol)}`;
|
|
2505
|
+
const cond = innerWhere === "" ? link : `${link} AND ${innerWhere}`;
|
|
2506
|
+
const inner = orderClauseFor(rel.to, childKnown, o["orderBy"], childAlias) + limitClause(o["limit"]);
|
|
2507
|
+
const outAlias = `wj${i}`;
|
|
2508
|
+
if (rel.kind === "many") {
|
|
2509
|
+
joins.push(`LEFT JOIN LATERAL (SELECT coalesce(json_agg(x.o), '[]'::json) AS d FROM (SELECT ${obj} AS o FROM ${quoteTable(rel.to)} ${childAlias} WHERE ${cond}${inner}) x) ${quoteIdent(outAlias)} ON true`);
|
|
2510
|
+
} else {
|
|
2511
|
+
joins.push(`LEFT JOIN LATERAL (SELECT ${obj} AS d FROM ${quoteTable(rel.to)} ${childAlias} WHERE ${cond}${inner} LIMIT 1) ${quoteIdent(outAlias)} ON true`);
|
|
2512
|
+
}
|
|
2513
|
+
select.push(`${quoteIdent(outAlias)}."d" AS ${quoteIdent(name)}`);
|
|
2514
|
+
}
|
|
2515
|
+
return {
|
|
2516
|
+
select,
|
|
2517
|
+
joins
|
|
2518
|
+
};
|
|
2519
|
+
}
|
|
2520
|
+
__name(withClauses, "withClauses");
|
|
2357
2521
|
function createOps(tx) {
|
|
2358
2522
|
const at = /* @__PURE__ */ __name(() => resolveTx(tx), "at");
|
|
2359
2523
|
const ops = {
|
|
@@ -2797,7 +2961,13 @@ function createOps(tx) {
|
|
|
2797
2961
|
const limit = limitClause(opts.limit);
|
|
2798
2962
|
const offset = offsetClause(opts.offset, opts.limit);
|
|
2799
2963
|
const cols = selectClause(table, known, opts.select);
|
|
2800
|
-
const
|
|
2964
|
+
const w = opts.with !== void 0 && Object.keys(opts.with).length > 0 ? withClauses(table, opts.with, add, "findMany") : {
|
|
2965
|
+
select: [],
|
|
2966
|
+
joins: []
|
|
2967
|
+
};
|
|
2968
|
+
const selectList = w.select.length > 0 ? `${cols === "*" ? "t.*" : cols}, ${w.select.join(", ")}` : cols;
|
|
2969
|
+
const joinSql = w.joins.length > 0 ? ` ${w.joins.join(" ")}` : "";
|
|
2970
|
+
const sql = `SELECT ${selectList} FROM ${quoteTable(table)} t${joinSql} WHERE true${whereSql}${order}${limit}${offset}`;
|
|
2801
2971
|
return asTableRows(table, await (await at()).unsafe(sql, params));
|
|
2802
2972
|
},
|
|
2803
2973
|
/**
|
|
@@ -4727,23 +4897,21 @@ async function createApp(opts) {
|
|
|
4727
4897
|
if (spec.required && !callerClaims) {
|
|
4728
4898
|
return envelope("unauthorized", "A valid access token is required", 401, requestId);
|
|
4729
4899
|
}
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
if (refusal) {
|
|
4739
|
-
await uploadDb.commit();
|
|
4740
|
-
return refusal;
|
|
4741
|
-
}
|
|
4900
|
+
const uploadDb = createRequestDatabase(sql, {
|
|
4901
|
+
role: config.dbRole,
|
|
4902
|
+
serviceRole: config.dbServiceRole,
|
|
4903
|
+
claimsJson: JSON.stringify(callerClaims ?? {})
|
|
4904
|
+
});
|
|
4905
|
+
try {
|
|
4906
|
+
const refusal = await refuseUnlessAuthorized(uploadDb.client, spec, requestId, makeRoleResolver(uploadDb.client));
|
|
4907
|
+
if (refusal) {
|
|
4742
4908
|
await uploadDb.commit();
|
|
4743
|
-
|
|
4744
|
-
await uploadDb.rollback(err);
|
|
4745
|
-
throw err;
|
|
4909
|
+
return refusal;
|
|
4746
4910
|
}
|
|
4911
|
+
await uploadDb.commit();
|
|
4912
|
+
} catch (err) {
|
|
4913
|
+
await uploadDb.rollback(err);
|
|
4914
|
+
throw err;
|
|
4747
4915
|
}
|
|
4748
4916
|
const grant = grantFor(target?.entry, {
|
|
4749
4917
|
userId: typeof callerClaims?.sub === "string" ? callerClaims.sub : null,
|
|
@@ -4782,11 +4950,18 @@ async function createApp(opts) {
|
|
|
4782
4950
|
claimsJson: JSON.stringify(claims ?? {})
|
|
4783
4951
|
});
|
|
4784
4952
|
const rolesOfCaller = makeRoleResolver(db.client);
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
if (
|
|
4953
|
+
let dispatched = false;
|
|
4954
|
+
const settleBeforeRefusal = /* @__PURE__ */ __name(async () => {
|
|
4955
|
+
if (dispatched) return;
|
|
4956
|
+
await db.rollback(new Error("request refused before dispatch"));
|
|
4957
|
+
}, "settleBeforeRefusal");
|
|
4958
|
+
const refusal = await refuseUnlessAuthorized(db.client, spec, requestId, rolesOfCaller);
|
|
4959
|
+
if (refusal) {
|
|
4960
|
+
await settleBeforeRefusal();
|
|
4961
|
+
return refusal;
|
|
4788
4962
|
}
|
|
4789
4963
|
if (claims && spec.verifiedEmail && claims.email_verified !== true) {
|
|
4964
|
+
await settleBeforeRefusal();
|
|
4790
4965
|
return envelope("email_not_verified", "A verified email address is required", 403, requestId);
|
|
4791
4966
|
}
|
|
4792
4967
|
let parsedBody;
|
|
@@ -4795,6 +4970,7 @@ async function createApp(opts) {
|
|
|
4795
4970
|
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
4796
4971
|
const declared = Number(req.headers.get("content-length") ?? "");
|
|
4797
4972
|
if (Number.isFinite(declared) && declared > MAX_BODY_BYTES) {
|
|
4973
|
+
await settleBeforeRefusal();
|
|
4798
4974
|
return new Response(JSON.stringify({
|
|
4799
4975
|
error: "payload_too_large",
|
|
4800
4976
|
error_description: `Request body exceeds ${MAX_BODY_BYTES} bytes`,
|
|
@@ -4807,6 +4983,7 @@ async function createApp(opts) {
|
|
|
4807
4983
|
}
|
|
4808
4984
|
const buf = await req.arrayBuffer().catch(() => null);
|
|
4809
4985
|
if (buf && buf.byteLength > MAX_BODY_BYTES) {
|
|
4986
|
+
await settleBeforeRefusal();
|
|
4810
4987
|
return new Response(JSON.stringify({
|
|
4811
4988
|
error: "payload_too_large",
|
|
4812
4989
|
error_description: `Request body exceeds ${MAX_BODY_BYTES} bytes`,
|
|
@@ -4842,6 +5019,7 @@ async function createApp(opts) {
|
|
|
4842
5019
|
...JSON_HEADERS
|
|
4843
5020
|
};
|
|
4844
5021
|
if (attest.nextChallenge) headers["x-palbase-attest-challenge"] = attest.nextChallenge;
|
|
5022
|
+
await settleBeforeRefusal();
|
|
4845
5023
|
return new Response(JSON.stringify({
|
|
4846
5024
|
error: attest.reason,
|
|
4847
5025
|
error_description: "This endpoint requires a verified app instance",
|
|
@@ -4856,6 +5034,7 @@ async function createApp(opts) {
|
|
|
4856
5034
|
attestChallengeOut = attest.nextChallenge;
|
|
4857
5035
|
const retryAfter = limiter.check(meta.options?.rateLimit, RateLimiter.key(hit.entry.id, userId, req.headers), Date.now());
|
|
4858
5036
|
if (retryAfter !== null) {
|
|
5037
|
+
await settleBeforeRefusal();
|
|
4859
5038
|
return new Response(JSON.stringify({
|
|
4860
5039
|
error: "too_many_requests",
|
|
4861
5040
|
error_description: "Rate limit exceeded for this endpoint",
|
|
@@ -4887,6 +5066,7 @@ async function createApp(opts) {
|
|
|
4887
5066
|
readParsedBody();
|
|
4888
5067
|
const r = p.schema.safeParse(parsedBody);
|
|
4889
5068
|
if (!r.success) {
|
|
5069
|
+
await settleBeforeRefusal();
|
|
4890
5070
|
return envelope("bad_request", "Request body failed validation", 400, requestId, {
|
|
4891
5071
|
data: {
|
|
4892
5072
|
fields: fieldErrors(r.error)
|
|
@@ -4899,6 +5079,7 @@ async function createApp(opts) {
|
|
|
4899
5079
|
case "query": {
|
|
4900
5080
|
const r = p.schema.safeParse(Object.fromEntries(url.searchParams));
|
|
4901
5081
|
if (!r.success) {
|
|
5082
|
+
await settleBeforeRefusal();
|
|
4902
5083
|
return envelope("bad_request", "Query parameters failed validation", 400, requestId, {
|
|
4903
5084
|
data: {
|
|
4904
5085
|
fields: fieldErrors(r.error)
|
|
@@ -4919,6 +5100,7 @@ async function createApp(opts) {
|
|
|
4919
5100
|
}
|
|
4920
5101
|
const r = p.schema.safeParse(headersFor(raw, p.schema));
|
|
4921
5102
|
if (!r.success) {
|
|
5103
|
+
await settleBeforeRefusal();
|
|
4922
5104
|
return envelope("bad_request", "Request headers failed validation", 400, requestId, {
|
|
4923
5105
|
data: {
|
|
4924
5106
|
fields: fieldErrors(r.error)
|
|
@@ -4951,17 +5133,20 @@ async function createApp(opts) {
|
|
|
4951
5133
|
break;
|
|
4952
5134
|
case "uploadedObject": {
|
|
4953
5135
|
if (uploadSecret === "" || !verifySignature(req.headers.get(SIGNATURE_HEADER) ?? "", uploadSecret)) {
|
|
5136
|
+
await settleBeforeRefusal();
|
|
4954
5137
|
return envelope("unauthorized", "This endpoint accepts uploads through storage, not directly", 401, requestId);
|
|
4955
5138
|
}
|
|
4956
5139
|
readParsedBody();
|
|
4957
5140
|
const envelopeIn = parsedBody;
|
|
4958
5141
|
if (!envelopeIn?.uploadedObject) {
|
|
5142
|
+
await settleBeforeRefusal();
|
|
4959
5143
|
return envelope("bad_request", "the completion call carried no uploaded object", 400, requestId);
|
|
4960
5144
|
}
|
|
4961
5145
|
const uploadId = envelopeIn.uploadedObject.uploadId;
|
|
4962
5146
|
if (typeof uploadId === "string" && uploadId !== "") {
|
|
4963
5147
|
const already = completions.recall(uploadId);
|
|
4964
5148
|
if (already) {
|
|
5149
|
+
await settleBeforeRefusal();
|
|
4965
5150
|
return new Response(already.body, {
|
|
4966
5151
|
status: already.status,
|
|
4967
5152
|
headers: already.contentType ? {
|
|
@@ -5011,6 +5196,7 @@ async function createApp(opts) {
|
|
|
5011
5196
|
args[p.index] = void 0;
|
|
5012
5197
|
}
|
|
5013
5198
|
}
|
|
5199
|
+
dispatched = true;
|
|
5014
5200
|
try {
|
|
5015
5201
|
const services = buildServices(db);
|
|
5016
5202
|
if (meta.options?.sseConfig !== void 0) {
|