@friggframework/core 2.0.0--canary.707.df80bfd.0 → 2.0.0--canary.680.d670696.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.
Files changed (161) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/CLAUDE.md +0 -28
  3. package/README.md +0 -105
  4. package/application/commands/integration-commands.js +2 -2
  5. package/application/commands/scheduler-commands.js +7 -11
  6. package/application/commands/user-commands.js +5 -17
  7. package/core/Worker.js +7 -31
  8. package/core/create-handler.js +0 -9
  9. package/credential/use-cases/credential-operations-for-user.js +25 -110
  10. package/credential/use-cases/reauthorize-credential-for-user.js +8 -15
  11. package/database/config.js +24 -48
  12. package/database/documentdb-encryption-service.js +0 -1
  13. package/database/documentdb-utils.js +1 -6
  14. package/database/encryption/encryption-config.js +44 -13
  15. package/database/encryption/encryption-schema-registry.js +31 -88
  16. package/database/prisma.js +2 -4
  17. package/generated/prisma-mongodb/edge.js +4 -27
  18. package/generated/prisma-mongodb/index-browser.js +1 -24
  19. package/generated/prisma-mongodb/index.d.ts +48 -3228
  20. package/generated/prisma-mongodb/index.js +4 -27
  21. package/generated/prisma-mongodb/package.json +1 -1
  22. package/generated/prisma-mongodb/schema.prisma +0 -65
  23. package/generated/prisma-mongodb/wasm.js +4 -27
  24. package/generated/prisma-postgresql/edge.js +4 -27
  25. package/generated/prisma-postgresql/index-browser.js +1 -24
  26. package/generated/prisma-postgresql/index.d.ts +51 -3503
  27. package/generated/prisma-postgresql/index.js +4 -27
  28. package/generated/prisma-postgresql/package.json +1 -1
  29. package/generated/prisma-postgresql/schema.prisma +0 -61
  30. package/generated/prisma-postgresql/wasm.js +4 -27
  31. package/handlers/app-definition-loader.js +12 -110
  32. package/handlers/routers/auth.js +12 -40
  33. package/handlers/routers/health.js +2 -4
  34. package/handlers/routers/integration-defined-routers.js +92 -144
  35. package/handlers/routers/integration-webhook-routers.js +64 -102
  36. package/index.js +1 -64
  37. package/infrastructure/scheduler/index.js +6 -19
  38. package/infrastructure/scheduler/scheduler-service-factory.js +7 -55
  39. package/integrations/index.js +0 -5
  40. package/integrations/integration-router.js +73 -115
  41. package/integrations/repositories/integration-repository-documentdb.js +3 -35
  42. package/integrations/repositories/integration-repository-interface.js +1 -17
  43. package/integrations/repositories/integration-repository-mongo.js +76 -59
  44. package/integrations/repositories/integration-repository-postgres.js +76 -62
  45. package/integrations/tests/doubles/test-integration-repository.js +1 -12
  46. package/integrations/use-cases/create-integration.js +20 -55
  47. package/integrations/use-cases/get-integrations-for-user.js +40 -80
  48. package/integrations/use-cases/index.js +1 -7
  49. package/integrations/use-cases/integration-operations-for-user.js +24 -55
  50. package/integrations/utils/map-integration-dto.js +1 -44
  51. package/management-api/management-api-config.js +2 -71
  52. package/management-api/meta-router.js +2 -21
  53. package/management-api/openapi/components.js +3 -50
  54. package/management-api/openapi/v2-operations.js +5 -17
  55. package/management-api/route-registry.js +6 -123
  56. package/management-api/v2/dependencies.js +15 -40
  57. package/management-api/v2/dto.js +0 -20
  58. package/management-api/v2/handlers/authorization.js +0 -1
  59. package/management-api/v2/handlers/credentials.js +2 -6
  60. package/management-api/v2/handlers/entities.js +7 -10
  61. package/management-api/v2/handlers/integrations.js +3 -6
  62. package/management-api/v2/request.js +1 -32
  63. package/modules/index.js +0 -8
  64. package/modules/module-factory.js +0 -12
  65. package/modules/module.js +2 -53
  66. package/modules/proxy/proxy-errors.js +1 -12
  67. package/modules/proxy/proxy-path.js +3 -7
  68. package/modules/proxy/proxy-policy.js +5 -34
  69. package/modules/repositories/module-repository-documentdb.js +6 -51
  70. package/modules/repositories/module-repository-interface.js +2 -19
  71. package/modules/repositories/module-repository-mongo.js +74 -67
  72. package/modules/repositories/module-repository-postgres.js +74 -66
  73. package/modules/repositories/module-repository.js +1 -2
  74. package/modules/requester/proxy-request.js +1 -2
  75. package/modules/requester/requester.js +3 -8
  76. package/modules/use-cases/entity-operations-for-user.js +13 -50
  77. package/modules/use-cases/entity-types.js +7 -31
  78. package/modules/use-cases/execute-entity-proxy-request.js +15 -107
  79. package/modules/use-cases/get-authorization-requirements.js +2 -2
  80. package/modules/use-cases/get-entities-for-user.js +13 -26
  81. package/modules/use-cases/get-entity-module-for-user.js +7 -34
  82. package/modules/use-cases/get-entity-options-by-id.js +4 -10
  83. package/modules/use-cases/get-entity-options-by-type.js +1 -1
  84. package/modules/use-cases/get-module-instance-from-type.js +1 -1
  85. package/modules/use-cases/get-module.js +4 -10
  86. package/modules/use-cases/multi-step-authorization.js +13 -40
  87. package/modules/use-cases/process-authorization-callback.js +19 -53
  88. package/modules/use-cases/refresh-entity-options.js +4 -10
  89. package/modules/use-cases/test-module-auth.js +4 -10
  90. package/package.json +5 -6
  91. package/prisma-mongodb/schema.prisma +0 -65
  92. package/prisma-postgresql/schema.prisma +0 -61
  93. package/queues/index.js +0 -25
  94. package/types/index.d.ts +0 -1
  95. package/types/modules/index.d.ts +1 -157
  96. package/user/repositories/user-repository-documentdb.js +2 -27
  97. package/user/repositories/user-repository-interface.js +0 -18
  98. package/user/repositories/user-repository-mongo.js +0 -24
  99. package/user/repositories/user-repository-postgres.js +0 -18
  100. package/user/use-cases/authenticate-user.js +1 -7
  101. package/user/use-cases/get-user-from-adopter-jwt.js +124 -95
  102. package/user/use-cases/get-user-from-x-frigg-headers.js +80 -83
  103. package/user/user.js +1 -64
  104. package/database/organization-where.js +0 -18
  105. package/database/unique-violation.js +0 -25
  106. package/extensions/bootstrap-runner.js +0 -43
  107. package/extensions/extension-loader.js +0 -230
  108. package/extensions/index.js +0 -44
  109. package/extensions/initialize-app.js +0 -123
  110. package/extensions/prisma-composer.js +0 -270
  111. package/extensions/route-mounter.js +0 -103
  112. package/extensions/schema-composer.js +0 -188
  113. package/infrastructure/scheduler/netlify-scheduler-adapter.js +0 -216
  114. package/infrastructure/scheduler/scheduled-job-repository.js +0 -118
  115. package/integrations/repositories/integration-not-found.js +0 -14
  116. package/integrations/schedule-config.js +0 -80
  117. package/integrations/use-cases/dispatch-ongoing-syncs.js +0 -100
  118. package/integrations/use-cases/resolve-integration-ownership.js +0 -177
  119. package/modules/entity-scope.js +0 -15
  120. package/modules/proxy/proxy-bases.js +0 -169
  121. package/modules/repositories/entity-not-found.js +0 -18
  122. package/modules/scope-config.js +0 -192
  123. package/modules/scope-policy.js +0 -112
  124. package/modules/scope-resolution.js +0 -288
  125. package/modules/scope-visibility.js +0 -247
  126. package/modules/tests/doubles/ownership-matching.js +0 -18
  127. package/modules/use-cases/authorize-entity-for-user.js +0 -61
  128. package/modules/use-cases/create-entity-from-credential.js +0 -113
  129. package/modules/use-cases/manage-access.js +0 -21
  130. package/prisma-postgresql/migrations/20261015000000_add_organization_membership/migration.sql +0 -26
  131. package/prisma-postgresql/migrations/20261016000000_add_entity_integration_organization/migration.sql +0 -25
  132. package/prisma-postgresql/migrations/20261017000000_add_scheduled_job/migration.sql +0 -28
  133. package/providers/index.js +0 -23
  134. package/providers/resolve-provider.js +0 -93
  135. package/providers/runtime-detection.js +0 -124
  136. package/queues/providers/index.js +0 -11
  137. package/queues/providers/netlify-background-provider.js +0 -150
  138. package/queues/providers/qstash-queue-provider.js +0 -219
  139. package/queues/providers/sqs-queue-provider.js +0 -70
  140. package/queues/queue-client-interface.js +0 -55
  141. package/queues/queue-message-auth.js +0 -193
  142. package/queues/queue-provider-factory.js +0 -101
  143. package/queues/queue-provider.js +0 -65
  144. package/queues/sqs-queue-client.js +0 -81
  145. package/types/user/index.d.ts +0 -134
  146. package/user/adopter-jwt-config.js +0 -177
  147. package/user/adopter-jwt-errors.js +0 -59
  148. package/user/adopter-token-verifier.js +0 -122
  149. package/user/app-user-helpers.js +0 -97
  150. package/user/create-user-authentication.js +0 -64
  151. package/user/membership.js +0 -51
  152. package/user/repositories/organization-membership-record.js +0 -19
  153. package/user/repositories/organization-membership-repository-documentdb.js +0 -106
  154. package/user/repositories/organization-membership-repository-factory.js +0 -42
  155. package/user/repositories/organization-membership-repository-interface.js +0 -57
  156. package/user/repositories/organization-membership-repository-mongo.js +0 -13
  157. package/user/repositories/organization-membership-repository-postgres.js +0 -29
  158. package/user/repositories/organization-membership-repository-prisma.js +0 -81
  159. package/user/tests/doubles/adopter-jwt-fixtures.js +0 -220
  160. package/user/use-cases/ensure-organization-membership.js +0 -92
  161. package/user/use-cases/find-individual-users-by-organization.js +0 -54
@@ -3,39 +3,6 @@
3
3
  * Manages configuration for Prisma ORM operations
4
4
  */
5
5
 
6
- /**
7
- * Maps an app definition's `database` block to a Prisma database type.
8
- *
9
- * @param {Object|undefined} database - `Definition.database`
10
- * @param {string} where - where the definition lives, for the error message
11
- * @returns {'mongodb'|'postgresql'|'documentdb'}
12
- */
13
- function databaseTypeFromConfig(database, where) {
14
- if (!database) {
15
- throw new Error(
16
- '[Frigg] App definition missing database configuration. ' +
17
- `Add database: { postgres: { enable: true } } (or mongoDB/documentDB) to ${where}`
18
- );
19
- }
20
-
21
- // Determine database type from enabled database
22
- // Priority order: postgres > mongoDB > documentDB
23
- if (database.postgres?.enable === true) {
24
- return 'postgresql';
25
- }
26
- if (database.mongoDB?.enable === true) {
27
- return 'mongodb';
28
- }
29
- if (database.documentDB?.enable === true) {
30
- return 'documentdb';
31
- }
32
-
33
- throw new Error(
34
- '[Frigg] No database enabled in app definition. ' +
35
- 'Set one of: database.postgres.enable, database.mongoDB.enable, or database.documentDB.enable to true'
36
- );
37
- }
38
-
39
6
  /**
40
7
  * Determines database type from environment or app definition
41
8
  *
@@ -54,20 +21,6 @@ function getDatabaseType() {
54
21
 
55
22
  // Fallback: Load app definition
56
23
  try {
57
- // A definition preset with setAppDefinition() (provider-netlify's
58
- // function preamble) wins: on Netlify process.cwd() is the function
59
- // root at runtime, so discovery cannot find the backend.
60
- const {
61
- getPresetAppDefinition,
62
- } = require('../handlers/app-definition-loader');
63
- const preset = getPresetAppDefinition();
64
- if (preset) {
65
- return databaseTypeFromConfig(
66
- preset.database,
67
- 'your backend/index.js'
68
- );
69
- }
70
-
71
24
  const path = require('node:path');
72
25
  const fs = require('node:fs');
73
26
  const { findNearestBackendPackageJson } = require('../utils');
@@ -123,7 +76,30 @@ function getDatabaseType() {
123
76
  }
124
77
 
125
78
  database = backendModule?.Definition?.database;
126
- return databaseTypeFromConfig(database, backendIndexPath);
79
+
80
+ if (!database) {
81
+ throw new Error(
82
+ '[Frigg] App definition missing database configuration. ' +
83
+ `Add database: { postgres: { enable: true } } (or mongoDB/documentDB) to ${backendIndexPath}`
84
+ );
85
+ }
86
+
87
+ // Determine database type from enabled database
88
+ // Priority order: postgres > mongoDB > documentDB
89
+ if (database.postgres?.enable === true) {
90
+ return 'postgresql';
91
+ }
92
+ if (database.mongoDB?.enable === true) {
93
+ return 'mongodb';
94
+ }
95
+ if (database.documentDB?.enable === true) {
96
+ return 'documentdb';
97
+ }
98
+
99
+ throw new Error(
100
+ '[Frigg] No database enabled in app definition. ' +
101
+ 'Set one of: database.postgres.enable, database.mongoDB.enable, or database.documentDB.enable to true'
102
+ );
127
103
  } catch (error) {
128
104
  // Re-throw with context if it's our error
129
105
  if (error.message.includes('[Frigg]')) {
@@ -251,7 +251,6 @@ class DocumentDBEncryptionService {
251
251
  const errorContext = {
252
252
  modelName,
253
253
  fieldPath,
254
- encryptedValuePrefix: encryptedValue.substring(0, 20),
255
254
  errorMessage: error.message
256
255
  };
257
256
 
@@ -58,12 +58,7 @@ async function insertOne(client, collection, document) {
58
58
 
59
59
  // Provide helpful context for common errors
60
60
  if (error.code === 11000) {
61
- // `code` lets callers recognise a lost race without parsing text
62
- // (see database/unique-violation.js).
63
- throw Object.assign(
64
- new Error(`${errorMsg} - Duplicate key violation`),
65
- { code: 11000 }
66
- );
61
+ throw new Error(`${errorMsg} - Duplicate key violation`);
67
62
  }
68
63
  throw new Error(errorMsg);
69
64
  }
@@ -18,9 +18,6 @@
18
18
  */
19
19
 
20
20
  const { logger } = require('./logger');
21
- const {
22
- isDeployedRuntime: isDeployedProviderRuntime,
23
- } = require('../../providers/runtime-detection');
24
21
 
25
22
  const LOCAL_BYPASS_STAGES = ['dev', 'test', 'local'];
26
23
  const OPT_OUT_VAR = 'FRIGG_ENCRYPTION_DISABLED';
@@ -43,18 +40,42 @@ function isTrue(value) {
43
40
  }
44
41
 
45
42
  /**
46
- * True when the process runs as a deployed function, on AWS Lambda or on the
47
- * active provider's platform (provider-netlify: FRIGG_PROVIDER=netlify, set by
48
- * its generated entry points), and not under a local emulator or test runner.
49
- * One rule for encryption and queue authentication: core/providers/
50
- * runtime-detection asks the provider's detect(), and fails closed when a
51
- * named non-AWS provider cannot be loaded.
43
+ * True when the process runs as a deployed function, on AWS Lambda or on
44
+ * another provider's platform.
45
+ *
46
+ * - AWS Lambda sets AWS_LAMBDA_FUNCTION_NAME, LAMBDA_TASK_ROOT and
47
+ * AWS_EXECUTION_ENV (AWS_Lambda_<runtime>). Other AWS hosts (CloudShell,
48
+ * CodeBuild, ECS) set AWS_EXECUTION_ENV to other values and count as local:
49
+ * CLI commands run from CI must not trip the deployed-stage check.
50
+ * - Other providers: FRIGG_PROVIDER names a non-AWS provider. Frigg's
51
+ * generated function entry points for that provider set it (provider-netlify
52
+ * sets 'netlify'), so it is present in every deployed function. Netlify
53
+ * exposes SITE_ID, CONTEXT and NETLIFY at build time only, so they cannot
54
+ * tell a running function from a laptop.
55
+ *
56
+ * A local run is never deployed: serverless-offline and `serverless invoke
57
+ * local` (which set the Lambda variables themselves) mark IS_OFFLINE /
58
+ * IS_LOCAL, `netlify dev` marks NETLIFY_DEV, and Jest marks JEST_WORKER_ID.
52
59
  *
53
60
  * @param {Object} [env=process.env]
54
61
  * @returns {boolean}
55
62
  */
56
63
  function isDeployedRuntime(env = process.env) {
57
- return isDeployedProviderRuntime(env);
64
+ const localRun =
65
+ isTrue(env.IS_OFFLINE) ||
66
+ isTrue(env.IS_LOCAL) ||
67
+ isTrue(env.NETLIFY_DEV) ||
68
+ isSet(env.JEST_WORKER_ID);
69
+ if (localRun) return false;
70
+
71
+ const onAwsRuntime =
72
+ isSet(env.AWS_LAMBDA_FUNCTION_NAME) ||
73
+ isSet(env.LAMBDA_TASK_ROOT) ||
74
+ String(env.AWS_EXECUTION_ENV ?? '').startsWith('AWS_Lambda_');
75
+ if (onAwsRuntime) return true;
76
+
77
+ const provider = String(env.FRIGG_PROVIDER ?? '').trim().toLowerCase();
78
+ return provider !== '' && provider !== 'aws';
58
79
  }
59
80
 
60
81
  function missingKeyMessage(stage) {
@@ -100,6 +121,10 @@ function resolveEncryptionConfig(env = process.env) {
100
121
  const runtime = isDeployedRuntime(env) ? 'deployed' : 'local';
101
122
  const hasKMS = isSet(env.KMS_KEY_ARN);
102
123
  const hasAES = isSet(env.AES_KEY_ID);
124
+ // AES needs the key as well as its id, locally too: a cryptor built from
125
+ // the id alone cannot encrypt, and a local run reads failed decrypts as
126
+ // stored values, so an incomplete pair would hand back blobs as tokens.
127
+ const hasCompleteAES = hasAES && isSet(env.AES_KEY);
103
128
  const optOutRequested = isTrue(env[OPT_OUT_VAR]);
104
129
 
105
130
  const base = {
@@ -120,14 +145,13 @@ function resolveEncryptionConfig(env = process.env) {
120
145
  if (LOCAL_BYPASS_STAGES.includes(String(stage).toLowerCase())) {
121
146
  return { ...base, bypassed: true };
122
147
  }
123
- if (hasKMS || hasAES) {
148
+ if (hasKMS || hasCompleteAES) {
124
149
  const method = hasKMS ? 'kms' : 'aes';
125
150
  return { ...base, enabled: true, method, mode: method };
126
151
  }
127
152
  return base;
128
153
  }
129
154
 
130
- const hasCompleteAES = hasAES && isSet(env.AES_KEY);
131
155
  if (hasKMS || hasCompleteAES) {
132
156
  const method = hasKMS ? 'kms' : 'aes';
133
157
  return {
@@ -191,7 +215,14 @@ function getEncryptionConfig(env = process.env) {
191
215
  );
192
216
  }
193
217
 
194
- if (config.runtime === 'local' && !config.enabled && !config.bypassed) {
218
+ if (config.runtime === 'local' && !config.enabled && !config.bypassed && config.hasAES) {
219
+ warnOnce(
220
+ 'local-incomplete-aes',
221
+ `AES_KEY_ID is set but AES_KEY is not for local stage "${config.stage}". ` +
222
+ 'Field-level encryption disabled for this local run; set both to encrypt. ' +
223
+ 'A deployed stage refuses to start without both.'
224
+ );
225
+ } else if (config.runtime === 'local' && !config.enabled && !config.bypassed) {
195
226
  warnOnce(
196
227
  'local-no-keys',
197
228
  `No encryption keys configured (KMS_KEY_ARN or AES_KEY_ID) for local stage "${config.stage}". ` +
@@ -9,6 +9,7 @@
9
9
  */
10
10
 
11
11
  const { logger } = require('./logger');
12
+ const { isDeployedRuntime } = require('./encryption-config');
12
13
  const { registerDeniedKeys } = require('../../logs/denied-keys');
13
14
  const {
14
15
  getEntityTypeRegistry,
@@ -229,85 +230,35 @@ function loadModuleEncryptionSchemas(integrations, entities) {
229
230
  *
230
231
  * Used by both Prisma (MongoDB/PostgreSQL) and DocumentDB encryption services.
231
232
  */
232
- /**
233
- * Registers encryption schemas declared by app-level extensions
234
- * (`appDefinition.coreExtensions[].encryption`), e.g. the db-credentials
235
- * extension's `OAuthAppCredential.clientSecret`.
236
- *
237
- * @param {Array<Object>} extensions - Normalized extensions (extension-loader)
238
- */
239
- function loadExtensionEncryptionSchemas(extensions) {
240
- if (!extensions || !Array.isArray(extensions) || extensions.length === 0) {
241
- return;
242
- }
243
-
244
- for (const ext of extensions) {
245
- if (!ext.encryption || typeof ext.encryption !== 'object') {
246
- continue;
247
- }
233
+ function loadCustomEncryptionSchema() {
234
+ let appDefinition;
235
+ try {
236
+ // Lazy require to avoid circular dependency issues
237
+ const path = require('node:path');
238
+ const { findNearestBackendPackageJson } = require('../../utils');
248
239
 
249
- const schema = {};
250
- for (const [modelName, config] of Object.entries(ext.encryption)) {
251
- if (config && Array.isArray(config.fields) && config.fields.length > 0) {
252
- schema[modelName] = { fields: config.fields };
253
- }
240
+ const backendPackagePath = findNearestBackendPackageJson();
241
+ if (!backendPackagePath) {
242
+ return; // No backend found, skip custom schema
254
243
  }
255
244
 
256
- if (Object.keys(schema).length > 0) {
257
- logger.info(
258
- `Registering encryption schema from extension "${ext.name}" for models: ${Object.keys(schema).join(', ')}`
259
- );
260
- // registerCustomSchema replaces the registered schema, so merge:
261
- // an extension adds its models to the app's encryption.schema
262
- // rather than dropping it.
263
- const merged = { ...customSchema };
264
- for (const [modelName, config] of Object.entries(schema)) {
265
- const existing = merged[modelName]?.fields || [];
266
- merged[modelName] = {
267
- ...merged[modelName],
268
- fields: [...new Set([...existing, ...config.fields])],
269
- };
270
- }
271
- registerCustomSchema(merged);
272
- }
273
- }
274
- }
245
+ const backendDir = path.dirname(backendPackagePath);
246
+ const backendIndexPath = path.join(backendDir, 'index.js');
275
247
 
276
- function readAppDefinitionForEncryption() {
277
- // Lazy require to avoid circular dependency issues
278
- const {
279
- getPresetAppDefinition,
280
- } = require('../../handlers/app-definition-loader');
281
- // A definition preset with setAppDefinition() (provider-netlify's
282
- // preamble) wins: on Netlify process.cwd() cannot find the backend.
283
- const preset = getPresetAppDefinition();
284
- if (preset) {
285
- return preset;
248
+ const backendModule = require(backendIndexPath);
249
+ appDefinition = backendModule?.Definition;
250
+ } catch (error) {
251
+ // No app definition to read (tests, standalone usage): there is
252
+ // nothing to register, so nothing is lost by carrying on.
253
+ logger.debug('Could not load custom encryption schema:', error.message);
254
+ return;
286
255
  }
287
256
 
288
- const path = require('node:path');
289
- const { findNearestBackendPackageJson } = require('../../utils');
290
-
291
- const backendPackagePath = findNearestBackendPackageJson();
292
- if (!backendPackagePath) {
293
- return null; // No backend found, skip custom schema
257
+ if (!appDefinition) {
258
+ return; // No app definition found
294
259
  }
295
260
 
296
- const backendDir = path.dirname(backendPackagePath);
297
- const backendIndexPath = path.join(backendDir, 'index.js');
298
-
299
- const backendModule = require(backendIndexPath);
300
- return backendModule?.Definition || null;
301
- }
302
-
303
- function loadCustomEncryptionSchema() {
304
261
  try {
305
- const appDefinition = readAppDefinitionForEncryption();
306
-
307
- if (!appDefinition) {
308
- return; // No app definition found
309
- }
310
-
311
262
  // Load app-level custom schema
312
263
  const customSchema = appDefinition.encryption?.schema;
313
264
  if (customSchema && Object.keys(customSchema).length > 0) {
@@ -322,15 +273,6 @@ function loadCustomEncryptionSchema() {
322
273
  registerEncryptionOptOut(disable);
323
274
  }
324
275
 
325
- // Load app-level extension encryption schemas. Before the module
326
- // schemas: loadModuleEncryptionSchemas currently throws (see the
327
- // NOTE inside it) and the throw would skip anything after it.
328
- const { loadExtensions } = require('../../extensions/extension-loader');
329
- const extensions = loadExtensions(appDefinition);
330
- if (extensions.length > 0) {
331
- loadExtensionEncryptionSchemas(extensions);
332
- }
333
-
334
276
  // Load module-level encryption schemas from integrations
335
277
  const integrations = appDefinition.integrations;
336
278
  if (Array.isArray(integrations) || appDefinition.entities) {
@@ -340,14 +282,16 @@ function loadCustomEncryptionSchema() {
340
282
  );
341
283
  }
342
284
  } catch (error) {
343
- // A bad entity registry is a configuration error, not "no custom schema".
344
- if (error instanceof EntityRegistryError) throw error;
345
- // Silently ignore errors - custom schema is optional
346
- // This handles cases like:
347
- // - Backend package.json not found (tests, standalone usage)
348
- // - No appDefinition defined
349
- // - No custom encryption schema specified
350
- logger.debug('Could not load custom encryption schema:', error.message);
285
+ // The app declared fields to encrypt and they could not be registered:
286
+ // carrying on would store them in plaintext. A bad entity registry is a
287
+ // configuration error anywhere; a deployed function refuses to start
288
+ // for any registration failure, and a local run says so loudly.
289
+ if (error instanceof EntityRegistryError || isDeployedRuntime()) {
290
+ throw error;
291
+ }
292
+ logger.warn(
293
+ `Encryption schema from the app definition could not be registered; those fields stay plaintext in this local run: ${error.message}`
294
+ );
351
295
  }
352
296
  }
353
297
 
@@ -492,7 +436,6 @@ module.exports = {
492
436
  registerEncryptionOptOut,
493
437
  loadCustomEncryptionSchema,
494
438
  loadModuleEncryptionSchemas,
495
- loadExtensionEncryptionSchemas,
496
439
  extractCredentialFieldsFromModules,
497
440
  validateCustomSchema,
498
441
  validateOptOut,
@@ -41,15 +41,13 @@ const prismaClientSingleton = () => {
41
41
  const paths = [
42
42
  // Lambda layer location (when using Prisma Lambda layer)
43
43
  `/opt/nodejs/node_modules/generated/prisma-${dbType}`,
44
- // __dirname-based absolute path (Netlify functions and bundlers)
45
- require('node:path').resolve(__dirname, `../generated/prisma-${dbType}`),
46
44
  // Local development location (relative to core package)
47
45
  `../generated/prisma-${dbType}`,
48
46
  ];
49
47
 
50
- for (const candidate of paths) {
48
+ for (const path of paths) {
51
49
  try {
52
- return require(candidate).PrismaClient;
50
+ return require(path).PrismaClient;
53
51
  } catch (err) {
54
52
  // Continue to next path
55
53
  }