@geekmidas/db 10.0.0-alpha.99 → 10.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/CHANGELOG.md +67 -0
- package/README.md +0 -17
- package/dist/kysely/pagination.cjs +9 -8
- package/dist/kysely/pagination.cjs.map +1 -1
- package/dist/kysely/pagination.d.cts +14 -4
- package/dist/kysely/pagination.d.cts.map +1 -1
- package/dist/kysely/pagination.d.mts +14 -4
- package/dist/kysely/pagination.d.mts.map +1 -1
- package/dist/kysely/pagination.mjs +10 -7
- package/dist/kysely/pagination.mjs.map +1 -1
- package/dist/kysely-8WPSKCZG.cjs +17 -0
- package/dist/kysely-8WPSKCZG.cjs.map +1 -0
- package/dist/kysely-D3eeuId4.d.cts +13 -0
- package/dist/kysely-D3eeuId4.d.cts.map +1 -0
- package/dist/kysely-Dm1w5gAY.d.mts +13 -0
- package/dist/kysely-Dm1w5gAY.d.mts.map +1 -0
- package/dist/kysely-DmfA94RY.mjs +11 -0
- package/dist/kysely-DmfA94RY.mjs.map +1 -0
- package/dist/kysely.cjs +2 -11
- package/dist/kysely.d.cts +2 -9
- package/dist/kysely.d.mts +2 -9
- package/dist/kysely.mjs +2 -10
- package/dist/objection/pagination.cjs +7 -7
- package/dist/objection/pagination.cjs.map +1 -1
- package/dist/objection/pagination.d.cts +14 -4
- package/dist/objection/pagination.d.cts.map +1 -1
- package/dist/objection/pagination.d.mts +14 -4
- package/dist/objection/pagination.d.mts.map +1 -1
- package/dist/objection/pagination.mjs +8 -6
- package/dist/objection/pagination.mjs.map +1 -1
- package/dist/{pagination-CrU89125.d.cts → pagination-BAFX7C1I.d.cts} +4 -14
- package/dist/pagination-BAFX7C1I.d.cts.map +1 -0
- package/dist/pagination-BDLa7Yb_.mjs +37 -0
- package/dist/pagination-BDLa7Yb_.mjs.map +1 -0
- package/dist/pagination-Bdoa4PVj.cjs +55 -0
- package/dist/pagination-Bdoa4PVj.cjs.map +1 -0
- package/dist/{pagination-CrU89125.d.mts → pagination-BziGl-B8.d.mts} +4 -14
- package/dist/pagination-BziGl-B8.d.mts.map +1 -0
- package/dist/pagination.cjs +4 -55
- package/dist/pagination.d.cts +2 -2
- package/dist/pagination.d.mts +2 -2
- package/dist/pagination.mjs +2 -51
- package/dist/rls.cjs +29 -5
- package/dist/rls.cjs.map +1 -1
- package/dist/rls.d.cts +10 -6
- package/dist/rls.d.cts.map +1 -1
- package/dist/rls.d.mts +10 -6
- package/dist/rls.d.mts.map +1 -1
- package/dist/rls.mjs +5 -3
- package/dist/rls.mjs.map +1 -1
- package/package.json +9 -53
- package/src/__tests__/kysely.integration.spec.ts +741 -0
- package/src/__tests__/kysely.spec.ts +394 -0
- package/src/__tests__/rls.spec.ts +716 -0
- package/src/kysely/__tests__/pagination.integration.spec.ts +341 -0
- package/src/kysely/pagination.ts +113 -0
- package/src/kysely.ts +33 -0
- package/src/objection/__tests__/pagination.integration.spec.ts +291 -0
- package/src/objection/pagination.ts +98 -0
- package/src/pagination.ts +49 -0
- package/src/rls.ts +90 -0
- package/tsconfig.json +9 -0
- package/dist/errors.cjs +0 -73
- package/dist/errors.cjs.map +0 -1
- package/dist/errors.d.cts +0 -51
- package/dist/errors.d.cts.map +0 -1
- package/dist/errors.d.mts +0 -51
- package/dist/errors.d.mts.map +0 -1
- package/dist/errors.mjs +0 -69
- package/dist/errors.mjs.map +0 -1
- package/dist/introspect/DataBrowser.cjs +0 -117
- package/dist/introspect/DataBrowser.cjs.map +0 -1
- package/dist/introspect/DataBrowser.d.cts +0 -51
- package/dist/introspect/DataBrowser.d.cts.map +0 -1
- package/dist/introspect/DataBrowser.d.mts +0 -51
- package/dist/introspect/DataBrowser.d.mts.map +0 -1
- package/dist/introspect/DataBrowser.mjs +0 -116
- package/dist/introspect/DataBrowser.mjs.map +0 -1
- package/dist/introspect/errors.cjs +0 -48
- package/dist/introspect/errors.cjs.map +0 -1
- package/dist/introspect/errors.d.cts +0 -27
- package/dist/introspect/errors.d.cts.map +0 -1
- package/dist/introspect/errors.d.mts +0 -27
- package/dist/introspect/errors.d.mts.map +0 -1
- package/dist/introspect/errors.mjs +0 -45
- package/dist/introspect/errors.mjs.map +0 -1
- package/dist/introspect/filtering.cjs +0 -101
- package/dist/introspect/filtering.cjs.map +0 -1
- package/dist/introspect/filtering.d.cts +0 -29
- package/dist/introspect/filtering.d.cts.map +0 -1
- package/dist/introspect/filtering.d.mts +0 -29
- package/dist/introspect/filtering.d.mts.map +0 -1
- package/dist/introspect/filtering.mjs +0 -98
- package/dist/introspect/filtering.mjs.map +0 -1
- package/dist/introspect/handler.cjs +0 -159
- package/dist/introspect/handler.cjs.map +0 -1
- package/dist/introspect/handler.d.cts +0 -43
- package/dist/introspect/handler.d.cts.map +0 -1
- package/dist/introspect/handler.d.mts +0 -43
- package/dist/introspect/handler.d.mts.map +0 -1
- package/dist/introspect/handler.mjs +0 -158
- package/dist/introspect/handler.mjs.map +0 -1
- package/dist/introspect/index.cjs +0 -22
- package/dist/introspect/index.d.cts +0 -8
- package/dist/introspect/index.d.mts +0 -8
- package/dist/introspect/index.mjs +0 -8
- package/dist/introspect/introspection.cjs +0 -149
- package/dist/introspect/introspection.cjs.map +0 -1
- package/dist/introspect/introspection.d.cts +0 -25
- package/dist/introspect/introspection.d.cts.map +0 -1
- package/dist/introspect/introspection.d.mts +0 -25
- package/dist/introspect/introspection.d.mts.map +0 -1
- package/dist/introspect/introspection.mjs +0 -146
- package/dist/introspect/introspection.mjs.map +0 -1
- package/dist/introspect/types.cjs +0 -24
- package/dist/introspect/types.cjs.map +0 -1
- package/dist/introspect/types.d.cts +0 -113
- package/dist/introspect/types.d.cts.map +0 -1
- package/dist/introspect/types.d.mts +0 -113
- package/dist/introspect/types.d.mts.map +0 -1
- package/dist/introspect/types.mjs +0 -23
- package/dist/introspect/types.mjs.map +0 -1
- package/dist/kysely.cjs.map +0 -1
- package/dist/kysely.d.cts.map +0 -1
- package/dist/kysely.d.mts.map +0 -1
- package/dist/kysely.mjs.map +0 -1
- package/dist/pagination-CrU89125.d.cts.map +0 -1
- package/dist/pagination-CrU89125.d.mts.map +0 -1
- package/dist/pagination.cjs.map +0 -1
- package/dist/pagination.mjs.map +0 -1
- package/dist/pg/roles.cjs +0 -177
- package/dist/pg/roles.cjs.map +0 -1
- package/dist/pg/roles.d.cts +0 -90
- package/dist/pg/roles.d.cts.map +0 -1
- package/dist/pg/roles.d.mts +0 -90
- package/dist/pg/roles.d.mts.map +0 -1
- package/dist/pg/roles.mjs +0 -173
- package/dist/pg/roles.mjs.map +0 -1
- package/dist/pg/url.cjs +0 -48
- package/dist/pg/url.cjs.map +0 -1
- package/dist/pg/url.d.cts +0 -45
- package/dist/pg/url.d.cts.map +0 -1
- package/dist/pg/url.d.mts +0 -45
- package/dist/pg/url.d.mts.map +0 -1
- package/dist/pg/url.mjs +0 -47
- package/dist/pg/url.mjs.map +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Direction,
|
|
1
|
+
import { Direction, decodeCursor, encodeCursor } from "../pagination-BDLa7Yb_.mjs";
|
|
2
|
+
|
|
2
3
|
//#region src/objection/pagination.ts
|
|
3
4
|
/**
|
|
4
5
|
* Cursor-based paginated search for Objection.js models.
|
|
@@ -17,11 +18,11 @@ import { Direction, InvalidCursor, decodeCursor, encodeCursor } from "../paginat
|
|
|
17
18
|
* });
|
|
18
19
|
* ```
|
|
19
20
|
*/
|
|
20
|
-
async function paginatedSearch({ query, cursor, limit = 20, mapRow, cursorField = "id", cursorDirection =
|
|
21
|
+
async function paginatedSearch({ query, cursor, limit = 20, mapRow, cursorField = "id", cursorDirection = Direction.Asc }) {
|
|
21
22
|
const total = await query.resultSize();
|
|
22
23
|
let paginatedQuery = query.clone();
|
|
23
24
|
if (cursor) {
|
|
24
|
-
const operator = cursorDirection ===
|
|
25
|
+
const operator = cursorDirection === Direction.Asc ? ">" : "<";
|
|
25
26
|
paginatedQuery = paginatedQuery.where(cursorField, operator, cursor);
|
|
26
27
|
}
|
|
27
28
|
const data = await paginatedQuery.orderBy(cursorField, cursorDirection).limit(limit + 1);
|
|
@@ -30,8 +31,9 @@ async function paginatedSearch({ query, cursor, limit = 20, mapRow, cursorField
|
|
|
30
31
|
const lastRow = rows[rows.length - 1];
|
|
31
32
|
const nextCursor = hasMore && lastRow ? String(lastRow[cursorField]) : void 0;
|
|
32
33
|
const mapper = mapRow ?? ((row) => row);
|
|
34
|
+
const items = await Promise.all(rows.map(mapper));
|
|
33
35
|
return {
|
|
34
|
-
items
|
|
36
|
+
items,
|
|
35
37
|
pagination: {
|
|
36
38
|
total,
|
|
37
39
|
hasMore,
|
|
@@ -39,7 +41,7 @@ async function paginatedSearch({ query, cursor, limit = 20, mapRow, cursorField
|
|
|
39
41
|
}
|
|
40
42
|
};
|
|
41
43
|
}
|
|
42
|
-
//#endregion
|
|
43
|
-
export { Direction, InvalidCursor, decodeCursor, encodeCursor, paginatedSearch };
|
|
44
44
|
|
|
45
|
+
//#endregion
|
|
46
|
+
export { Direction, decodeCursor, encodeCursor, paginatedSearch };
|
|
45
47
|
//# sourceMappingURL=pagination.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.mjs","names":[],"sources":["../../src/objection/pagination.ts"],"sourcesContent":["import type { Model, QueryBuilder } from 'objection';\nimport {\n\tDirection,\n\tdecodeCursor,\n\tencodeCursor,\n\
|
|
1
|
+
{"version":3,"file":"pagination.mjs","names":["row: TModel"],"sources":["../../src/objection/pagination.ts"],"sourcesContent":["import type { Model, QueryBuilder } from 'objection';\nimport {\n\tDirection,\n\tdecodeCursor,\n\tencodeCursor,\n\ttype PaginationResult,\n} from '../pagination';\n\nexport { Direction, decodeCursor, encodeCursor, type PaginationResult };\n\n/**\n * Options for paginated search with Objection.js models.\n */\nexport interface ObjectionPaginatedSearchOptions<\n\tTModel extends Model,\n\tTMapRow extends (row: TModel) => unknown = (row: TModel) => TModel,\n> {\n\t/** The Objection QueryBuilder to paginate (e.g. User.query(trx).where(...)) */\n\tquery: QueryBuilder<TModel>;\n\t/** Cursor value for pagination (value of cursorField from previous page) */\n\tcursor?: string;\n\t/** Maximum number of items per page (default: 20) */\n\tlimit?: number;\n\t/** Function to transform each row to the output format (default: identity) */\n\tmapRow?: TMapRow;\n\t/** Field to use for cursor pagination (default: 'id') */\n\tcursorField?: string;\n\t/** Sort direction for cursor field (default: Direction.Asc) */\n\tcursorDirection?: Direction;\n}\n\n/**\n * Cursor-based paginated search for Objection.js models.\n *\n * Accepts a pre-built QueryBuilder so callers can apply filters,\n * eager loading, and scopes before pagination is layered on top.\n *\n * @example\n * ```typescript\n * const result = await paginatedSearch({\n * query: User.query(trx).where('orgId', orgId).withGraphFetched('roles'),\n * cursor: previousCursor,\n * limit: 20,\n * cursorField: 'createdAt',\n * cursorDirection: Direction.Desc,\n * });\n * ```\n */\nexport async function paginatedSearch<\n\tTModel extends Model,\n\tTMapRow extends (row: TModel) => unknown = (row: TModel) => TModel,\n>({\n\tquery,\n\tcursor,\n\tlimit = 20,\n\tmapRow,\n\tcursorField = 'id',\n\tcursorDirection = Direction.Asc,\n}: ObjectionPaginatedSearchOptions<TModel, TMapRow>): Promise<\n\tPaginationResult<Awaited<ReturnType<TMapRow>>>\n> {\n\t// Get total count (without cursor filtering)\n\tconst total = await query.resultSize();\n\n\t// Apply cursor if provided\n\tlet paginatedQuery = query.clone();\n\tif (cursor) {\n\t\tconst operator = cursorDirection === Direction.Asc ? '>' : '<';\n\t\tpaginatedQuery = paginatedQuery.where(cursorField, operator, cursor);\n\t}\n\n\t// Fetch one extra to determine if there are more results\n\tconst data = await paginatedQuery\n\t\t.orderBy(cursorField, cursorDirection)\n\t\t.limit(limit + 1);\n\n\tconst hasMore = data.length > limit;\n\tconst rows = hasMore ? data.slice(0, limit) : data;\n\tconst lastRow = rows[rows.length - 1];\n\tconst nextCursor =\n\t\thasMore && lastRow\n\t\t\t? String((lastRow as Record<string, unknown>)[cursorField])\n\t\t\t: undefined;\n\n\tconst mapper = mapRow ?? ((row: TModel) => row);\n\tconst items = (await Promise.all(rows.map(mapper))) as Awaited<\n\t\tReturnType<TMapRow>\n\t>[];\n\n\treturn {\n\t\titems,\n\t\tpagination: {\n\t\t\ttotal,\n\t\t\thasMore,\n\t\t\tcursor: nextCursor,\n\t\t},\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAgDA,eAAsB,gBAGpB,EACD,OACA,QACA,QAAQ,IACR,QACA,cAAc,MACd,kBAAkB,UAAU,KACsB,EAEjD;CAED,MAAM,QAAQ,MAAM,MAAM,YAAY;CAGtC,IAAI,iBAAiB,MAAM,OAAO;AAClC,KAAI,QAAQ;EACX,MAAM,WAAW,oBAAoB,UAAU,MAAM,MAAM;AAC3D,mBAAiB,eAAe,MAAM,aAAa,UAAU,OAAO;CACpE;CAGD,MAAM,OAAO,MAAM,eACjB,QAAQ,aAAa,gBAAgB,CACrC,MAAM,QAAQ,EAAE;CAElB,MAAM,UAAU,KAAK,SAAS;CAC9B,MAAM,OAAO,UAAU,KAAK,MAAM,GAAG,MAAM,GAAG;CAC9C,MAAM,UAAU,KAAK,KAAK,SAAS;CACnC,MAAM,aACL,WAAW,UACR,OAAQ,QAAoC,aAAa;CAG7D,MAAM,SAAS,WAAW,CAACA,QAAgB;CAC3C,MAAM,QAAS,MAAM,QAAQ,IAAI,KAAK,IAAI,OAAO,CAAC;AAIlD,QAAO;EACN;EACA,YAAY;GACX;GACA;GACA,QAAQ;EACR;CACD;AACD"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
declare enum Direction {
|
|
6
6
|
Asc = "asc",
|
|
7
|
-
Desc = "desc"
|
|
7
|
+
Desc = "desc",
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
10
10
|
* Result of a paginated query.
|
|
@@ -26,17 +26,7 @@ declare function encodeCursor(value: unknown): string;
|
|
|
26
26
|
* Decode a cursor string back to its original value.
|
|
27
27
|
*/
|
|
28
28
|
declare function decodeCursor(cursor: string): unknown;
|
|
29
|
-
|
|
30
|
-
* A cursor that did not come from `encodeCursor`.
|
|
31
|
-
*
|
|
32
|
-
* Usually a cursor from a different page size or sort that was edited by hand,
|
|
33
|
-
* or truncated on its way through a URL. The fix is the same either way: start
|
|
34
|
-
* again from the first page.
|
|
35
|
-
*/
|
|
36
|
-
declare class InvalidCursor extends Error {
|
|
37
|
-
readonly cursor: string;
|
|
38
|
-
constructor(cursor: string);
|
|
39
|
-
}
|
|
29
|
+
//# sourceMappingURL=pagination.d.ts.map
|
|
40
30
|
//#endregion
|
|
41
|
-
export {
|
|
42
|
-
//# sourceMappingURL=pagination-
|
|
31
|
+
export { Direction, PaginationResult, decodeCursor, encodeCursor };
|
|
32
|
+
//# sourceMappingURL=pagination-BAFX7C1I.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination-BAFX7C1I.d.cts","names":[],"sources":["../src/pagination.ts"],"sourcesContent":[],"mappings":";;AAGA;AAQA;AAagB,aArBJ,SAAA;EAgCI,GAAA,GAAA,KAAA;;;;;;UAxBC;SACT;;;;;;;;;;;iBAYQ,YAAA;;;;iBAWA,YAAA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//#region src/pagination.ts
|
|
2
|
+
/**
|
|
3
|
+
* Sort direction for cursor-based pagination.
|
|
4
|
+
*/
|
|
5
|
+
let Direction = /* @__PURE__ */ function(Direction$1) {
|
|
6
|
+
Direction$1["Asc"] = "asc";
|
|
7
|
+
Direction$1["Desc"] = "desc";
|
|
8
|
+
return Direction$1;
|
|
9
|
+
}({});
|
|
10
|
+
/**
|
|
11
|
+
* Encode a cursor value for safe URL transmission.
|
|
12
|
+
* Supports various types: string, number, Date, etc.
|
|
13
|
+
*/
|
|
14
|
+
function encodeCursor(value) {
|
|
15
|
+
const payload = {
|
|
16
|
+
v: value instanceof Date ? value.toISOString() : value,
|
|
17
|
+
t: value instanceof Date ? "date" : typeof value
|
|
18
|
+
};
|
|
19
|
+
return Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Decode a cursor string back to its original value.
|
|
23
|
+
*/
|
|
24
|
+
function decodeCursor(cursor) {
|
|
25
|
+
try {
|
|
26
|
+
const json = Buffer.from(cursor, "base64url").toString("utf-8");
|
|
27
|
+
const payload = JSON.parse(json);
|
|
28
|
+
if (payload.t === "date") return new Date(payload.v);
|
|
29
|
+
return payload.v;
|
|
30
|
+
} catch {
|
|
31
|
+
throw new Error("Invalid cursor format");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
export { Direction, decodeCursor, encodeCursor };
|
|
37
|
+
//# sourceMappingURL=pagination-BDLa7Yb_.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination-BDLa7Yb_.mjs","names":["value: unknown","cursor: string"],"sources":["../src/pagination.ts"],"sourcesContent":["/**\n * Sort direction for cursor-based pagination.\n */\nexport enum Direction {\n\tAsc = 'asc',\n\tDesc = 'desc',\n}\n\n/**\n * Result of a paginated query.\n */\nexport interface PaginationResult<TItem> {\n\titems: TItem[];\n\tpagination: {\n\t\ttotal: number;\n\t\thasMore: boolean;\n\t\tcursor?: string;\n\t};\n}\n\n/**\n * Encode a cursor value for safe URL transmission.\n * Supports various types: string, number, Date, etc.\n */\nexport function encodeCursor(value: unknown): string {\n\tconst payload = {\n\t\tv: value instanceof Date ? value.toISOString() : value,\n\t\tt: value instanceof Date ? 'date' : typeof value,\n\t};\n\treturn Buffer.from(JSON.stringify(payload)).toString('base64url');\n}\n\n/**\n * Decode a cursor string back to its original value.\n */\nexport function decodeCursor(cursor: string): unknown {\n\ttry {\n\t\tconst json = Buffer.from(cursor, 'base64url').toString('utf-8');\n\t\tconst payload = JSON.parse(json);\n\n\t\tif (payload.t === 'date') {\n\t\t\treturn new Date(payload.v);\n\t\t}\n\n\t\treturn payload.v;\n\t} catch {\n\t\tthrow new Error('Invalid cursor format');\n\t}\n}\n"],"mappings":";;;;AAGA,IAAY,kDAAL;AACN;AACA;;AACA;;;;;AAkBD,SAAgB,aAAaA,OAAwB;CACpD,MAAM,UAAU;EACf,GAAG,iBAAiB,OAAO,MAAM,aAAa,GAAG;EACjD,GAAG,iBAAiB,OAAO,gBAAgB;CAC3C;AACD,QAAO,OAAO,KAAK,KAAK,UAAU,QAAQ,CAAC,CAAC,SAAS,YAAY;AACjE;;;;AAKD,SAAgB,aAAaC,QAAyB;AACrD,KAAI;EACH,MAAM,OAAO,OAAO,KAAK,QAAQ,YAAY,CAAC,SAAS,QAAQ;EAC/D,MAAM,UAAU,KAAK,MAAM,KAAK;AAEhC,MAAI,QAAQ,MAAM,OACjB,QAAO,IAAI,KAAK,QAAQ;AAGzB,SAAO,QAAQ;CACf,QAAO;AACP,QAAM,IAAI,MAAM;CAChB;AACD"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/pagination.ts
|
|
3
|
+
/**
|
|
4
|
+
* Sort direction for cursor-based pagination.
|
|
5
|
+
*/
|
|
6
|
+
let Direction = /* @__PURE__ */ function(Direction$1) {
|
|
7
|
+
Direction$1["Asc"] = "asc";
|
|
8
|
+
Direction$1["Desc"] = "desc";
|
|
9
|
+
return Direction$1;
|
|
10
|
+
}({});
|
|
11
|
+
/**
|
|
12
|
+
* Encode a cursor value for safe URL transmission.
|
|
13
|
+
* Supports various types: string, number, Date, etc.
|
|
14
|
+
*/
|
|
15
|
+
function encodeCursor(value) {
|
|
16
|
+
const payload = {
|
|
17
|
+
v: value instanceof Date ? value.toISOString() : value,
|
|
18
|
+
t: value instanceof Date ? "date" : typeof value
|
|
19
|
+
};
|
|
20
|
+
return Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Decode a cursor string back to its original value.
|
|
24
|
+
*/
|
|
25
|
+
function decodeCursor(cursor) {
|
|
26
|
+
try {
|
|
27
|
+
const json = Buffer.from(cursor, "base64url").toString("utf-8");
|
|
28
|
+
const payload = JSON.parse(json);
|
|
29
|
+
if (payload.t === "date") return new Date(payload.v);
|
|
30
|
+
return payload.v;
|
|
31
|
+
} catch {
|
|
32
|
+
throw new Error("Invalid cursor format");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
//#endregion
|
|
37
|
+
Object.defineProperty(exports, 'Direction', {
|
|
38
|
+
enumerable: true,
|
|
39
|
+
get: function () {
|
|
40
|
+
return Direction;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
Object.defineProperty(exports, 'decodeCursor', {
|
|
44
|
+
enumerable: true,
|
|
45
|
+
get: function () {
|
|
46
|
+
return decodeCursor;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
Object.defineProperty(exports, 'encodeCursor', {
|
|
50
|
+
enumerable: true,
|
|
51
|
+
get: function () {
|
|
52
|
+
return encodeCursor;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
//# sourceMappingURL=pagination-Bdoa4PVj.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination-Bdoa4PVj.cjs","names":["value: unknown","cursor: string"],"sources":["../src/pagination.ts"],"sourcesContent":["/**\n * Sort direction for cursor-based pagination.\n */\nexport enum Direction {\n\tAsc = 'asc',\n\tDesc = 'desc',\n}\n\n/**\n * Result of a paginated query.\n */\nexport interface PaginationResult<TItem> {\n\titems: TItem[];\n\tpagination: {\n\t\ttotal: number;\n\t\thasMore: boolean;\n\t\tcursor?: string;\n\t};\n}\n\n/**\n * Encode a cursor value for safe URL transmission.\n * Supports various types: string, number, Date, etc.\n */\nexport function encodeCursor(value: unknown): string {\n\tconst payload = {\n\t\tv: value instanceof Date ? value.toISOString() : value,\n\t\tt: value instanceof Date ? 'date' : typeof value,\n\t};\n\treturn Buffer.from(JSON.stringify(payload)).toString('base64url');\n}\n\n/**\n * Decode a cursor string back to its original value.\n */\nexport function decodeCursor(cursor: string): unknown {\n\ttry {\n\t\tconst json = Buffer.from(cursor, 'base64url').toString('utf-8');\n\t\tconst payload = JSON.parse(json);\n\n\t\tif (payload.t === 'date') {\n\t\t\treturn new Date(payload.v);\n\t\t}\n\n\t\treturn payload.v;\n\t} catch {\n\t\tthrow new Error('Invalid cursor format');\n\t}\n}\n"],"mappings":";;;;;AAGA,IAAY,kDAAL;AACN;AACA;;AACA;;;;;AAkBD,SAAgB,aAAaA,OAAwB;CACpD,MAAM,UAAU;EACf,GAAG,iBAAiB,OAAO,MAAM,aAAa,GAAG;EACjD,GAAG,iBAAiB,OAAO,gBAAgB;CAC3C;AACD,QAAO,OAAO,KAAK,KAAK,UAAU,QAAQ,CAAC,CAAC,SAAS,YAAY;AACjE;;;;AAKD,SAAgB,aAAaC,QAAyB;AACrD,KAAI;EACH,MAAM,OAAO,OAAO,KAAK,QAAQ,YAAY,CAAC,SAAS,QAAQ;EAC/D,MAAM,UAAU,KAAK,MAAM,KAAK;AAEhC,MAAI,QAAQ,MAAM,OACjB,QAAO,IAAI,KAAK,QAAQ;AAGzB,SAAO,QAAQ;CACf,QAAO;AACP,QAAM,IAAI,MAAM;CAChB;AACD"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
declare enum Direction {
|
|
6
6
|
Asc = "asc",
|
|
7
|
-
Desc = "desc"
|
|
7
|
+
Desc = "desc",
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
10
10
|
* Result of a paginated query.
|
|
@@ -26,17 +26,7 @@ declare function encodeCursor(value: unknown): string;
|
|
|
26
26
|
* Decode a cursor string back to its original value.
|
|
27
27
|
*/
|
|
28
28
|
declare function decodeCursor(cursor: string): unknown;
|
|
29
|
-
|
|
30
|
-
* A cursor that did not come from `encodeCursor`.
|
|
31
|
-
*
|
|
32
|
-
* Usually a cursor from a different page size or sort that was edited by hand,
|
|
33
|
-
* or truncated on its way through a URL. The fix is the same either way: start
|
|
34
|
-
* again from the first page.
|
|
35
|
-
*/
|
|
36
|
-
declare class InvalidCursor extends Error {
|
|
37
|
-
readonly cursor: string;
|
|
38
|
-
constructor(cursor: string);
|
|
39
|
-
}
|
|
29
|
+
//# sourceMappingURL=pagination.d.ts.map
|
|
40
30
|
//#endregion
|
|
41
|
-
export {
|
|
42
|
-
//# sourceMappingURL=pagination-
|
|
31
|
+
export { Direction, PaginationResult, decodeCursor, encodeCursor };
|
|
32
|
+
//# sourceMappingURL=pagination-BziGl-B8.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination-BziGl-B8.d.mts","names":[],"sources":["../src/pagination.ts"],"sourcesContent":[],"mappings":";;AAGA;AAQA;AAagB,aArBJ,SAAA;EAgCI,GAAA,GAAA,KAAA;;;;;;UAxBC;SACT;;;;;;;;;;;iBAYQ,YAAA;;;;iBAWA,YAAA"}
|
package/dist/pagination.cjs
CHANGED
|
@@ -1,56 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
//#region src/pagination.ts
|
|
3
|
-
/**
|
|
4
|
-
* Sort direction for cursor-based pagination.
|
|
5
|
-
*/
|
|
6
|
-
let Direction = /* @__PURE__ */ function(Direction) {
|
|
7
|
-
Direction["Asc"] = "asc";
|
|
8
|
-
Direction["Desc"] = "desc";
|
|
9
|
-
return Direction;
|
|
10
|
-
}({});
|
|
11
|
-
/**
|
|
12
|
-
* Encode a cursor value for safe URL transmission.
|
|
13
|
-
* Supports various types: string, number, Date, etc.
|
|
14
|
-
*/
|
|
15
|
-
function encodeCursor(value) {
|
|
16
|
-
const payload = {
|
|
17
|
-
v: value instanceof Date ? value.toISOString() : value,
|
|
18
|
-
t: value instanceof Date ? "date" : typeof value
|
|
19
|
-
};
|
|
20
|
-
return Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Decode a cursor string back to its original value.
|
|
24
|
-
*/
|
|
25
|
-
function decodeCursor(cursor) {
|
|
26
|
-
try {
|
|
27
|
-
const json = Buffer.from(cursor, "base64url").toString("utf-8");
|
|
28
|
-
const payload = JSON.parse(json);
|
|
29
|
-
if (payload.t === "date") return new Date(payload.v);
|
|
30
|
-
return payload.v;
|
|
31
|
-
} catch {
|
|
32
|
-
throw new InvalidCursor(cursor);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* A cursor that did not come from `encodeCursor`.
|
|
37
|
-
*
|
|
38
|
-
* Usually a cursor from a different page size or sort that was edited by hand,
|
|
39
|
-
* or truncated on its way through a URL. The fix is the same either way: start
|
|
40
|
-
* again from the first page.
|
|
41
|
-
*/
|
|
42
|
-
var InvalidCursor = class extends Error {
|
|
43
|
-
cursor;
|
|
44
|
-
constructor(cursor) {
|
|
45
|
-
super("This cursor was not produced by encodeCursor. Drop it and request the first page again.");
|
|
46
|
-
this.cursor = cursor;
|
|
47
|
-
this.name = "InvalidCursor";
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
//#endregion
|
|
51
|
-
exports.Direction = Direction;
|
|
52
|
-
exports.InvalidCursor = InvalidCursor;
|
|
53
|
-
exports.decodeCursor = decodeCursor;
|
|
54
|
-
exports.encodeCursor = encodeCursor;
|
|
1
|
+
const require_pagination = require('./pagination-Bdoa4PVj.cjs');
|
|
55
2
|
|
|
56
|
-
|
|
3
|
+
exports.Direction = require_pagination.Direction;
|
|
4
|
+
exports.decodeCursor = require_pagination.decodeCursor;
|
|
5
|
+
exports.encodeCursor = require_pagination.encodeCursor;
|
package/dist/pagination.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { Direction,
|
|
1
|
+
import { Direction, PaginationResult, decodeCursor, encodeCursor } from "./pagination-BAFX7C1I.cjs";
|
|
2
|
+
export { Direction, PaginationResult, decodeCursor, encodeCursor };
|
package/dist/pagination.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { Direction,
|
|
1
|
+
import { Direction, PaginationResult, decodeCursor, encodeCursor } from "./pagination-BziGl-B8.mjs";
|
|
2
|
+
export { Direction, PaginationResult, decodeCursor, encodeCursor };
|
package/dist/pagination.mjs
CHANGED
|
@@ -1,52 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* Sort direction for cursor-based pagination.
|
|
4
|
-
*/
|
|
5
|
-
let Direction = /* @__PURE__ */ function(Direction) {
|
|
6
|
-
Direction["Asc"] = "asc";
|
|
7
|
-
Direction["Desc"] = "desc";
|
|
8
|
-
return Direction;
|
|
9
|
-
}({});
|
|
10
|
-
/**
|
|
11
|
-
* Encode a cursor value for safe URL transmission.
|
|
12
|
-
* Supports various types: string, number, Date, etc.
|
|
13
|
-
*/
|
|
14
|
-
function encodeCursor(value) {
|
|
15
|
-
const payload = {
|
|
16
|
-
v: value instanceof Date ? value.toISOString() : value,
|
|
17
|
-
t: value instanceof Date ? "date" : typeof value
|
|
18
|
-
};
|
|
19
|
-
return Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Decode a cursor string back to its original value.
|
|
23
|
-
*/
|
|
24
|
-
function decodeCursor(cursor) {
|
|
25
|
-
try {
|
|
26
|
-
const json = Buffer.from(cursor, "base64url").toString("utf-8");
|
|
27
|
-
const payload = JSON.parse(json);
|
|
28
|
-
if (payload.t === "date") return new Date(payload.v);
|
|
29
|
-
return payload.v;
|
|
30
|
-
} catch {
|
|
31
|
-
throw new InvalidCursor(cursor);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* A cursor that did not come from `encodeCursor`.
|
|
36
|
-
*
|
|
37
|
-
* Usually a cursor from a different page size or sort that was edited by hand,
|
|
38
|
-
* or truncated on its way through a URL. The fix is the same either way: start
|
|
39
|
-
* again from the first page.
|
|
40
|
-
*/
|
|
41
|
-
var InvalidCursor = class extends Error {
|
|
42
|
-
cursor;
|
|
43
|
-
constructor(cursor) {
|
|
44
|
-
super("This cursor was not produced by encodeCursor. Drop it and request the first page again.");
|
|
45
|
-
this.cursor = cursor;
|
|
46
|
-
this.name = "InvalidCursor";
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
//#endregion
|
|
50
|
-
export { Direction, InvalidCursor, decodeCursor, encodeCursor };
|
|
1
|
+
import { Direction, decodeCursor, encodeCursor } from "./pagination-BDLa7Yb_.mjs";
|
|
51
2
|
|
|
52
|
-
|
|
3
|
+
export { Direction, decodeCursor, encodeCursor };
|
package/dist/rls.cjs
CHANGED
|
@@ -1,6 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
const require_kysely = require('./kysely-8WPSKCZG.cjs');
|
|
25
|
+
const kysely = __toESM(require("kysely"));
|
|
26
|
+
|
|
4
27
|
//#region src/rls.ts
|
|
5
28
|
/**
|
|
6
29
|
* Execute a callback within a transaction with RLS context variables set.
|
|
@@ -32,7 +55,8 @@ async function withRlsContext(db, context, callback, options) {
|
|
|
32
55
|
for (const [key, value] of Object.entries(context)) {
|
|
33
56
|
if (value === null || value === void 0) continue;
|
|
34
57
|
const settingName = `${prefix}.${key}`;
|
|
35
|
-
|
|
58
|
+
const settingValue = String(value);
|
|
59
|
+
await kysely.sql`SELECT set_config(${settingName}, ${settingValue}, true)`.execute(trx);
|
|
36
60
|
}
|
|
37
61
|
return callback(trx);
|
|
38
62
|
}, options?.settings);
|
|
@@ -41,8 +65,8 @@ async function withRlsContext(db, context, callback, options) {
|
|
|
41
65
|
* Bypass marker symbol for explicitly skipping RLS context.
|
|
42
66
|
*/
|
|
43
67
|
const RLS_BYPASS = Symbol.for("geekmidas.rls.bypass");
|
|
68
|
+
|
|
44
69
|
//#endregion
|
|
45
70
|
exports.RLS_BYPASS = RLS_BYPASS;
|
|
46
71
|
exports.withRlsContext = withRlsContext;
|
|
47
|
-
|
|
48
72
|
//# sourceMappingURL=rls.cjs.map
|
package/dist/rls.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rls.cjs","names":["
|
|
1
|
+
{"version":3,"file":"rls.cjs","names":["db: DatabaseConnection<DB>","context: RlsContext","callback: (trx: Transaction<DB>) => Promise<T>","options?: WithRlsContextOptions"],"sources":["../src/rls.ts"],"sourcesContent":["import type { Transaction } from 'kysely';\nimport { sql } from 'kysely';\nimport {\n\ttype DatabaseConnection,\n\ttype TransactionSettings,\n\twithTransaction,\n} from './kysely';\n\n/**\n * RLS context - key-value pairs to set as PostgreSQL session variables.\n * Keys become `prefix.key` (e.g., `app.user_id`).\n */\nexport interface RlsContext {\n\t[key: string]: string | number | boolean | null | undefined;\n}\n\n/**\n * Options for withRlsContext function.\n */\nexport interface WithRlsContextOptions {\n\t/** Prefix for PostgreSQL session variables (default: 'app') */\n\tprefix?: string;\n\t/** Transaction settings (isolation level) */\n\tsettings?: TransactionSettings;\n}\n\n/**\n * Execute a callback within a transaction with RLS context variables set.\n *\n * Sets PostgreSQL session variables using `SET LOCAL` which scopes them to the\n * current transaction. Variables are automatically cleared when the transaction\n * ends (commit or rollback).\n *\n * @example\n * ```ts\n * await withRlsContext(\n * db,\n * { user_id: session.userId, tenant_id: session.tenantId },\n * async (trx) => {\n * // RLS policies can now use current_setting('app.user_id')\n * return trx.selectFrom('orders').selectAll().execute();\n * }\n * );\n * ```\n *\n * @param db - Database connection (Kysely, Transaction, or ControlledTransaction)\n * @param context - Key-value pairs to set as session variables\n * @param callback - Function to execute within the RLS context\n * @param options - Optional prefix and transaction settings\n */\nexport async function withRlsContext<DB, T>(\n\tdb: DatabaseConnection<DB>,\n\tcontext: RlsContext,\n\tcallback: (trx: Transaction<DB>) => Promise<T>,\n\toptions?: WithRlsContextOptions,\n): Promise<T> {\n\tconst prefix = options?.prefix ?? 'app';\n\n\treturn withTransaction(\n\t\tdb,\n\t\tasync (trx) => {\n\t\t\t// Set each context variable using SET LOCAL (scoped to transaction)\n\t\t\tfor (const [key, value] of Object.entries(context)) {\n\t\t\t\tif (value === null || value === undefined) continue;\n\n\t\t\t\tconst settingName = `${prefix}.${key}`;\n\t\t\t\tconst settingValue = String(value);\n\n\t\t\t\t// Use raw SQL for SET LOCAL with proper escaping\n\t\t\t\t// The setting name is an identifier, value is a string literal\n\t\t\t\tawait sql`SELECT set_config(${settingName}, ${settingValue}, true)`.execute(\n\t\t\t\t\ttrx,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn callback(trx);\n\t\t},\n\t\toptions?.settings,\n\t);\n}\n\n/**\n * Bypass marker symbol for explicitly skipping RLS context.\n */\nexport const RLS_BYPASS = Symbol.for('geekmidas.rls.bypass');\n\n/**\n * Type for RLS bypass marker.\n */\nexport type RlsBypass = typeof RLS_BYPASS;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDA,eAAsB,eACrBA,IACAC,SACAC,UACAC,SACa;CACb,MAAM,SAAS,SAAS,UAAU;AAElC,QAAO,+BACN,IACA,OAAO,QAAQ;AAEd,OAAK,MAAM,CAAC,KAAK,MAAM,IAAI,OAAO,QAAQ,QAAQ,EAAE;AACnD,OAAI,UAAU,QAAQ,iBAAqB;GAE3C,MAAM,eAAe,EAAE,OAAO,GAAG,IAAI;GACrC,MAAM,eAAe,OAAO,MAAM;AAIlC,SAAM,WAAI,oBAAoB,YAAY,IAAI,aAAa,SAAS,QACnE,IACA;EACD;AAED,SAAO,SAAS,IAAI;CACpB,GACD,SAAS,SACT;AACD;;;;AAKD,MAAa,aAAa,OAAO,IAAI,uBAAuB"}
|
package/dist/rls.d.cts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import { DatabaseConnection, TransactionSettings } from "./kysely.cjs";
|
|
1
|
+
import { DatabaseConnection, TransactionSettings } from "./kysely-D3eeuId4.cjs";
|
|
2
2
|
import { Transaction } from "kysely";
|
|
3
|
+
|
|
3
4
|
//#region src/rls.d.ts
|
|
5
|
+
|
|
4
6
|
/**
|
|
5
7
|
* RLS context - key-value pairs to set as PostgreSQL session variables.
|
|
6
8
|
* Keys become `prefix.key` (e.g., `app.user_id`).
|
|
7
9
|
*/
|
|
8
|
-
|
|
10
|
+
interface RlsContext {
|
|
9
11
|
[key: string]: string | number | boolean | null | undefined;
|
|
10
12
|
}
|
|
11
13
|
/**
|
|
12
14
|
* Options for withRlsContext function.
|
|
13
15
|
*/
|
|
14
|
-
|
|
16
|
+
interface WithRlsContextOptions {
|
|
15
17
|
/** Prefix for PostgreSQL session variables (default: 'app') */
|
|
16
18
|
prefix?: string;
|
|
17
19
|
/** Transaction settings (isolation level) */
|
|
@@ -41,14 +43,16 @@ export interface WithRlsContextOptions {
|
|
|
41
43
|
* @param callback - Function to execute within the RLS context
|
|
42
44
|
* @param options - Optional prefix and transaction settings
|
|
43
45
|
*/
|
|
44
|
-
|
|
46
|
+
declare function withRlsContext<DB, T>(db: DatabaseConnection<DB>, context: RlsContext, callback: (trx: Transaction<DB>) => Promise<T>, options?: WithRlsContextOptions): Promise<T>;
|
|
45
47
|
/**
|
|
46
48
|
* Bypass marker symbol for explicitly skipping RLS context.
|
|
47
49
|
*/
|
|
48
|
-
|
|
50
|
+
declare const RLS_BYPASS: unique symbol;
|
|
49
51
|
/**
|
|
50
52
|
* Type for RLS bypass marker.
|
|
51
53
|
*/
|
|
52
|
-
|
|
54
|
+
type RlsBypass = typeof RLS_BYPASS;
|
|
55
|
+
//# sourceMappingURL=rls.d.ts.map
|
|
53
56
|
//#endregion
|
|
57
|
+
export { RLS_BYPASS, RlsBypass, RlsContext, WithRlsContextOptions, withRlsContext };
|
|
54
58
|
//# sourceMappingURL=rls.d.cts.map
|
package/dist/rls.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rls.d.cts","names":[],"sources":["../src/rls.ts"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"rls.d.cts","names":[],"sources":["../src/rls.ts"],"sourcesContent":[],"mappings":";;;;;;;AAYA;AAOA;AA+BsB,UAtCL,UAAA,CAsCmB;EAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,MAAA,GAAA,MAAA,GAAA,OAAA,GAAA,IAAA,GAAA,SAAA;;;;;AAGnB,UAlCA,qBAAA,CAkCA;EAAW;EAAkB,MAAT,CAAA,EAAA,MAAA;EAAO;EACZ,QACrB,CAAA,EAhCC,mBAgCD;;AAAD;AA6BV;AAKA;;;;;;;;;;;;;;;;;;;;;;iBAvCsB,0BACjB,mBAAmB,cACd,4BACO,YAAY,QAAQ,QAAQ,cAClC,wBACR,QAAQ;;;;cA6BE;;;;KAKD,SAAA,UAAmB"}
|
package/dist/rls.d.mts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import { DatabaseConnection, TransactionSettings } from "./kysely.mjs";
|
|
1
|
+
import { DatabaseConnection, TransactionSettings } from "./kysely-Dm1w5gAY.mjs";
|
|
2
2
|
import { Transaction } from "kysely";
|
|
3
|
+
|
|
3
4
|
//#region src/rls.d.ts
|
|
5
|
+
|
|
4
6
|
/**
|
|
5
7
|
* RLS context - key-value pairs to set as PostgreSQL session variables.
|
|
6
8
|
* Keys become `prefix.key` (e.g., `app.user_id`).
|
|
7
9
|
*/
|
|
8
|
-
|
|
10
|
+
interface RlsContext {
|
|
9
11
|
[key: string]: string | number | boolean | null | undefined;
|
|
10
12
|
}
|
|
11
13
|
/**
|
|
12
14
|
* Options for withRlsContext function.
|
|
13
15
|
*/
|
|
14
|
-
|
|
16
|
+
interface WithRlsContextOptions {
|
|
15
17
|
/** Prefix for PostgreSQL session variables (default: 'app') */
|
|
16
18
|
prefix?: string;
|
|
17
19
|
/** Transaction settings (isolation level) */
|
|
@@ -41,14 +43,16 @@ export interface WithRlsContextOptions {
|
|
|
41
43
|
* @param callback - Function to execute within the RLS context
|
|
42
44
|
* @param options - Optional prefix and transaction settings
|
|
43
45
|
*/
|
|
44
|
-
|
|
46
|
+
declare function withRlsContext<DB, T>(db: DatabaseConnection<DB>, context: RlsContext, callback: (trx: Transaction<DB>) => Promise<T>, options?: WithRlsContextOptions): Promise<T>;
|
|
45
47
|
/**
|
|
46
48
|
* Bypass marker symbol for explicitly skipping RLS context.
|
|
47
49
|
*/
|
|
48
|
-
|
|
50
|
+
declare const RLS_BYPASS: unique symbol;
|
|
49
51
|
/**
|
|
50
52
|
* Type for RLS bypass marker.
|
|
51
53
|
*/
|
|
52
|
-
|
|
54
|
+
type RlsBypass = typeof RLS_BYPASS;
|
|
55
|
+
//# sourceMappingURL=rls.d.ts.map
|
|
53
56
|
//#endregion
|
|
57
|
+
export { RLS_BYPASS, RlsBypass, RlsContext, WithRlsContextOptions, withRlsContext };
|
|
54
58
|
//# sourceMappingURL=rls.d.mts.map
|
package/dist/rls.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rls.d.mts","names":[],"sources":["../src/rls.ts"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"rls.d.mts","names":[],"sources":["../src/rls.ts"],"sourcesContent":[],"mappings":";;;;;;;AAYA;AAOA;AA+BsB,UAtCL,UAAA,CAsCmB;EAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,MAAA,GAAA,MAAA,GAAA,OAAA,GAAA,IAAA,GAAA,SAAA;;;;;AAGnB,UAlCA,qBAAA,CAkCA;EAAW;EAAkB,MAAT,CAAA,EAAA,MAAA;EAAO;EACZ,QACrB,CAAA,EAhCC,mBAgCD;;AAAD;AA6BV;AAKA;;;;;;;;;;;;;;;;;;;;;;iBAvCsB,0BACjB,mBAAmB,cACd,4BACO,YAAY,QAAQ,QAAQ,cAClC,wBACR,QAAQ;;;;cA6BE;;;;KAKD,SAAA,UAAmB"}
|
package/dist/rls.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { withTransaction } from "./kysely.mjs";
|
|
1
|
+
import { withTransaction } from "./kysely-DmfA94RY.mjs";
|
|
2
2
|
import { sql } from "kysely";
|
|
3
|
+
|
|
3
4
|
//#region src/rls.ts
|
|
4
5
|
/**
|
|
5
6
|
* Execute a callback within a transaction with RLS context variables set.
|
|
@@ -31,7 +32,8 @@ async function withRlsContext(db, context, callback, options) {
|
|
|
31
32
|
for (const [key, value] of Object.entries(context)) {
|
|
32
33
|
if (value === null || value === void 0) continue;
|
|
33
34
|
const settingName = `${prefix}.${key}`;
|
|
34
|
-
|
|
35
|
+
const settingValue = String(value);
|
|
36
|
+
await sql`SELECT set_config(${settingName}, ${settingValue}, true)`.execute(trx);
|
|
35
37
|
}
|
|
36
38
|
return callback(trx);
|
|
37
39
|
}, options?.settings);
|
|
@@ -40,7 +42,7 @@ async function withRlsContext(db, context, callback, options) {
|
|
|
40
42
|
* Bypass marker symbol for explicitly skipping RLS context.
|
|
41
43
|
*/
|
|
42
44
|
const RLS_BYPASS = Symbol.for("geekmidas.rls.bypass");
|
|
45
|
+
|
|
43
46
|
//#endregion
|
|
44
47
|
export { RLS_BYPASS, withRlsContext };
|
|
45
|
-
|
|
46
48
|
//# sourceMappingURL=rls.mjs.map
|
package/dist/rls.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rls.mjs","names":[],"sources":["../src/rls.ts"],"sourcesContent":["import type { Transaction } from 'kysely';\nimport { sql } from 'kysely';\nimport {\n\ttype DatabaseConnection,\n\ttype TransactionSettings,\n\twithTransaction,\n} from './kysely';\n\n/**\n * RLS context - key-value pairs to set as PostgreSQL session variables.\n * Keys become `prefix.key` (e.g., `app.user_id`).\n */\nexport interface RlsContext {\n\t[key: string]: string | number | boolean | null | undefined;\n}\n\n/**\n * Options for withRlsContext function.\n */\nexport interface WithRlsContextOptions {\n\t/** Prefix for PostgreSQL session variables (default: 'app') */\n\tprefix?: string;\n\t/** Transaction settings (isolation level) */\n\tsettings?: TransactionSettings;\n}\n\n/**\n * Execute a callback within a transaction with RLS context variables set.\n *\n * Sets PostgreSQL session variables using `SET LOCAL` which scopes them to the\n * current transaction. Variables are automatically cleared when the transaction\n * ends (commit or rollback).\n *\n * @example\n * ```ts\n * await withRlsContext(\n * db,\n * { user_id: session.userId, tenant_id: session.tenantId },\n * async (trx) => {\n * // RLS policies can now use current_setting('app.user_id')\n * return trx.selectFrom('orders').selectAll().execute();\n * }\n * );\n * ```\n *\n * @param db - Database connection (Kysely, Transaction, or ControlledTransaction)\n * @param context - Key-value pairs to set as session variables\n * @param callback - Function to execute within the RLS context\n * @param options - Optional prefix and transaction settings\n */\nexport async function withRlsContext<DB, T>(\n\tdb: DatabaseConnection<DB>,\n\tcontext: RlsContext,\n\tcallback: (trx: Transaction<DB>) => Promise<T>,\n\toptions?: WithRlsContextOptions,\n): Promise<T> {\n\tconst prefix = options?.prefix ?? 'app';\n\n\treturn withTransaction(\n\t\tdb,\n\t\tasync (trx) => {\n\t\t\t// Set each context variable using SET LOCAL (scoped to transaction)\n\t\t\tfor (const [key, value] of Object.entries(context)) {\n\t\t\t\tif (value === null || value === undefined) continue;\n\n\t\t\t\tconst settingName = `${prefix}.${key}`;\n\t\t\t\tconst settingValue = String(value);\n\n\t\t\t\t// Use raw SQL for SET LOCAL with proper escaping\n\t\t\t\t// The setting name is an identifier, value is a string literal\n\t\t\t\tawait sql`SELECT set_config(${settingName}, ${settingValue}, true)`.execute(\n\t\t\t\t\ttrx,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn callback(trx);\n\t\t},\n\t\toptions?.settings,\n\t);\n}\n\n/**\n * Bypass marker symbol for explicitly skipping RLS context.\n */\nexport const RLS_BYPASS = Symbol.for('geekmidas.rls.bypass');\n\n/**\n * Type for RLS bypass marker.\n */\nexport type RlsBypass = typeof RLS_BYPASS;\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"rls.mjs","names":["db: DatabaseConnection<DB>","context: RlsContext","callback: (trx: Transaction<DB>) => Promise<T>","options?: WithRlsContextOptions"],"sources":["../src/rls.ts"],"sourcesContent":["import type { Transaction } from 'kysely';\nimport { sql } from 'kysely';\nimport {\n\ttype DatabaseConnection,\n\ttype TransactionSettings,\n\twithTransaction,\n} from './kysely';\n\n/**\n * RLS context - key-value pairs to set as PostgreSQL session variables.\n * Keys become `prefix.key` (e.g., `app.user_id`).\n */\nexport interface RlsContext {\n\t[key: string]: string | number | boolean | null | undefined;\n}\n\n/**\n * Options for withRlsContext function.\n */\nexport interface WithRlsContextOptions {\n\t/** Prefix for PostgreSQL session variables (default: 'app') */\n\tprefix?: string;\n\t/** Transaction settings (isolation level) */\n\tsettings?: TransactionSettings;\n}\n\n/**\n * Execute a callback within a transaction with RLS context variables set.\n *\n * Sets PostgreSQL session variables using `SET LOCAL` which scopes them to the\n * current transaction. Variables are automatically cleared when the transaction\n * ends (commit or rollback).\n *\n * @example\n * ```ts\n * await withRlsContext(\n * db,\n * { user_id: session.userId, tenant_id: session.tenantId },\n * async (trx) => {\n * // RLS policies can now use current_setting('app.user_id')\n * return trx.selectFrom('orders').selectAll().execute();\n * }\n * );\n * ```\n *\n * @param db - Database connection (Kysely, Transaction, or ControlledTransaction)\n * @param context - Key-value pairs to set as session variables\n * @param callback - Function to execute within the RLS context\n * @param options - Optional prefix and transaction settings\n */\nexport async function withRlsContext<DB, T>(\n\tdb: DatabaseConnection<DB>,\n\tcontext: RlsContext,\n\tcallback: (trx: Transaction<DB>) => Promise<T>,\n\toptions?: WithRlsContextOptions,\n): Promise<T> {\n\tconst prefix = options?.prefix ?? 'app';\n\n\treturn withTransaction(\n\t\tdb,\n\t\tasync (trx) => {\n\t\t\t// Set each context variable using SET LOCAL (scoped to transaction)\n\t\t\tfor (const [key, value] of Object.entries(context)) {\n\t\t\t\tif (value === null || value === undefined) continue;\n\n\t\t\t\tconst settingName = `${prefix}.${key}`;\n\t\t\t\tconst settingValue = String(value);\n\n\t\t\t\t// Use raw SQL for SET LOCAL with proper escaping\n\t\t\t\t// The setting name is an identifier, value is a string literal\n\t\t\t\tawait sql`SELECT set_config(${settingName}, ${settingValue}, true)`.execute(\n\t\t\t\t\ttrx,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn callback(trx);\n\t\t},\n\t\toptions?.settings,\n\t);\n}\n\n/**\n * Bypass marker symbol for explicitly skipping RLS context.\n */\nexport const RLS_BYPASS = Symbol.for('geekmidas.rls.bypass');\n\n/**\n * Type for RLS bypass marker.\n */\nexport type RlsBypass = typeof RLS_BYPASS;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDA,eAAsB,eACrBA,IACAC,SACAC,UACAC,SACa;CACb,MAAM,SAAS,SAAS,UAAU;AAElC,QAAO,gBACN,IACA,OAAO,QAAQ;AAEd,OAAK,MAAM,CAAC,KAAK,MAAM,IAAI,OAAO,QAAQ,QAAQ,EAAE;AACnD,OAAI,UAAU,QAAQ,iBAAqB;GAE3C,MAAM,eAAe,EAAE,OAAO,GAAG,IAAI;GACrC,MAAM,eAAe,OAAO,MAAM;AAIlC,SAAM,IAAI,oBAAoB,YAAY,IAAI,aAAa,SAAS,QACnE,IACA;EACD;AAED,SAAO,SAAS,IAAI;CACpB,GACD,SAAS,SACT;AACD;;;;AAKD,MAAa,aAAa,OAAO,IAAI,uBAAuB"}
|