gencow 0.1.247 → 0.1.249
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/bin/gencow.mjs +4 -15
- package/core/index.js +255 -77
- package/core/package.json +1 -1
- package/dashboard/assets/index-DvEb2ey9.css +1 -0
- package/dashboard/assets/index-PfrmDrvH.js +401 -0
- package/dashboard/index.html +2 -2
- package/lib/backup-command.mjs +11 -0
- package/lib/cli-command-runner.mjs +23 -0
- package/lib/cli-project-runtime.mjs +12 -3
- package/lib/codegen-command.mjs +25 -9
- package/lib/dashboard-assets.mjs +22 -0
- package/lib/db-command.mjs +17 -15
- package/lib/deploy-auditor.mjs +15 -2
- package/lib/deploy-bundle-staging.mjs +1 -1
- package/lib/deploy-bundle-summary.mjs +47 -0
- package/lib/deploy-command.mjs +3 -0
- package/lib/deploy-failure-diagnostic.mjs +212 -8
- package/lib/deploy-package-runtime.mjs +25 -30
- package/lib/deploy-runtime-asset-audit.mjs +81 -0
- package/lib/deploy-runtime-path-audit.mjs +81 -0
- package/lib/deploy-runtime.mjs +0 -4
- package/lib/deploy-static-fullstack-runtime.mjs +0 -5
- package/lib/deployment-artifact-provenance.mjs +9 -4
- package/lib/deployment-operation-poll.mjs +44 -0
- package/lib/dev-cloud-bundle.mjs +11 -0
- package/lib/dev-cloud-migrations.mjs +0 -14
- package/lib/dev-local-command.mjs +8 -19
- package/lib/doctor-command.mjs +36 -27
- package/lib/jobs-command.d.mts +14 -0
- package/lib/jobs-command.mjs +51 -7
- package/lib/migration-diagnostic.mjs +4 -1
- package/lib/platform-client.mjs +121 -2
- package/lib/procedure-rpc-diagnostic.mjs +47 -0
- package/lib/project-migration-manifest.mjs +1 -0
- package/lib/release-client.mjs +18 -0
- package/lib/runtime-bom-diagnostic.mjs +155 -0
- package/lib/runtime-bom-resolve.mjs +275 -212
- package/lib/runtime-command.mjs +34 -32
- package/lib/ts-codegen-import-extension.mjs +329 -0
- package/package.json +3 -3
- package/runtime/config.mjs +5 -2
- package/runtime/server.mjs +29543 -21790
- package/runtime/tooling.mjs +46 -12
- package/scripts/bundle-server.mjs +2 -9
- package/dashboard/assets/index-BIg8EAY8.css +0 -1
- package/dashboard/assets/index-CcD-YPfN.js +0 -408
package/bin/gencow.mjs
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* gencow help — show this help
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import { execSync
|
|
19
|
+
import { execSync } from "child_process";
|
|
20
20
|
import { existsSync, readFileSync, writeFileSync, unlinkSync, cpSync, symlinkSync, copyFileSync } from "fs";
|
|
21
21
|
import { resolve, dirname } from "path";
|
|
22
22
|
import { fileURLToPath } from "url";
|
|
@@ -146,7 +146,9 @@ const runDoctorCommand = createDoctorCommand({
|
|
|
146
146
|
warnImpl: warn,
|
|
147
147
|
errorImpl: error,
|
|
148
148
|
successImpl: success,
|
|
149
|
-
exitImpl: (code) =>
|
|
149
|
+
exitImpl: (code) => {
|
|
150
|
+
process.exitCode = code;
|
|
151
|
+
},
|
|
150
152
|
cwdImpl: () => process.cwd(),
|
|
151
153
|
BOLD,
|
|
152
154
|
CYAN,
|
|
@@ -546,19 +548,6 @@ ${BOLD}Examples:${RESET}
|
|
|
546
548
|
// ── env — 환경변수 관리 (Cloud only) ─────────
|
|
547
549
|
env: runEnvCommand,
|
|
548
550
|
|
|
549
|
-
async platform() {
|
|
550
|
-
log(`\n${BOLD}${CYAN}Gencow Platform${RESET} ${DIM}— Control Plane${RESET}\n`);
|
|
551
|
-
info("Starting Control Plane on port 4000...");
|
|
552
|
-
const cwd = process.cwd();
|
|
553
|
-
const proc = spawn("pnpm", ["--filter", "@gencow/platform", "dev"], {
|
|
554
|
-
cwd,
|
|
555
|
-
stdio: "inherit",
|
|
556
|
-
shell: true,
|
|
557
|
-
});
|
|
558
|
-
proc.on("exit", (code) => process.exit(code ?? 0));
|
|
559
|
-
process.on("SIGINT", () => proc.kill());
|
|
560
|
-
},
|
|
561
|
-
|
|
562
551
|
// ── dev:cloud (watch + auto-deploy + live log streaming) ──
|
|
563
552
|
"dev:cloud": runDevCloudCommand,
|
|
564
553
|
|
package/core/index.js
CHANGED
|
@@ -2256,11 +2256,11 @@ async function countWorkflowV1Backlog(db, workflowName) {
|
|
|
2256
2256
|
pendingByName: numberFrom(row?.pending_by_name)
|
|
2257
2257
|
};
|
|
2258
2258
|
}
|
|
2259
|
-
async function countWorkflowBacklog(db, workflowName) {
|
|
2259
|
+
async function countWorkflowBacklog(db, workflowName, requireV2 = false) {
|
|
2260
2260
|
try {
|
|
2261
2261
|
return await countWorkflowV2Backlog(db, workflowName);
|
|
2262
2262
|
} catch (error) {
|
|
2263
|
-
if (!isMissingWorkflowV2SchemaError(error)) throw error;
|
|
2263
|
+
if (!isMissingWorkflowV2SchemaError(error) || requireV2) throw error;
|
|
2264
2264
|
return countWorkflowV1Backlog(db, workflowName);
|
|
2265
2265
|
}
|
|
2266
2266
|
}
|
|
@@ -2301,7 +2301,7 @@ async function applyWorkflowStartAdmission(options) {
|
|
|
2301
2301
|
});
|
|
2302
2302
|
}
|
|
2303
2303
|
await acquireWorkflowStartAdmissionLock(options.db);
|
|
2304
|
-
const counts = await countWorkflowBacklog(options.db, options.workflowName);
|
|
2304
|
+
const counts = await countWorkflowBacklog(options.db, options.workflowName, options.requireV2);
|
|
2305
2305
|
if (counts.pending >= policy.pendingPerApp) {
|
|
2306
2306
|
throw new JobAdmissionError("job_backlog_limit_exceeded", "workflow pending backlog limit exceeded", {
|
|
2307
2307
|
details: { limit: policy.pendingPerApp, pending: counts.pending }
|
|
@@ -2949,11 +2949,13 @@ function parseJsonField(value) {
|
|
|
2949
2949
|
}
|
|
2950
2950
|
}
|
|
2951
2951
|
function toIsoString(value) {
|
|
2952
|
-
if (value
|
|
2952
|
+
if (typeof value === "number" && !Number.isFinite(value)) return String(/* @__PURE__ */ new Date(NaN));
|
|
2953
|
+
if (value instanceof Date) return Number.isFinite(value.getTime()) ? value.toISOString() : String(value);
|
|
2953
2954
|
const parsed = new Date(value);
|
|
2954
2955
|
return Number.isFinite(parsed.getTime()) ? parsed.toISOString() : String(value);
|
|
2955
2956
|
}
|
|
2956
2957
|
function toOptionalIsoString(value) {
|
|
2958
|
+
if (typeof value === "number" && !Number.isFinite(value)) return toIsoString(value);
|
|
2957
2959
|
return value ? toIsoString(value) : null;
|
|
2958
2960
|
}
|
|
2959
2961
|
function publicV2Status(status) {
|
|
@@ -3628,6 +3630,7 @@ var RESERVED_TENANT_RUNTIME_ENV_KEYS = [
|
|
|
3628
3630
|
"GENCOW_FUNCTIONS",
|
|
3629
3631
|
"GENCOW_STORAGE",
|
|
3630
3632
|
"GENCOW_STORAGE_REQUIRE_READ_GRANT",
|
|
3633
|
+
"GENCOW_LOCAL_STORAGE_READ_GRANT_SECRET",
|
|
3631
3634
|
"GENCOW_STORAGE_BACKEND",
|
|
3632
3635
|
"GENCOW_STORAGE_LEGACY_LOCAL_FALLBACK",
|
|
3633
3636
|
"GENCOW_STORAGE_QUOTA_BYTES",
|
|
@@ -4097,8 +4100,157 @@ import { pgTable } from "drizzle-orm/pg-core";
|
|
|
4097
4100
|
var pgBaseTable = pgTable;
|
|
4098
4101
|
|
|
4099
4102
|
// ../core/src/rls-db.ts
|
|
4100
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4101
4103
|
import { sql as sql7 } from "drizzle-orm";
|
|
4104
|
+
|
|
4105
|
+
// ../core/src/rls-db-scoped-query.ts
|
|
4106
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4107
|
+
import { NoopCache } from "drizzle-orm/cache/core";
|
|
4108
|
+
import { RelationalQueryBuilder as PgRelationalQueryBuilder } from "drizzle-orm/pg-core/query-builders/query";
|
|
4109
|
+
import { PgDialect } from "drizzle-orm/pg-core/dialect";
|
|
4110
|
+
import { PgAsyncRelationalQuery } from "drizzle-orm/pg-core/async/query";
|
|
4111
|
+
var activeRlsExecution = new AsyncLocalStorage();
|
|
4112
|
+
function createRlsDiagnosticError(message, diagnostic) {
|
|
4113
|
+
return Object.assign(new Error(message), diagnostic);
|
|
4114
|
+
}
|
|
4115
|
+
function createRlsScopeToken() {
|
|
4116
|
+
return {};
|
|
4117
|
+
}
|
|
4118
|
+
function createRlsScopeConflictError() {
|
|
4119
|
+
return createRlsDiagnosticError("A query cannot switch database scopes while an RLS operation is active.", {
|
|
4120
|
+
code: "RLS_SCOPE_CONFLICT",
|
|
4121
|
+
status: 409,
|
|
4122
|
+
stage: "rls-query-execution",
|
|
4123
|
+
capability: "rls-scoped-query",
|
|
4124
|
+
stateImpact: "Rejected query executed no tenant SQL; enclosing operation may still finish independently",
|
|
4125
|
+
retryable: false,
|
|
4126
|
+
retryPrecondition: "Invoke only a database handle matching the active RLS scope, or wait until the active RLS execution completes.",
|
|
4127
|
+
nextAction: "EDIT_AND_CHECK"
|
|
4128
|
+
});
|
|
4129
|
+
}
|
|
4130
|
+
var unsupportedByReason = {
|
|
4131
|
+
cache: {
|
|
4132
|
+
message: "RLS-scoped queries do not support a shared Drizzle result cache.",
|
|
4133
|
+
retryPrecondition: "Remove the shared Drizzle cache configuration before retrying; shared result caches are not supported by RLS-scoped queries."
|
|
4134
|
+
},
|
|
4135
|
+
relations: {
|
|
4136
|
+
message: "This relational builder is not from the verified Drizzle v1 integration.",
|
|
4137
|
+
retryPrecondition: "Check the installed version with `pnpm why drizzle-orm`; use verified drizzle-orm@1.0.0-rc.4 without custom relational builders before retrying."
|
|
4138
|
+
},
|
|
4139
|
+
session: {
|
|
4140
|
+
message: "This Drizzle session cannot be safely bound to the transaction-scoped RLS client.",
|
|
4141
|
+
retryPrecondition: "Check the installed version with `pnpm why drizzle-orm`; use a verified Drizzle driver and session before retrying."
|
|
4142
|
+
}
|
|
4143
|
+
};
|
|
4144
|
+
function createRlsUnsupportedError(reason = "relations") {
|
|
4145
|
+
return createRlsDiagnosticError(unsupportedByReason[reason].message, {
|
|
4146
|
+
code: "RLS_DRIZZLE_INTEGRATION_UNSUPPORTED",
|
|
4147
|
+
status: 409,
|
|
4148
|
+
stage: "rls-query-setup",
|
|
4149
|
+
capability: "rls-scoped-query",
|
|
4150
|
+
stateImpact: "This rejected setup executed no tenant SQL and made no database state change",
|
|
4151
|
+
retryable: false,
|
|
4152
|
+
retryPrecondition: unsupportedByReason[reason].retryPrecondition,
|
|
4153
|
+
nextAction: "EDIT_AND_CHECK"
|
|
4154
|
+
});
|
|
4155
|
+
}
|
|
4156
|
+
function assertRlsScopeMayEnter(scope) {
|
|
4157
|
+
const active = activeRlsExecution.getStore();
|
|
4158
|
+
if (active?.active && active.scope !== scope) {
|
|
4159
|
+
throw createRlsScopeConflictError();
|
|
4160
|
+
}
|
|
4161
|
+
}
|
|
4162
|
+
function currentRlsExecution(scope) {
|
|
4163
|
+
const active = activeRlsExecution.getStore();
|
|
4164
|
+
if (!active?.active) return void 0;
|
|
4165
|
+
if (active.scope !== scope) throw createRlsScopeConflictError();
|
|
4166
|
+
return active;
|
|
4167
|
+
}
|
|
4168
|
+
function matchingRlsExecutionClient(scope) {
|
|
4169
|
+
const active = activeRlsExecution.getStore();
|
|
4170
|
+
return active?.active && active.scope === scope ? active.client : void 0;
|
|
4171
|
+
}
|
|
4172
|
+
async function runWithRlsScope(scope, client, work) {
|
|
4173
|
+
const active = { scope, client, active: true };
|
|
4174
|
+
return activeRlsExecution.run(active, async () => {
|
|
4175
|
+
try {
|
|
4176
|
+
return await work();
|
|
4177
|
+
} finally {
|
|
4178
|
+
active.active = false;
|
|
4179
|
+
}
|
|
4180
|
+
});
|
|
4181
|
+
}
|
|
4182
|
+
function runWithRlsTransactionScope(scope, tx, work) {
|
|
4183
|
+
assertRlsScopeMayEnter(scope);
|
|
4184
|
+
return runWithRlsScope(scope, tx.session?.client, work);
|
|
4185
|
+
}
|
|
4186
|
+
function createRlsRelationalQueryRegistry(query2, session, baseSession) {
|
|
4187
|
+
const scopedRegistry = /* @__PURE__ */ Object.create(null);
|
|
4188
|
+
for (const tableName of Reflect.ownKeys(query2)) {
|
|
4189
|
+
const descriptor = Object.getOwnPropertyDescriptor(query2, tableName);
|
|
4190
|
+
if (typeof tableName !== "string" || !descriptor || !descriptor.enumerable || !("value" in descriptor)) {
|
|
4191
|
+
throw createRlsUnsupportedError("relations");
|
|
4192
|
+
}
|
|
4193
|
+
const builder = descriptor.value;
|
|
4194
|
+
if (!builder || typeof builder !== "object" || builder.session !== baseSession || !builder.schema || typeof builder.schema !== "object" || !builder.table || typeof builder.table !== "object" || !builder.tableConfig || typeof builder.tableConfig !== "object" || !builder.dialect || typeof builder.dialect !== "object" || Object.getPrototypeOf(builder.dialect) !== PgDialect.prototype || Reflect.get(builder.dialect, "constructor") !== PgDialect || typeof builder.parseJson !== "boolean" || builder.builder !== PgAsyncRelationalQuery || Object.getPrototypeOf(builder) !== PgRelationalQueryBuilder.prototype || Reflect.get(builder, "constructor") !== PgRelationalQueryBuilder || Reflect.get(builder, "findMany") !== PgRelationalQueryBuilder.prototype.findMany || Reflect.get(builder, "findFirst") !== PgRelationalQueryBuilder.prototype.findFirst) {
|
|
4195
|
+
throw createRlsUnsupportedError("relations");
|
|
4196
|
+
}
|
|
4197
|
+
const scopedBuilder = Reflect.construct(PgRelationalQueryBuilder, [
|
|
4198
|
+
builder.schema,
|
|
4199
|
+
builder.table,
|
|
4200
|
+
builder.tableConfig,
|
|
4201
|
+
builder.dialect,
|
|
4202
|
+
session,
|
|
4203
|
+
builder.parseJson,
|
|
4204
|
+
PgAsyncRelationalQuery
|
|
4205
|
+
]);
|
|
4206
|
+
const trustedFindMany = PgRelationalQueryBuilder.prototype.findMany;
|
|
4207
|
+
const trustedFindFirst = PgRelationalQueryBuilder.prototype.findFirst;
|
|
4208
|
+
Object.defineProperties(scopedBuilder, {
|
|
4209
|
+
findMany: {
|
|
4210
|
+
value: function(config) {
|
|
4211
|
+
return Reflect.apply(trustedFindMany, this, [config]);
|
|
4212
|
+
}
|
|
4213
|
+
},
|
|
4214
|
+
findFirst: {
|
|
4215
|
+
value: function(config) {
|
|
4216
|
+
return Reflect.apply(trustedFindFirst, this, [config]);
|
|
4217
|
+
}
|
|
4218
|
+
}
|
|
4219
|
+
});
|
|
4220
|
+
Object.freeze(scopedBuilder);
|
|
4221
|
+
Object.defineProperty(scopedRegistry, tableName, {
|
|
4222
|
+
value: scopedBuilder,
|
|
4223
|
+
enumerable: true,
|
|
4224
|
+
configurable: false,
|
|
4225
|
+
writable: false
|
|
4226
|
+
});
|
|
4227
|
+
}
|
|
4228
|
+
return Object.freeze(scopedRegistry);
|
|
4229
|
+
}
|
|
4230
|
+
function isVerifiedNoopCache(cache) {
|
|
4231
|
+
if (!cache || typeof cache !== "object") return false;
|
|
4232
|
+
const candidate = cache;
|
|
4233
|
+
const ownKeys = Reflect.ownKeys(cache);
|
|
4234
|
+
const ownPropertiesAreExpected = ownKeys.every((key) => {
|
|
4235
|
+
if (key !== "invalidate") return false;
|
|
4236
|
+
const descriptor = Object.getOwnPropertyDescriptor(cache, key);
|
|
4237
|
+
return descriptor && "value" in descriptor && descriptor.value === NoopCache.prototype.onMutate;
|
|
4238
|
+
});
|
|
4239
|
+
return candidate.constructor === NoopCache && Object.getPrototypeOf(cache) === NoopCache.prototype && ownPropertiesAreExpected && candidate.strategy === NoopCache.prototype.strategy && candidate.get === NoopCache.prototype.get && candidate.put === NoopCache.prototype.put && candidate.onMutate === NoopCache.prototype.onMutate;
|
|
4240
|
+
}
|
|
4241
|
+
function hasUnpartitionedRlsCache(db, session) {
|
|
4242
|
+
const databaseCache = db?.$cache;
|
|
4243
|
+
const sessionCache = session?.cache;
|
|
4244
|
+
const hasResultCacheSurface = (cache) => {
|
|
4245
|
+
if (!cache || typeof cache !== "object") return false;
|
|
4246
|
+
return ["strategy", "get", "put"].some((method) => typeof Reflect.get(cache, method) === "function");
|
|
4247
|
+
};
|
|
4248
|
+
const hasUnverifiedSessionCache = sessionCache !== void 0 && sessionCache !== null && !isVerifiedNoopCache(sessionCache);
|
|
4249
|
+
const hasUnverifiedDatabaseCache = hasResultCacheSurface(databaseCache) && !isVerifiedNoopCache(databaseCache);
|
|
4250
|
+
return hasUnverifiedSessionCache || hasUnverifiedDatabaseCache;
|
|
4251
|
+
}
|
|
4252
|
+
|
|
4253
|
+
// ../core/src/rls-db.ts
|
|
4102
4254
|
var TRANSACTION_ISOLATION_LEVELS = /* @__PURE__ */ new Set([
|
|
4103
4255
|
"read uncommitted",
|
|
4104
4256
|
"read committed",
|
|
@@ -4140,11 +4292,6 @@ async function forEachSetConfig(rls, setOne) {
|
|
|
4140
4292
|
await setOne(name, value);
|
|
4141
4293
|
}
|
|
4142
4294
|
}
|
|
4143
|
-
var rlsExecClient = new AsyncLocalStorage();
|
|
4144
|
-
function isBunSqlSession(session) {
|
|
4145
|
-
const name = session?.constructor?.name;
|
|
4146
|
-
return typeof name === "string" && name.includes("BunSQLSession");
|
|
4147
|
-
}
|
|
4148
4295
|
function isDrizzleTransactionDb(db) {
|
|
4149
4296
|
const d = db;
|
|
4150
4297
|
if (typeof d?.rollback === "function") {
|
|
@@ -4178,11 +4325,11 @@ async function injectRlsVarsOnTx(tx, rls, onTransactionContextFailure) {
|
|
|
4178
4325
|
throw error;
|
|
4179
4326
|
}
|
|
4180
4327
|
}
|
|
4181
|
-
async function withRlsLeasedConnection(leased, rls, fn) {
|
|
4328
|
+
async function withRlsLeasedConnection(leased, rls, fn, scope) {
|
|
4182
4329
|
try {
|
|
4183
4330
|
await leased.query("begin");
|
|
4184
4331
|
await applyRlsSessionVars(leased, rls);
|
|
4185
|
-
const result = await
|
|
4332
|
+
const result = scope ? await runWithRlsScope(scope, leased, () => fn(leased)) : await fn(leased);
|
|
4186
4333
|
await leased.query("commit");
|
|
4187
4334
|
return result;
|
|
4188
4335
|
} catch (e) {
|
|
@@ -4195,19 +4342,20 @@ async function withRlsLeasedConnection(leased, rls, fn) {
|
|
|
4195
4342
|
leased.release();
|
|
4196
4343
|
}
|
|
4197
4344
|
}
|
|
4198
|
-
async function withRlsConnection(session, rls, reuseOuterConnection, fn) {
|
|
4345
|
+
async function withRlsConnection(session, rls, reuseOuterConnection, scope, fn) {
|
|
4346
|
+
assertRlsScopeMayEnter(scope);
|
|
4199
4347
|
if (reuseOuterConnection) {
|
|
4200
4348
|
const c2 = session.client;
|
|
4201
|
-
return
|
|
4349
|
+
return runWithRlsScope(scope, c2, async () => {
|
|
4202
4350
|
await applyRlsSessionVars(c2, rls);
|
|
4203
4351
|
return fn(c2);
|
|
4204
4352
|
});
|
|
4205
4353
|
}
|
|
4206
4354
|
const c = session.client;
|
|
4207
|
-
const runInner = async (client) => {
|
|
4355
|
+
const runInner = async (client) => runWithRlsScope(scope, client, async () => {
|
|
4208
4356
|
await applyRlsSessionVars(client, rls);
|
|
4209
|
-
return
|
|
4210
|
-
};
|
|
4357
|
+
return fn(client);
|
|
4358
|
+
});
|
|
4211
4359
|
if (typeof c.begin === "function") {
|
|
4212
4360
|
return c.begin(runInner);
|
|
4213
4361
|
}
|
|
@@ -4216,7 +4364,7 @@ async function withRlsConnection(session, rls, reuseOuterConnection, fn) {
|
|
|
4216
4364
|
}
|
|
4217
4365
|
if (typeof c.connect === "function" && typeof c.query === "function") {
|
|
4218
4366
|
const leased = await c.connect();
|
|
4219
|
-
return withRlsLeasedConnection(leased, rls, fn);
|
|
4367
|
+
return withRlsLeasedConnection(leased, rls, fn, scope);
|
|
4220
4368
|
}
|
|
4221
4369
|
return runInner(c);
|
|
4222
4370
|
}
|
|
@@ -4231,29 +4379,7 @@ function createClientBoundSession(session, client) {
|
|
|
4231
4379
|
}
|
|
4232
4380
|
});
|
|
4233
4381
|
}
|
|
4234
|
-
|
|
4235
|
-
if (!("client" in pq)) {
|
|
4236
|
-
return await fn();
|
|
4237
|
-
}
|
|
4238
|
-
const prevPq = pq.client;
|
|
4239
|
-
pq.client = client;
|
|
4240
|
-
try {
|
|
4241
|
-
return await fn();
|
|
4242
|
-
} finally {
|
|
4243
|
-
pq.client = prevPq;
|
|
4244
|
-
}
|
|
4245
|
-
}
|
|
4246
|
-
function createGenericPreparedQueryClientExecutors(pq) {
|
|
4247
|
-
const origExecute = pq.execute.bind(pq);
|
|
4248
|
-
const origAll = typeof pq.all === "function" ? pq.all.bind(pq) : null;
|
|
4249
|
-
return {
|
|
4250
|
-
execute(client, placeholderValues) {
|
|
4251
|
-
return withPreparedQueryClient(pq, client, () => origExecute(placeholderValues));
|
|
4252
|
-
},
|
|
4253
|
-
all: origAll ? (client, placeholderValues) => withPreparedQueryClient(pq, client, () => origAll(placeholderValues)) : void 0
|
|
4254
|
-
};
|
|
4255
|
-
}
|
|
4256
|
-
function createBunSqlPreparedQueryClientExecutors(baseSession, prepareQuery, prepareArgs) {
|
|
4382
|
+
function createSessionBoundPreparedQueryClientExecutors(pq, baseSession, prepareQuery, prepareArgs) {
|
|
4257
4383
|
const reprepareOnClient = (client) => {
|
|
4258
4384
|
const clientBoundSession = createClientBoundSession(baseSession, client);
|
|
4259
4385
|
return Reflect.apply(prepareQuery, clientBoundSession, prepareArgs);
|
|
@@ -4262,60 +4388,74 @@ function createBunSqlPreparedQueryClientExecutors(baseSession, prepareQuery, pre
|
|
|
4262
4388
|
execute(client, placeholderValues) {
|
|
4263
4389
|
return reprepareOnClient(client).execute(placeholderValues);
|
|
4264
4390
|
},
|
|
4265
|
-
all(client, placeholderValues) {
|
|
4391
|
+
all: typeof pq.all === "function" ? (client, placeholderValues) => {
|
|
4266
4392
|
const txPreparedQuery = reprepareOnClient(client);
|
|
4267
4393
|
if (typeof txPreparedQuery.all === "function") {
|
|
4268
4394
|
return txPreparedQuery.all(placeholderValues);
|
|
4269
4395
|
}
|
|
4270
4396
|
return txPreparedQuery.execute(placeholderValues);
|
|
4271
|
-
}
|
|
4397
|
+
} : void 0
|
|
4272
4398
|
};
|
|
4273
4399
|
}
|
|
4274
4400
|
function createPreparedQueryClientExecutors(params) {
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
}
|
|
4282
|
-
return createGenericPreparedQueryClientExecutors(params.pq);
|
|
4401
|
+
return createSessionBoundPreparedQueryClientExecutors(
|
|
4402
|
+
params.pq,
|
|
4403
|
+
params.baseSession,
|
|
4404
|
+
params.prepareQuery,
|
|
4405
|
+
params.prepareArgs
|
|
4406
|
+
);
|
|
4283
4407
|
}
|
|
4284
|
-
async function runPreparedQueryWithRls(session, rls, reuseOuterConnection, runOnClient, placeholderValues) {
|
|
4285
|
-
const active =
|
|
4408
|
+
async function runPreparedQueryWithRls(session, rls, reuseOuterConnection, scope, runOnClient, placeholderValues) {
|
|
4409
|
+
const active = currentRlsExecution(scope);
|
|
4286
4410
|
if (active) {
|
|
4287
|
-
return runOnClient(active, placeholderValues);
|
|
4411
|
+
return runOnClient(active.client, placeholderValues);
|
|
4288
4412
|
}
|
|
4289
4413
|
return withRlsConnection(
|
|
4290
4414
|
session,
|
|
4291
4415
|
rls,
|
|
4292
4416
|
reuseOuterConnection,
|
|
4417
|
+
scope,
|
|
4293
4418
|
(client) => runOnClient(client, placeholderValues)
|
|
4294
4419
|
);
|
|
4295
4420
|
}
|
|
4296
|
-
function wrapPreparedQuery(pq, session, baseSession, prepareQuery, prepareArgs, rls, reuseOuterConnection) {
|
|
4421
|
+
function wrapPreparedQuery(pq, session, baseSession, prepareQuery, prepareArgs, rls, reuseOuterConnection, scope) {
|
|
4297
4422
|
const clientExecutors = createPreparedQueryClientExecutors({
|
|
4298
4423
|
pq,
|
|
4299
4424
|
baseSession,
|
|
4300
4425
|
prepareQuery,
|
|
4301
4426
|
prepareArgs
|
|
4302
4427
|
});
|
|
4303
|
-
pq.execute = (placeholderValues) => runPreparedQueryWithRls(
|
|
4428
|
+
pq.execute = (placeholderValues) => runPreparedQueryWithRls(
|
|
4429
|
+
session,
|
|
4430
|
+
rls,
|
|
4431
|
+
reuseOuterConnection,
|
|
4432
|
+
scope,
|
|
4433
|
+
clientExecutors.execute,
|
|
4434
|
+
placeholderValues
|
|
4435
|
+
);
|
|
4304
4436
|
if (clientExecutors.all) {
|
|
4305
|
-
pq.all = (placeholderValues) => runPreparedQueryWithRls(
|
|
4437
|
+
pq.all = (placeholderValues) => runPreparedQueryWithRls(
|
|
4438
|
+
session,
|
|
4439
|
+
rls,
|
|
4440
|
+
reuseOuterConnection,
|
|
4441
|
+
scope,
|
|
4442
|
+
clientExecutors.all,
|
|
4443
|
+
placeholderValues
|
|
4444
|
+
);
|
|
4306
4445
|
}
|
|
4307
4446
|
}
|
|
4308
|
-
function wrapSession(session, rls, reuseOuterConnection) {
|
|
4447
|
+
function wrapSession(session, rls, reuseOuterConnection, scope) {
|
|
4309
4448
|
return new Proxy(session, {
|
|
4310
4449
|
get(sTarget, sProp, sRecv) {
|
|
4311
4450
|
if (sProp === "client") {
|
|
4312
|
-
return
|
|
4451
|
+
return matchingRlsExecutionClient(scope) ?? Reflect.get(sTarget, sProp, sRecv);
|
|
4313
4452
|
}
|
|
4314
4453
|
if (sProp === "prepareQuery") {
|
|
4315
4454
|
return (...args) => {
|
|
4316
4455
|
const prepareQuery = Reflect.get(sTarget, sProp, sRecv);
|
|
4456
|
+
if (typeof prepareQuery !== "function") throw createRlsUnsupportedError("session");
|
|
4317
4457
|
const pq = Reflect.apply(prepareQuery, sRecv, args);
|
|
4318
|
-
wrapPreparedQuery(pq, sRecv, sTarget, prepareQuery, args, rls, reuseOuterConnection);
|
|
4458
|
+
wrapPreparedQuery(pq, sRecv, sTarget, prepareQuery, args, rls, reuseOuterConnection, scope);
|
|
4319
4459
|
return pq;
|
|
4320
4460
|
};
|
|
4321
4461
|
}
|
|
@@ -4326,15 +4466,32 @@ function wrapSession(session, rls, reuseOuterConnection) {
|
|
|
4326
4466
|
}
|
|
4327
4467
|
function createRlsDb(db, rls, options = {}) {
|
|
4328
4468
|
const reuseOuterConnection = isDrizzleTransactionDb(db);
|
|
4329
|
-
const
|
|
4330
|
-
const
|
|
4469
|
+
const database = db;
|
|
4470
|
+
const baseSession = database.session ?? database._?.session;
|
|
4471
|
+
if (!baseSession || typeof baseSession !== "object") {
|
|
4472
|
+
throw createRlsUnsupportedError("session");
|
|
4473
|
+
}
|
|
4474
|
+
if (hasUnpartitionedRlsCache(db, baseSession)) {
|
|
4475
|
+
throw createRlsUnsupportedError("cache");
|
|
4476
|
+
}
|
|
4477
|
+
const scope = createRlsScopeToken();
|
|
4478
|
+
const wrappedSession = wrapSession(baseSession, rls, reuseOuterConnection, scope);
|
|
4479
|
+
const baseQuery = Reflect.get(db, "query", db);
|
|
4480
|
+
const scopedQuery = baseQuery && typeof baseQuery === "object" ? createRlsRelationalQueryRegistry(baseQuery, wrappedSession, baseSession) : baseQuery;
|
|
4331
4481
|
return new Proxy(db, {
|
|
4332
4482
|
get(target, prop, receiver) {
|
|
4483
|
+
if (prop === "query") {
|
|
4484
|
+
return scopedQuery;
|
|
4485
|
+
}
|
|
4486
|
+
if (prop === "$client") {
|
|
4487
|
+
return Reflect.get(target, prop, target);
|
|
4488
|
+
}
|
|
4333
4489
|
if (prop === "session") {
|
|
4334
4490
|
return wrappedSession;
|
|
4335
4491
|
}
|
|
4336
4492
|
if (prop === "_") {
|
|
4337
|
-
const inner = target
|
|
4493
|
+
const inner = Reflect.get(target, prop, receiver);
|
|
4494
|
+
if (!inner || typeof inner !== "object") return inner;
|
|
4338
4495
|
return new Proxy(inner, {
|
|
4339
4496
|
get(i, p, r) {
|
|
4340
4497
|
if (p === "session") return wrappedSession;
|
|
@@ -4344,6 +4501,7 @@ function createRlsDb(db, rls, options = {}) {
|
|
|
4344
4501
|
}
|
|
4345
4502
|
if (prop === "transaction") {
|
|
4346
4503
|
return async (callback, ...rest) => {
|
|
4504
|
+
assertRlsScopeMayEnter(scope);
|
|
4347
4505
|
let callbackStarted = false;
|
|
4348
4506
|
const configStatement = transactionConfigSql(rest[0]);
|
|
4349
4507
|
const transactionArgs = configStatement ? [] : rest;
|
|
@@ -4353,7 +4511,7 @@ function createRlsDb(db, rls, options = {}) {
|
|
|
4353
4511
|
if (configStatement) await tx.execute(configStatement);
|
|
4354
4512
|
await injectRlsVarsOnTx(tx, rls, options.onTransactionContextFailure);
|
|
4355
4513
|
callbackStarted = true;
|
|
4356
|
-
return await callback(tx);
|
|
4514
|
+
return await runWithRlsTransactionScope(scope, tx, () => callback(tx));
|
|
4357
4515
|
},
|
|
4358
4516
|
...transactionArgs
|
|
4359
4517
|
);
|
|
@@ -4371,13 +4529,14 @@ function createRlsDb(db, rls, options = {}) {
|
|
|
4371
4529
|
}
|
|
4372
4530
|
if (prop === "transactionWithCharacteristics") {
|
|
4373
4531
|
return async (characteristics, callback) => {
|
|
4532
|
+
assertRlsScopeMayEnter(scope);
|
|
4374
4533
|
return await target.transaction(async (tx) => {
|
|
4375
4534
|
await applyTransactionConfig(tx, {
|
|
4376
4535
|
...characteristics?.isolationLevel ? { isolationLevel: characteristics.isolationLevel } : {},
|
|
4377
4536
|
...characteristics?.readOnly ? { accessMode: "read only" } : {}
|
|
4378
4537
|
});
|
|
4379
4538
|
await injectRlsVarsOnTx(tx, rls, options.onTransactionContextFailure);
|
|
4380
|
-
return callback(tx);
|
|
4539
|
+
return runWithRlsTransactionScope(scope, tx, () => callback(tx));
|
|
4381
4540
|
});
|
|
4382
4541
|
};
|
|
4383
4542
|
}
|
|
@@ -4401,6 +4560,7 @@ import {
|
|
|
4401
4560
|
ilike,
|
|
4402
4561
|
inArray,
|
|
4403
4562
|
notInArray,
|
|
4563
|
+
isNull,
|
|
4404
4564
|
or,
|
|
4405
4565
|
and,
|
|
4406
4566
|
count as drizzleCount,
|
|
@@ -4451,6 +4611,13 @@ function detectOwnerMeta(table) {
|
|
|
4451
4611
|
}
|
|
4452
4612
|
try {
|
|
4453
4613
|
const config = getTableConfig(table);
|
|
4614
|
+
const declared = getOwnerRlsMeta(table);
|
|
4615
|
+
if (declared) {
|
|
4616
|
+
const propertyName = resolvePropertyName(table, declared.columnName);
|
|
4617
|
+
const column = anyTable[propertyName];
|
|
4618
|
+
if (column)
|
|
4619
|
+
return { column, columnName: declared.columnName, propertyName, readPublic: declared.readPublic };
|
|
4620
|
+
}
|
|
4454
4621
|
if (config.policies && config.policies.length > 0) {
|
|
4455
4622
|
const propName = anyTable["userId"] ? "userId" : anyTable["user_id"] ? "user_id" : null;
|
|
4456
4623
|
if (propName) {
|
|
@@ -4571,7 +4738,7 @@ function crud(table, options) {
|
|
|
4571
4738
|
const conditions = [];
|
|
4572
4739
|
if (options?.softDelete) {
|
|
4573
4740
|
const sdField = anyTable[options.softDelete.field];
|
|
4574
|
-
conditions.push(
|
|
4741
|
+
conditions.push(isNull(sdField));
|
|
4575
4742
|
}
|
|
4576
4743
|
if (args?.search && options?.searchFields?.length) {
|
|
4577
4744
|
const searchConds = options.searchFields.map(
|
|
@@ -4662,7 +4829,7 @@ function crud(table, options) {
|
|
|
4662
4829
|
}
|
|
4663
4830
|
if (options?.softDelete) {
|
|
4664
4831
|
const sdField = anyTable[options.softDelete.field];
|
|
4665
|
-
whereCond = and(whereCond,
|
|
4832
|
+
whereCond = and(whereCond, isNull(sdField));
|
|
4666
4833
|
}
|
|
4667
4834
|
return await inRlsOrPlainTx(ctx.db, async (tx) => {
|
|
4668
4835
|
const [result] = await tx.select().from(anyTable).where(whereCond).limit(1);
|
|
@@ -4775,6 +4942,7 @@ import {
|
|
|
4775
4942
|
ilike as ilike3,
|
|
4776
4943
|
or as or3,
|
|
4777
4944
|
and as and3,
|
|
4945
|
+
isNull as isNull2,
|
|
4778
4946
|
count as drizzleCount2,
|
|
4779
4947
|
getTableName as getTableName4,
|
|
4780
4948
|
getTableColumns as getTableColumns3
|
|
@@ -4956,6 +5124,13 @@ function detectOwnerMeta2(table) {
|
|
|
4956
5124
|
}
|
|
4957
5125
|
try {
|
|
4958
5126
|
const config = getTableConfig2(table);
|
|
5127
|
+
const declared = getOwnerRlsMeta(table);
|
|
5128
|
+
if (declared) {
|
|
5129
|
+
const propertyName = resolvePropertyName2(table, declared.columnName);
|
|
5130
|
+
const column = anyTable[propertyName];
|
|
5131
|
+
if (column)
|
|
5132
|
+
return { column, columnName: declared.columnName, propertyName, readPublic: declared.readPublic };
|
|
5133
|
+
}
|
|
4959
5134
|
if (config.policies && config.policies.length > 0) {
|
|
4960
5135
|
const propName = anyTable["userId"] ? "userId" : anyTable["user_id"] ? "user_id" : null;
|
|
4961
5136
|
if (propName) {
|
|
@@ -5290,7 +5465,7 @@ function buildCrud(table, options, procedure) {
|
|
|
5290
5465
|
const conditions = [];
|
|
5291
5466
|
if (options?.softDelete) {
|
|
5292
5467
|
const sdField = anyTable[options.softDelete.field];
|
|
5293
|
-
conditions.push(
|
|
5468
|
+
conditions.push(isNull2(sdField));
|
|
5294
5469
|
}
|
|
5295
5470
|
if (args.search && options?.searchFields?.length) {
|
|
5296
5471
|
if (disableILike) {
|
|
@@ -5568,7 +5743,7 @@ function buildCrud(table, options, procedure) {
|
|
|
5568
5743
|
}
|
|
5569
5744
|
if (options?.softDelete) {
|
|
5570
5745
|
const sdField = anyTable[options.softDelete.field];
|
|
5571
|
-
whereCond = and3(whereCond,
|
|
5746
|
+
whereCond = and3(whereCond, isNull2(sdField));
|
|
5572
5747
|
}
|
|
5573
5748
|
return whereCond;
|
|
5574
5749
|
}
|
|
@@ -5677,15 +5852,18 @@ function buildCrud(table, options, procedure) {
|
|
|
5677
5852
|
if (options?.hooks?.beforeUpdate) {
|
|
5678
5853
|
updateData = await options.hooks.beforeUpdate(updateData);
|
|
5679
5854
|
}
|
|
5680
|
-
const { result, preRealtimeRow, postRealtimeRow } = await inRlsOrPlainTx(
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
postRow =
|
|
5855
|
+
const { result, preRealtimeRow, postRealtimeRow } = await inRlsOrPlainTx(
|
|
5856
|
+
context.db,
|
|
5857
|
+
async (tx) => {
|
|
5858
|
+
const preRow = crudRealtime.explicitScopedList ? await selectFullRowForRealtime(tx, updateWhere) : null;
|
|
5859
|
+
const [updated] = listProjection !== void 0 ? await tx.update(anyTable).set(updateData).where(updateWhere).returning(listProjection) : await tx.update(anyTable).set(updateData).where(updateWhere).returning();
|
|
5860
|
+
let postRow = updated ?? null;
|
|
5861
|
+
if (crudRealtime.explicitScopedList && updated) {
|
|
5862
|
+
postRow = await selectFullRowForRealtime(tx, eq3(pk, idVal));
|
|
5863
|
+
}
|
|
5864
|
+
return { result: updated, preRealtimeRow: preRow, postRealtimeRow: postRow };
|
|
5686
5865
|
}
|
|
5687
|
-
|
|
5688
|
-
});
|
|
5866
|
+
);
|
|
5689
5867
|
if (crudRealtime.enabled) {
|
|
5690
5868
|
const mutationEventId = createCrudRealtimeEventId();
|
|
5691
5869
|
let listInvalidationError;
|