@gencow/core 0.1.23 → 0.1.25

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.
Files changed (77) hide show
  1. package/dist/crud.d.ts +2 -2
  2. package/dist/crud.js +225 -208
  3. package/dist/index.d.ts +7 -3
  4. package/dist/index.js +4 -1
  5. package/dist/reactive.js +10 -3
  6. package/dist/retry.js +1 -1
  7. package/dist/rls-db.d.ts +2 -2
  8. package/dist/rls-db.js +1 -5
  9. package/dist/scheduler.d.ts +2 -0
  10. package/dist/scheduler.js +16 -6
  11. package/dist/server.d.ts +0 -1
  12. package/dist/server.js +0 -1
  13. package/dist/storage.js +29 -22
  14. package/dist/v.d.ts +2 -2
  15. package/dist/workflow-types.d.ts +81 -0
  16. package/dist/workflow-types.js +12 -0
  17. package/dist/workflow.d.ts +30 -0
  18. package/dist/workflow.js +150 -0
  19. package/dist/workflows-api.d.ts +13 -0
  20. package/dist/workflows-api.js +321 -0
  21. package/package.json +46 -42
  22. package/src/__tests__/auth.test.ts +90 -86
  23. package/src/__tests__/crons.test.ts +69 -67
  24. package/src/__tests__/crud-codegen-integration.test.ts +164 -170
  25. package/src/__tests__/crud-owner-rls.test.ts +308 -301
  26. package/src/__tests__/crud.test.ts +694 -711
  27. package/src/__tests__/dist-exports.test.ts +120 -114
  28. package/src/__tests__/fixtures/basic/auth.ts +16 -16
  29. package/src/__tests__/fixtures/basic/drizzle.config.ts +1 -4
  30. package/src/__tests__/fixtures/basic/index.ts +1 -1
  31. package/src/__tests__/fixtures/basic/schema.ts +1 -1
  32. package/src/__tests__/fixtures/basic/tasks.ts +4 -4
  33. package/src/__tests__/fixtures/common/auth-schema.ts +38 -34
  34. package/src/__tests__/helpers/basic-rls-fixture.ts +80 -78
  35. package/src/__tests__/helpers/pglite-migrations.ts +2 -5
  36. package/src/__tests__/helpers/pglite-rls-session.ts +13 -16
  37. package/src/__tests__/helpers/seed-like-fill.ts +50 -44
  38. package/src/__tests__/helpers/test-gencow-ctx-rls.ts +4 -7
  39. package/src/__tests__/httpaction.test.ts +91 -91
  40. package/src/__tests__/image-optimization.test.ts +570 -574
  41. package/src/__tests__/load.test.ts +321 -308
  42. package/src/__tests__/network-sim.test.ts +238 -215
  43. package/src/__tests__/reactive.test.ts +380 -358
  44. package/src/__tests__/retry.test.ts +99 -84
  45. package/src/__tests__/rls-crud-basic.test.ts +172 -245
  46. package/src/__tests__/rls-crud-no-owner-rls-pglite.test.ts +81 -81
  47. package/src/__tests__/rls-custom-mutation-handlers.test.ts +47 -94
  48. package/src/__tests__/rls-custom-query-handlers.test.ts +92 -92
  49. package/src/__tests__/rls-db-leased-connection.test.ts +2 -6
  50. package/src/__tests__/rls-session-and-policies.test.ts +181 -199
  51. package/src/__tests__/scheduler-durable-v2.test.ts +199 -181
  52. package/src/__tests__/scheduler-durable.test.ts +117 -117
  53. package/src/__tests__/scheduler-exec.test.ts +258 -246
  54. package/src/__tests__/scheduler.test.ts +129 -111
  55. package/src/__tests__/storage.test.ts +282 -269
  56. package/src/__tests__/tsconfig.json +6 -6
  57. package/src/__tests__/validator.test.ts +236 -232
  58. package/src/__tests__/workflow.test.ts +606 -0
  59. package/src/__tests__/ws-integration.test.ts +223 -218
  60. package/src/__tests__/ws-scale.test.ts +168 -159
  61. package/src/auth-config.ts +18 -18
  62. package/src/auth.ts +106 -106
  63. package/src/crons.ts +77 -77
  64. package/src/crud.ts +523 -479
  65. package/src/index.ts +71 -6
  66. package/src/reactive.ts +357 -331
  67. package/src/retry.ts +51 -54
  68. package/src/rls-db.ts +195 -205
  69. package/src/rls.ts +33 -36
  70. package/src/scheduler.ts +237 -211
  71. package/src/server.ts +0 -1
  72. package/src/storage.ts +632 -593
  73. package/src/v.ts +119 -114
  74. package/src/workflow-types.ts +108 -0
  75. package/src/workflow.ts +188 -0
  76. package/src/workflows-api.ts +415 -0
  77. package/src/db.ts +0 -18
package/src/retry.ts CHANGED
@@ -29,18 +29,18 @@
29
29
  // ─── 타입 ───────────────────────────────────────────────
30
30
 
31
31
  export interface RetryOptions {
32
- /** 최대 시도 횟수 (기본 3) */
33
- maxAttempts?: number;
34
- /** 첫 번째 재시도 대기 시간 (ms, 기본 1000) */
35
- initialBackoffMs?: number;
36
- /** backoff 배수 (기본 2 → 1s, 2s, 4s, 8s, ...) */
37
- base?: number;
38
- /** 최대 대기 시간 (ms, 기본 30000) */
39
- maxBackoffMs?: number;
40
- /** 재시도할 에러인지 판단 (기본: 모든 에러 재시도) */
41
- shouldRetry?: (error: unknown, attempt: number) => boolean;
42
- /** 재시도 시 호출되는 콜백 (로깅용) */
43
- onRetry?: (error: unknown, attempt: number, delayMs: number) => void;
32
+ /** 최대 시도 횟수 (기본 3) */
33
+ maxAttempts?: number;
34
+ /** 첫 번째 재시도 대기 시간 (ms, 기본 1000) */
35
+ initialBackoffMs?: number;
36
+ /** backoff 배수 (기본 2 → 1s, 2s, 4s, 8s, ...) */
37
+ base?: number;
38
+ /** 최대 대기 시간 (ms, 기본 30000) */
39
+ maxBackoffMs?: number;
40
+ /** 재시도할 에러인지 판단 (기본: 모든 에러 재시도) */
41
+ shouldRetry?: (error: unknown, attempt: number) => boolean;
42
+ /** 재시도 시 호출되는 콜백 (로깅용) */
43
+ onRetry?: (error: unknown, attempt: number, delayMs: number) => void;
44
44
  }
45
45
 
46
46
  // ─── 기본값 ─────────────────────────────────────────────
@@ -60,53 +60,50 @@ const JITTER_MAX = 1.25;
60
60
  * Exponential backoff + jitter로 재시도.
61
61
  * delay = min(initialBackoffMs × base^attempt × jitter, maxBackoffMs)
62
62
  */
63
- export async function withRetry<T>(
64
- fn: () => Promise<T>,
65
- options: RetryOptions = {},
66
- ): Promise<T> {
67
- const {
68
- maxAttempts = DEFAULT_MAX_ATTEMPTS,
69
- initialBackoffMs = DEFAULT_INITIAL_BACKOFF_MS,
70
- base = DEFAULT_BASE,
71
- maxBackoffMs = DEFAULT_MAX_BACKOFF_MS,
72
- shouldRetry,
73
- onRetry,
74
- } = options;
75
-
76
- if (maxAttempts < 1) {
77
- throw new Error(`withRetry: maxAttempts must be >= 1, got ${maxAttempts}`);
63
+ export async function withRetry<T>(fn: () => Promise<T>, options: RetryOptions = {}): Promise<T> {
64
+ const {
65
+ maxAttempts = DEFAULT_MAX_ATTEMPTS,
66
+ initialBackoffMs = DEFAULT_INITIAL_BACKOFF_MS,
67
+ base = DEFAULT_BASE,
68
+ maxBackoffMs = DEFAULT_MAX_BACKOFF_MS,
69
+ shouldRetry,
70
+ onRetry,
71
+ } = options;
72
+
73
+ if (maxAttempts < 1) {
74
+ throw new Error(`withRetry: maxAttempts must be >= 1, got ${maxAttempts}`);
75
+ }
76
+
77
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
78
+ try {
79
+ return await fn();
80
+ } catch (error: unknown) {
81
+ const isLastAttempt = attempt === maxAttempts - 1;
82
+
83
+ // 마지막 시도면 에러 throw
84
+ if (isLastAttempt) throw error;
85
+
86
+ // shouldRetry가 있으면 판단
87
+ if (shouldRetry && !shouldRetry(error, attempt)) throw error;
88
+
89
+ // 딜레이 계산: exponential backoff + jitter
90
+ const jitter = JITTER_MIN + Math.random() * (JITTER_MAX - JITTER_MIN);
91
+ const rawDelay = initialBackoffMs * Math.pow(base, attempt) * jitter;
92
+ const delay = Math.min(rawDelay, maxBackoffMs);
93
+
94
+ // 콜백 호출
95
+ if (onRetry) onRetry(error, attempt + 1, delay);
96
+
97
+ await sleep(delay);
78
98
  }
99
+ }
79
100
 
80
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
81
- try {
82
- return await fn();
83
- } catch (error: unknown) {
84
- const isLastAttempt = attempt === maxAttempts - 1;
85
-
86
- // 마지막 시도면 에러 throw
87
- if (isLastAttempt) throw error;
88
-
89
- // shouldRetry가 있으면 판단
90
- if (shouldRetry && !shouldRetry(error, attempt)) throw error;
91
-
92
- // 딜레이 계산: exponential backoff + jitter
93
- const jitter = JITTER_MIN + Math.random() * (JITTER_MAX - JITTER_MIN);
94
- const rawDelay = initialBackoffMs * Math.pow(base, attempt) * jitter;
95
- const delay = Math.min(rawDelay, maxBackoffMs);
96
-
97
- // 콜백 호출
98
- if (onRetry) onRetry(error, attempt + 1, delay);
99
-
100
- await sleep(delay);
101
- }
102
- }
103
-
104
- // TypeScript를 위한 unreachable — 실제로 여기에 도달하지 않음
105
- throw new Error("withRetry: unreachable");
101
+ // TypeScript를 위한 unreachable 실제로 여기에 도달하지 않음
102
+ throw new Error("withRetry: unreachable");
106
103
  }
107
104
 
108
105
  // ─── 내부 유틸리티 ──────────────────────────────────────
109
106
 
110
107
  function sleep(ms: number): Promise<void> {
111
- return new Promise(resolve => setTimeout(resolve, ms));
108
+ return new Promise((resolve) => setTimeout(resolve, ms));
112
109
  }
package/src/rls-db.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { AsyncLocalStorage } from "node:async_hooks";
2
2
  import { sql } from "drizzle-orm";
3
- import type { PgDatabase } from "drizzle-orm/pg-core";
3
+ import type { PgAsyncDatabase } from "drizzle-orm/pg-core";
4
4
 
5
5
  /**
6
6
  * RLS DB wrapper — execution paths for `withRlsConnection`:
@@ -15,66 +15,62 @@ import type { PgDatabase } from "drizzle-orm/pg-core";
15
15
  * Optional fields become `app.*` settings; add arbitrary allowed keys via `vars`.
16
16
  */
17
17
  export type RlsSessionContext = {
18
- /** `app.current_user_id` — required by `ownerRls()` policies in this repo. */
19
- userId: string;
20
- /** When set: `app.current_user_role`. */
21
- role?: string;
22
- /** When set: `app.tenant_id`. */
23
- tenantId?: string;
24
- /**
25
- * Extra transaction-local settings: keys must be validated `app.*` GUC names
26
- * and must not duplicate `app.current_user_id` / `app.current_user_role` / `app.tenant_id`
27
- * (use the top-level fields for those).
28
- */
29
- vars?: Record<string, string>;
18
+ /** `app.current_user_id` — required by `ownerRls()` policies in this repo. */
19
+ userId: string;
20
+ /** When set: `app.current_user_role`. */
21
+ role?: string;
22
+ /** When set: `app.tenant_id`. */
23
+ tenantId?: string;
24
+ /**
25
+ * Extra transaction-local settings: keys must be validated `app.*` GUC names
26
+ * and must not duplicate `app.current_user_id` / `app.current_user_role` / `app.tenant_id`
27
+ * (use the top-level fields for those).
28
+ */
29
+ vars?: Record<string, string>;
30
30
  };
31
31
 
32
32
  const gucNameRe = /^app\.[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)*$/;
33
33
 
34
- const RESERVED_VARS_KEYS = new Set([
35
- "app.current_user_id",
36
- "app.current_user_role",
37
- "app.tenant_id",
38
- ]);
34
+ const RESERVED_VARS_KEYS = new Set(["app.current_user_id", "app.current_user_role", "app.tenant_id"]);
39
35
 
40
36
  function assertSafeGucName(key: string): void {
41
- if (!gucNameRe.test(key)) {
42
- throw new Error(
43
- `createRlsDb: GUC name "${key}" is invalid — use lowercase app.* names (e.g. app.org_id)`,
44
- );
45
- }
37
+ if (!gucNameRe.test(key)) {
38
+ throw new Error(
39
+ `createRlsDb: GUC name "${key}" is invalid — use lowercase app.* names (e.g. app.org_id)`,
40
+ );
41
+ }
46
42
  }
47
43
 
48
44
  /** Ordered `(name, value)` pairs for `set_config(name, value, true)`. */
49
45
  function rlsSetConfigPairs(rls: RlsSessionContext): [string, string][] {
50
- const pairs: [string, string][] = [["app.current_user_id", rls.userId]];
51
- if (rls.role !== undefined) {
52
- pairs.push(["app.current_user_role", rls.role]);
53
- }
54
- if (rls.tenantId !== undefined) {
55
- pairs.push(["app.tenant_id", rls.tenantId]);
56
- }
57
- if (rls.vars) {
58
- for (const [key, value] of Object.entries(rls.vars)) {
59
- assertSafeGucName(key);
60
- if (RESERVED_VARS_KEYS.has(key)) {
61
- throw new Error(
62
- `createRlsDb: vars must not set "${key}" — use userId, role, or tenantId on the context object`,
63
- );
64
- }
65
- pairs.push([key, value]);
66
- }
46
+ const pairs: [string, string][] = [["app.current_user_id", rls.userId]];
47
+ if (rls.role !== undefined) {
48
+ pairs.push(["app.current_user_role", rls.role]);
49
+ }
50
+ if (rls.tenantId !== undefined) {
51
+ pairs.push(["app.tenant_id", rls.tenantId]);
52
+ }
53
+ if (rls.vars) {
54
+ for (const [key, value] of Object.entries(rls.vars)) {
55
+ assertSafeGucName(key);
56
+ if (RESERVED_VARS_KEYS.has(key)) {
57
+ throw new Error(
58
+ `createRlsDb: vars must not set "${key}" — use userId, role, or tenantId on the context object`,
59
+ );
60
+ }
61
+ pairs.push([key, value]);
67
62
  }
68
- return pairs;
63
+ }
64
+ return pairs;
69
65
  }
70
66
 
71
67
  async function forEachSetConfig(
72
- rls: RlsSessionContext,
73
- setOne: (name: string, value: string) => Promise<void>,
68
+ rls: RlsSessionContext,
69
+ setOne: (name: string, value: string) => Promise<void>,
74
70
  ): Promise<void> {
75
- for (const [name, value] of rlsSetConfigPairs(rls)) {
76
- await setOne(name, value);
77
- }
71
+ for (const [name, value] of rlsSetConfigPairs(rls)) {
72
+ await setOne(name, value);
73
+ }
78
74
  }
79
75
 
80
76
  /**
@@ -83,36 +79,32 @@ async function forEachSetConfig(
83
79
  const rlsExecClient = new AsyncLocalStorage<unknown>();
84
80
 
85
81
  function isDrizzleTransactionDb(db: unknown): boolean {
86
- const d = db as { constructor?: { name?: string }; rollback?: unknown };
87
- if (typeof d?.rollback === "function") {
88
- return true;
89
- }
90
- const name = d?.constructor?.name;
91
- return typeof name === "string" && name.includes("Transaction");
82
+ const d = db as { constructor?: { name?: string }; rollback?: unknown };
83
+ if (typeof d?.rollback === "function") {
84
+ return true;
85
+ }
86
+ const name = d?.constructor?.name;
87
+ return typeof name === "string" && name.includes("Transaction");
92
88
  }
93
89
 
94
90
  async function execSetConfig(client: any, name: string, value: string): Promise<void> {
95
- if (typeof client?.unsafe === "function") {
96
- await client.unsafe(`select set_config($1::text, $2::text, true)`, [name, value]);
97
- return;
98
- }
99
- if (typeof client?.query === "function") {
100
- await client.query(`select set_config($1::text, $2::text, true)`, [name, value]);
101
- return;
102
- }
103
- throw new Error(
104
- "createRlsDb: unsupported SQL driver (expected Bun SQL, node-pg client/pool, or PGlite)",
105
- );
91
+ if (typeof client?.unsafe === "function") {
92
+ await client.unsafe(`select set_config($1::text, $2::text, true)`, [name, value]);
93
+ return;
94
+ }
95
+ if (typeof client?.query === "function") {
96
+ await client.query(`select set_config($1::text, $2::text, true)`, [name, value]);
97
+ return;
98
+ }
99
+ throw new Error("createRlsDb: unsupported SQL driver (expected Bun SQL, node-pg client/pool, or PGlite)");
106
100
  }
107
101
 
108
102
  async function applyRlsSessionVars(client: any, rls: RlsSessionContext): Promise<void> {
109
- await forEachSetConfig(rls, (name, value) => execSetConfig(client, name, value));
103
+ await forEachSetConfig(rls, (name, value) => execSetConfig(client, name, value));
110
104
  }
111
105
 
112
106
  async function injectRlsVarsOnTx(tx: any, rls: RlsSessionContext): Promise<void> {
113
- await forEachSetConfig(rls, (name, value) =>
114
- tx.execute(sql`SELECT set_config(${name}, ${value}, true)`),
115
- );
107
+ await forEachSetConfig(rls, (name, value) => tx.execute(sql`SELECT set_config(${name}, ${value}, true)`));
116
108
  }
117
109
 
118
110
  /**
@@ -122,26 +114,26 @@ async function injectRlsVarsOnTx(tx: any, rls: RlsSessionContext): Promise<void>
122
114
  * @internal Exported only for unit tests — not re-exported from `@gencow/core` public API.
123
115
  */
124
116
  export async function withRlsLeasedConnection<T>(
125
- leased: { query: (sql: string) => Promise<unknown>; release: () => void },
126
- rls: RlsSessionContext,
127
- fn: (client: { query: (sql: string) => Promise<unknown>; release: () => void }) => Promise<T>,
117
+ leased: { query: (sql: string) => Promise<unknown>; release: () => void },
118
+ rls: RlsSessionContext,
119
+ fn: (client: { query: (sql: string) => Promise<unknown>; release: () => void }) => Promise<T>,
128
120
  ): Promise<T> {
121
+ try {
122
+ await leased.query("begin");
123
+ await applyRlsSessionVars(leased, rls);
124
+ const result = await rlsExecClient.run(leased, () => fn(leased));
125
+ await leased.query("commit");
126
+ return result;
127
+ } catch (e) {
129
128
  try {
130
- await leased.query("begin");
131
- await applyRlsSessionVars(leased, rls);
132
- const result = await rlsExecClient.run(leased, () => fn(leased));
133
- await leased.query("commit");
134
- return result;
135
- } catch (e) {
136
- try {
137
- await leased.query("rollback");
138
- } catch {
139
- /* ignore */
140
- }
141
- throw e;
142
- } finally {
143
- leased.release();
129
+ await leased.query("rollback");
130
+ } catch {
131
+ /* ignore */
144
132
  }
133
+ throw e;
134
+ } finally {
135
+ leased.release();
136
+ }
145
137
  }
146
138
 
147
139
  /**
@@ -150,104 +142,99 @@ export async function withRlsLeasedConnection<T>(
150
142
  * When `db` is already a Drizzle transaction object, reuses that connection (no nested top-level tx).
151
143
  */
152
144
  async function withRlsConnection<T>(
153
- session: any,
154
- rls: RlsSessionContext,
155
- reuseOuterConnection: boolean,
156
- fn: (client: any) => Promise<T>,
145
+ session: any,
146
+ rls: RlsSessionContext,
147
+ reuseOuterConnection: boolean,
148
+ fn: (client: any) => Promise<T>,
157
149
  ): Promise<T> {
158
- if (reuseOuterConnection) {
159
- const c = session.client;
160
- return rlsExecClient.run(c, async () => {
161
- await applyRlsSessionVars(c, rls);
162
- return fn(c);
163
- });
164
- }
150
+ if (reuseOuterConnection) {
165
151
  const c = session.client;
166
- const runInner = async (client: any) => {
167
- await applyRlsSessionVars(client, rls);
168
- return rlsExecClient.run(client, () => fn(client));
169
- };
170
- if (typeof c.begin === "function") {
171
- return c.begin(runInner);
172
- }
173
- if (typeof c.transaction === "function") {
174
- return c.transaction(runInner);
175
- }
176
- if (typeof c.connect === "function" && typeof c.query === "function") {
177
- const leased = await c.connect();
178
- return withRlsLeasedConnection(leased, rls, fn);
179
- }
180
- return runInner(c);
152
+ return rlsExecClient.run(c, async () => {
153
+ await applyRlsSessionVars(c, rls);
154
+ return fn(c);
155
+ });
156
+ }
157
+ const c = session.client;
158
+ const runInner = async (client: any) => {
159
+ await applyRlsSessionVars(client, rls);
160
+ return rlsExecClient.run(client, () => fn(client));
161
+ };
162
+ if (typeof c.begin === "function") {
163
+ return c.begin(runInner);
164
+ }
165
+ if (typeof c.transaction === "function") {
166
+ return c.transaction(runInner);
167
+ }
168
+ if (typeof c.connect === "function" && typeof c.query === "function") {
169
+ const leased = await c.connect();
170
+ return withRlsLeasedConnection(leased, rls, fn);
171
+ }
172
+ return runInner(c);
181
173
  }
182
174
 
183
- function wrapPreparedQuery(
184
- pq: any,
185
- session: any,
186
- rls: RlsSessionContext,
187
- reuseOuterConnection: boolean,
188
- ) {
189
- const origExecute = pq.execute.bind(pq);
190
- const origAll = pq.all.bind(pq);
175
+ function wrapPreparedQuery(pq: any, session: any, rls: RlsSessionContext, reuseOuterConnection: boolean) {
176
+ const origExecute = pq.execute.bind(pq);
177
+ const origAll = pq.all.bind(pq);
191
178
 
192
- pq.execute = async (placeholderValues?: unknown) => {
193
- const active = rlsExecClient.getStore();
194
- if (active) {
195
- const prev = pq.client;
196
- pq.client = active;
197
- try {
198
- return await origExecute(placeholderValues);
199
- } finally {
200
- pq.client = prev;
201
- }
202
- }
203
- return withRlsConnection(session, rls, reuseOuterConnection, async (client) => {
204
- const prev = pq.client;
205
- pq.client = client;
206
- try {
207
- return await origExecute(placeholderValues);
208
- } finally {
209
- pq.client = prev;
210
- }
211
- });
212
- };
179
+ pq.execute = async (placeholderValues?: unknown) => {
180
+ const active = rlsExecClient.getStore();
181
+ if (active) {
182
+ const prev = pq.client;
183
+ pq.client = active;
184
+ try {
185
+ return await origExecute(placeholderValues);
186
+ } finally {
187
+ pq.client = prev;
188
+ }
189
+ }
190
+ return withRlsConnection(session, rls, reuseOuterConnection, async (client) => {
191
+ const prev = pq.client;
192
+ pq.client = client;
193
+ try {
194
+ return await origExecute(placeholderValues);
195
+ } finally {
196
+ pq.client = prev;
197
+ }
198
+ });
199
+ };
213
200
 
214
- pq.all = async (placeholderValues?: unknown) => {
215
- const active = rlsExecClient.getStore();
216
- if (active) {
217
- const prev = pq.client;
218
- pq.client = active;
219
- try {
220
- return await origAll(placeholderValues);
221
- } finally {
222
- pq.client = prev;
223
- }
224
- }
225
- return withRlsConnection(session, rls, reuseOuterConnection, async (client) => {
226
- const prev = pq.client;
227
- pq.client = client;
228
- try {
229
- return await origAll(placeholderValues);
230
- } finally {
231
- pq.client = prev;
232
- }
233
- });
234
- };
201
+ pq.all = async (placeholderValues?: unknown) => {
202
+ const active = rlsExecClient.getStore();
203
+ if (active) {
204
+ const prev = pq.client;
205
+ pq.client = active;
206
+ try {
207
+ return await origAll(placeholderValues);
208
+ } finally {
209
+ pq.client = prev;
210
+ }
211
+ }
212
+ return withRlsConnection(session, rls, reuseOuterConnection, async (client) => {
213
+ const prev = pq.client;
214
+ pq.client = client;
215
+ try {
216
+ return await origAll(placeholderValues);
217
+ } finally {
218
+ pq.client = prev;
219
+ }
220
+ });
221
+ };
235
222
  }
236
223
 
237
224
  function wrapSession(session: any, rls: RlsSessionContext, reuseOuterConnection: boolean) {
238
- return new Proxy(session, {
239
- get(sTarget, sProp, sRecv) {
240
- if (sProp === "prepareQuery") {
241
- return (...args: unknown[]) => {
242
- const pq = sTarget.prepareQuery(...args);
243
- wrapPreparedQuery(pq, sTarget, rls, reuseOuterConnection);
244
- return pq;
245
- };
246
- }
247
- const v = Reflect.get(sTarget, sProp, sRecv);
248
- return typeof v === "function" ? v.bind(sTarget) : v;
249
- },
250
- });
225
+ return new Proxy(session, {
226
+ get(sTarget, sProp, sRecv) {
227
+ if (sProp === "prepareQuery") {
228
+ return (...args: unknown[]) => {
229
+ const pq = sTarget.prepareQuery(...args);
230
+ wrapPreparedQuery(pq, sTarget, rls, reuseOuterConnection);
231
+ return pq;
232
+ };
233
+ }
234
+ const v = Reflect.get(sTarget, sProp, sRecv);
235
+ return typeof v === "function" ? v.bind(sTarget) : v;
236
+ },
237
+ });
251
238
  }
252
239
 
253
240
  /**
@@ -258,37 +245,40 @@ function wrapSession(session: any, rls: RlsSessionContext, reuseOuterConnection:
258
245
  * `db.transaction()` still injects the same variables at the start of the callback transaction.
259
246
  */
260
247
  export function createRlsDb(
261
- db: PgDatabase<any, any, any>,
262
- rls: RlsSessionContext,
263
- ): PgDatabase<any, any, any> {
264
- const reuseOuterConnection = isDrizzleTransactionDb(db);
265
- const baseSession = (db as unknown as { session: any }).session;
266
- const wrappedSession = wrapSession(baseSession, rls, reuseOuterConnection);
248
+ db: PgAsyncDatabase<any, any, any, any>,
249
+ rls: RlsSessionContext,
250
+ ): PgAsyncDatabase<any, any, any, any> {
251
+ const reuseOuterConnection = isDrizzleTransactionDb(db);
252
+ const baseSession = (db as unknown as { session: any }).session;
253
+ const wrappedSession = wrapSession(baseSession, rls, reuseOuterConnection);
267
254
 
268
- return new Proxy(db, {
269
- get(target, prop, receiver) {
270
- if (prop === "session") {
271
- return wrappedSession;
272
- }
273
- if (prop === "_") {
274
- const inner = target._;
275
- return new Proxy(inner, {
276
- get(i, p, r) {
277
- if (p === "session") return wrappedSession;
278
- return Reflect.get(i, p, r);
279
- },
280
- });
281
- }
282
- if (prop === "transaction") {
283
- return async (callback: any, ...rest: any[]) => {
284
- return await target.transaction(async (tx: any) => {
285
- await injectRlsVarsOnTx(tx, rls);
286
- return await callback(tx);
287
- }, ...rest as any);
288
- };
289
- }
290
- const value = Reflect.get(target, prop, receiver);
291
- return typeof value === "function" ? value.bind(receiver) : value;
292
- },
293
- });
255
+ return new Proxy(db, {
256
+ get(target, prop, receiver) {
257
+ if (prop === "session") {
258
+ return wrappedSession;
259
+ }
260
+ if (prop === "_") {
261
+ const inner = target._;
262
+ return new Proxy(inner, {
263
+ get(i, p, r) {
264
+ if (p === "session") return wrappedSession;
265
+ return Reflect.get(i, p, r);
266
+ },
267
+ });
268
+ }
269
+ if (prop === "transaction") {
270
+ return async (callback: any, ...rest: any[]) => {
271
+ return await target.transaction(
272
+ async (tx: any) => {
273
+ await injectRlsVarsOnTx(tx, rls);
274
+ return await callback(tx);
275
+ },
276
+ ...(rest as any),
277
+ );
278
+ };
279
+ }
280
+ const value = Reflect.get(target, prop, receiver);
281
+ return typeof value === "function" ? value.bind(receiver) : value;
282
+ },
283
+ });
294
284
  }