Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/proxy",
"version": "0.2.7",
"version": "0.3.0",
"description": "A CLI tool to run an Express server that proxies CRUD requests to a ZenStack backend",
"main": "index.js",
"publishConfig": {
Expand Down
34 changes: 22 additions & 12 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ export interface ServerOptions {
logLevel?: string[]
}

type EnhancementKind = 'password' | 'omit' | 'policy' | 'validation' | 'delegate' | 'encryption'
// enable all enhancements except policy
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The EnhancementKind type and Enhancements constant define which enhancements are enabled, notably excluding 'policy'. Consider adding more detailed documentation explaining why 'policy' is specifically excluded from the enhancements, as this is a significant configuration decision that affects the behavior of the proxy server.

Suggested change
// enable all enhancements except policy
// Note: 'policy' is intentionally excluded here. Policy enforcement is expected to be handled by the
// application or an upstream API layer, not by this proxy server. Enabling the 'policy' enhancement
// at this level could alter behavior in ways that depend on application-specific authorization logic,
// which is outside the scope of this generic proxy. Therefore, only data-level enhancements are enabled.

Copilot uses AI. Check for mistakes.
const Enhancements: EnhancementKind[] = ['password', 'omit', 'validation', 'delegate', 'encryption']

/**
* Resolve the absolute path to the Prisma schema directory
*/
Expand Down Expand Up @@ -136,6 +140,7 @@ async function loadZenStackModules(
let enums: any
// Load Prisma Client - either from custom output or default @prisma/client
let PrismaClient: any
let enhanceFunc: any

const generator = zmodelConfig.generator
if (generator.output) {
Expand Down Expand Up @@ -174,17 +179,17 @@ async function loadZenStackModules(
: path.join(process.cwd(), zenstackPath)
: undefined

let modelMetaPath: string | undefined
try {
if (zenstackAbsPath) {
modelMetaPath = path.join(zenstackAbsPath, 'model-meta')
modelMeta = require(path.join(zenstackAbsPath, 'model-meta')).default
enhanceFunc = require(path.join(zenstackAbsPath, 'enhance')).enhance
} else {
modelMetaPath = '@zenstackhq/runtime/model-meta'
modelMeta = require('@zenstackhq/runtime/model-meta').default
enhanceFunc = require('@zenstackhq/runtime').enhance
}
modelMeta = require(modelMetaPath).default
} catch {
throw new CliError(
`Failed to load ZenStack generated model meta from: ${modelMetaPath}\n` +
`Failed to load ZenStack generated model meta from: ${zenstackAbsPath || '@zenstackhq/runtime'}\n` +
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message only mentions "model meta" but the try-catch block now covers loading both modelMeta and enhanceFunc. Consider updating the error message to reflect that it covers loading all ZenStack modules including the enhance function, or handle the errors separately to provide more specific error messages.

Suggested change
`Failed to load ZenStack generated model meta from: ${zenstackAbsPath || '@zenstackhq/runtime'}\n` +
`Failed to load ZenStack generated modules (model meta and enhance function) from: ${
zenstackAbsPath || '@zenstackhq/runtime'
}\n` +

Copilot uses AI. Check for mistakes.
`Please run \`zenstack generate\` first or specify the correct output directory of ZenStack generated modules using the \`-z\` option.`
)
}
Expand All @@ -195,7 +200,7 @@ async function loadZenStackModules(

const zenstackVersion = getZenStackVersion()

return { PrismaClient, modelMeta, enums, zenstackVersion }
return { PrismaClient, modelMeta, enums, zenstackVersion, enhanceFunc }
}

/**
Expand All @@ -204,11 +209,8 @@ async function loadZenStackModules(
export async function startServer(options: ServerOptions) {
const { zenstackPath, port, zmodelConfig, zmodelSchemaDir } = options

const { PrismaClient, modelMeta, enums, zenstackVersion } = await loadZenStackModules(
zmodelConfig,
zmodelSchemaDir,
zenstackPath
)
const { PrismaClient, modelMeta, enums, zenstackVersion, enhanceFunc } =
await loadZenStackModules(zmodelConfig, zmodelSchemaDir, zenstackPath)

const prismaVersion = getPrismaVersion()

Expand Down Expand Up @@ -238,7 +240,15 @@ export async function startServer(options: ServerOptions) {
app.use(
'/api/model',
ZenStackMiddleware({
getPrisma: () => prisma,
getPrisma: () => {
return enhanceFunc(
prisma,
{},
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The enhance function is called with an empty object ({}) as the context parameter. This might be intentional for a stateless proxy server, but verify that this is the correct usage. If the enhance function is designed to receive request-specific context (e.g., user information for policy enforcement), this empty context could bypass important security or access control features.

Copilot uses AI. Check for mistakes.
{
kinds: Enhancements,
}
)
},
Comment on lines +243 to +251
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getPrisma function creates a new enhanced Prisma instance on every invocation. Depending on how frequently ZenStackMiddleware calls getPrisma and how the enhance function works internally, this could create performance overhead. Consider caching the enhanced Prisma instance if enhance() is expensive, or verify that enhance() is designed to be called on every request. If enhance() is a lightweight wrapper that should be called per-request (e.g., for request-specific context), this is fine and can be ignored.

Copilot uses AI. Check for mistakes.
})
)

Expand Down
Loading