@getstrata/core 0.5.55 → 0.5.57

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 (118) hide show
  1. package/README.md +3 -1
  2. package/dist/{domain/abilities.d.ts → core/auth/abilityCatalog.d.ts} +9 -1
  3. package/dist/core/auth/accessControl.d.ts +1 -1
  4. package/dist/core/auth/membershipContext.d.ts +6 -4
  5. package/dist/core/auth/membershipService.d.ts +5 -6
  6. package/dist/core/contracts/authUserDirectory.d.ts +11 -0
  7. package/dist/core/contracts/membership.d.ts +20 -0
  8. package/dist/core/http/clientIp.d.ts +3 -0
  9. package/dist/core/jobs/dispatchWebhookJob.d.ts +2 -0
  10. package/dist/core/media/imageTransform.d.ts +13 -0
  11. package/dist/core/scheduler/osCron.d.ts +14 -0
  12. package/dist/core/tenant/tenancyConfig.d.ts +5 -0
  13. package/dist/core/tenant/tenantMiddleware.d.ts +1 -1
  14. package/dist/core/terminal/runShell.d.ts +6 -0
  15. package/dist/core/view/assertEtaHtmlSource.d.ts +5 -0
  16. package/dist/core/view/etaViewEngine.d.ts +4 -0
  17. package/dist/entries/audit/exportAuditLogs.js +2 -2
  18. package/dist/entries/audit/siemFormatter.js +2 -2
  19. package/dist/entries/auth/accessControl.js +4 -4
  20. package/dist/entries/auth/membershipMiddleware.js +21 -161
  21. package/dist/entries/auth/membershipScope.js +26 -166
  22. package/dist/entries/auth/membershipService.js +21 -161
  23. package/dist/entries/auth/oauth/providers.js +2 -2
  24. package/dist/entries/auth/password.js +2 -2
  25. package/dist/entries/auth/policy.js +2 -2
  26. package/dist/entries/auth/scimAuthMiddleware.js +22 -4
  27. package/dist/entries/auth/sessionCookie.js +4 -4
  28. package/dist/entries/auth/sessionGuard.js +12 -349
  29. package/dist/entries/auth/tokenHash.js +2 -2
  30. package/dist/entries/config/envSchema.js +2 -2
  31. package/dist/entries/contracts/container.js +2 -2
  32. package/dist/entries/contracts/di.js +2 -2
  33. package/dist/entries/contracts/serviceTokens.js +6 -6
  34. package/dist/entries/crypto/fieldEncryption.js +8 -8
  35. package/dist/entries/crypto/mfaSecret.js +2 -2
  36. package/dist/entries/database/errors.js +2 -2
  37. package/dist/entries/database/migrations.js +8 -8
  38. package/dist/entries/database/model.js +5 -5
  39. package/dist/entries/database/query.js +19 -19
  40. package/dist/entries/database/relationships.js +13 -13
  41. package/dist/entries/database/schema.js +13 -13
  42. package/dist/entries/database/seeders.js +2 -2
  43. package/dist/entries/facades.js +8 -8
  44. package/dist/entries/http/authMiddleware.js +2 -2
  45. package/dist/entries/http/bodySizeLimitMiddleware.js +2 -2
  46. package/dist/entries/http/clientIp.js +19 -0
  47. package/dist/entries/http/cookies.js +2 -2
  48. package/dist/entries/http/csrfMiddleware.js +2 -1
  49. package/dist/entries/http/csrfProtection.js +2 -2
  50. package/dist/entries/http/csrfToken.js +8 -7
  51. package/dist/entries/http/etag.js +8 -8
  52. package/dist/entries/http/flashSession.js +4 -4
  53. package/dist/entries/http/formRequest.js +2 -2
  54. package/dist/entries/http/loginThrottleMiddleware.js +20 -3
  55. package/dist/entries/http/memoryThrottleMiddleware.js +16 -1
  56. package/dist/entries/http/metricsMiddleware.js +2 -2
  57. package/dist/entries/http/pagination.js +4 -4
  58. package/dist/entries/http/parseFormBody.js +2 -2
  59. package/dist/entries/http/parseMultipartUpload.js +2 -2
  60. package/dist/entries/http/resources.js +2 -2
  61. package/dist/entries/http/response.js +214 -395
  62. package/dist/entries/http/scimThrottleMiddleware.js +40 -1
  63. package/dist/entries/http/securedRouteModelBinding.js +2 -2
  64. package/dist/entries/http/throttleMiddleware.js +20 -3
  65. package/dist/entries/http/validation.js +13 -13
  66. package/dist/entries/http/webErrorResponse.js +212 -393
  67. package/dist/entries/jobs/dispatchWebhookJob.js +111 -5
  68. package/dist/entries/lifecycle/gracefulShutdown.js +3 -3
  69. package/dist/entries/logging/logger.js +2 -2
  70. package/dist/entries/logging/requestLoggingMiddleware.js +16 -1
  71. package/dist/entries/mail/mailer.js +6 -6
  72. package/dist/entries/mail/markdownMail.js +3 -3
  73. package/dist/entries/mail/markdownMailable.js +2 -2
  74. package/dist/entries/media/imageTransform.js +40 -0
  75. package/dist/entries/metrics/prometheus.js +2 -2
  76. package/dist/entries/openapi/generator.js +2 -2
  77. package/dist/entries/queue/createAppQueue.js +4 -4
  78. package/dist/entries/queue/publicQueue.js +10 -10
  79. package/dist/entries/queue/queueMetrics.js +2 -2
  80. package/dist/entries/queue/redisQueue.js +7 -7
  81. package/dist/entries/queue.js +3 -3
  82. package/dist/entries/scheduler/osCron.js +27 -0
  83. package/dist/entries/scheduler/schedule.js +2 -2
  84. package/dist/entries/security/oauthState.js +3 -3
  85. package/dist/entries/security/publicReads.js +2 -2
  86. package/dist/entries/security/safeFetch.js +2 -2
  87. package/dist/entries/security/safeUrl.js +5 -5
  88. package/dist/entries/security/scimTenantTokens.js +3 -6
  89. package/dist/entries/security/totp.js +2 -2
  90. package/dist/entries/storage/storage.js +7 -7
  91. package/dist/entries/tenant/tenancyConfig.js +12 -0
  92. package/dist/entries/tenant/tenantDatabaseScope.js +13 -2
  93. package/dist/entries/terminal/runShell.js +18 -0
  94. package/dist/entries/validation/rules.js +12 -12
  95. package/dist/entries/view.js +212 -393
  96. package/dist/framework/public-api.d.ts +4 -1
  97. package/dist/index.js +2591 -2686
  98. package/package.json +27 -2
  99. package/dist/config/database.d.ts +0 -10
  100. package/dist/db/connection/createConnection.d.ts +0 -6
  101. package/dist/db/connection/index.d.ts +0 -11
  102. package/dist/domain/auth.d.ts +0 -4
  103. package/dist/domain/scim.d.ts +0 -9
  104. package/dist/modules/organization/memberRepository.d.ts +0 -14
  105. package/dist/modules/organization/memberTypes.d.ts +0 -9
  106. package/dist/modules/user/apiTokenRepository.d.ts +0 -8
  107. package/dist/modules/user/apiTokenTable.d.ts +0 -3
  108. package/dist/modules/user/authService.d.ts +0 -23
  109. package/dist/modules/user/notificationRepository.d.ts +0 -6
  110. package/dist/modules/user/notificationService.d.ts +0 -25
  111. package/dist/modules/user/notificationTable.d.ts +0 -3
  112. package/dist/modules/user/notificationTypes.d.ts +0 -12
  113. package/dist/modules/user/oauthIdentityRepository.d.ts +0 -9
  114. package/dist/modules/user/provider.d.ts +0 -11
  115. package/dist/modules/user/repository.d.ts +0 -13
  116. package/dist/modules/user/table.d.ts +0 -3
  117. package/dist/modules/user/tokenService.d.ts +0 -29
  118. package/dist/modules/user/types.d.ts +0 -46
@@ -30,6 +30,6 @@ function validateEnv(schema, env = process.env) {
30
30
  return resolved;
31
31
  }
32
32
  export {
33
- validateEnv,
34
- defineEnvSchema
33
+ defineEnvSchema,
34
+ validateEnv
35
35
  };
@@ -64,6 +64,6 @@ class ConfigStore {
64
64
  }
65
65
  }
66
66
  export {
67
- ServiceContainer,
68
- ConfigStore
67
+ ConfigStore,
68
+ ServiceContainer
69
69
  };
@@ -21,7 +21,7 @@ function resolveService(dependencies, token) {
21
21
  return dependencies.container.resolve(token);
22
22
  }
23
23
  export {
24
- resolveService,
24
+ assertAppDependenciesComplete,
25
25
  getRequiredDependency,
26
- assertAppDependenciesComplete
26
+ resolveService
27
27
  };
@@ -8,11 +8,11 @@ var CORE_POLICY_GATE_TOKEN = "core.policyGate";
8
8
  var CORE_AUTH_TOKEN = "core.auth";
9
9
  var CORE_TOKEN_SERVICE_TOKEN = "core.tokenService";
10
10
  export {
11
- CORE_TOKEN_SERVICE_TOKEN,
12
- CORE_QUEUE_TOKEN,
13
- CORE_POLICY_GATE_TOKEN,
14
- CORE_EVENT_BUS_TOKEN,
15
- CORE_CONFIG_TOKEN,
11
+ CORE_AUTH_TOKEN,
16
12
  CORE_CACHE_TOKEN,
17
- CORE_AUTH_TOKEN
13
+ CORE_CONFIG_TOKEN,
14
+ CORE_EVENT_BUS_TOKEN,
15
+ CORE_POLICY_GATE_TOKEN,
16
+ CORE_QUEUE_TOKEN,
17
+ CORE_TOKEN_SERVICE_TOKEN
18
18
  };
@@ -81,13 +81,13 @@ function emailLookupForQuery(email) {
81
81
  return hashLookupValue(normalized, key);
82
82
  }
83
83
  export {
84
- revealEmail,
85
- resolveEncryptionKey,
86
- protectEmail,
87
- normalizeEmail,
88
- isFieldEncryptionEnabled,
89
- hashLookupValue,
90
- encryptField,
84
+ decryptField,
91
85
  emailLookupForQuery,
92
- decryptField
86
+ encryptField,
87
+ hashLookupValue,
88
+ isFieldEncryptionEnabled,
89
+ normalizeEmail,
90
+ protectEmail,
91
+ resolveEncryptionKey,
92
+ revealEmail
93
93
  };
@@ -100,6 +100,6 @@ function revealMfaSecret(stored) {
100
100
  return decryptField(stored, key);
101
101
  }
102
102
  export {
103
- revealMfaSecret,
104
- protectMfaSecret
103
+ protectMfaSecret,
104
+ revealMfaSecret
105
105
  };
@@ -62,7 +62,7 @@ async function withDatabaseErrorHandling(operation) {
62
62
  }
63
63
  }
64
64
  export {
65
- withDatabaseErrorHandling,
65
+ isPostgresError,
66
66
  mapDatabaseError,
67
- isPostgresError
67
+ withDatabaseErrorHandling
68
68
  };
@@ -115,13 +115,13 @@ async function freshDatabase(db, migrations, options = {}) {
115
115
  await runFresh();
116
116
  }
117
117
  export {
118
- withMigrationLock,
119
- runPendingMigrations,
120
- rollbackDatabase,
121
- migrateDatabase,
122
- loadMigrationsFromDirectory,
123
- getMigrationStatus,
124
- getAppliedMigrations,
118
+ ensureMigrationsTable,
125
119
  freshDatabase,
126
- ensureMigrationsTable
120
+ getAppliedMigrations,
121
+ getMigrationStatus,
122
+ loadMigrationsFromDirectory,
123
+ migrateDatabase,
124
+ rollbackDatabase,
125
+ runPendingMigrations,
126
+ withMigrationLock
127
127
  };
@@ -876,10 +876,10 @@ function registerModelRepository(model, repository) {
876
876
  return model;
877
877
  }
878
878
  export {
879
- registerModelRepository,
880
- hydrateValue,
881
- filterMassAssignable,
882
- dehydrateValue,
879
+ Model,
883
880
  applyCasts,
884
- Model
881
+ dehydrateValue,
882
+ filterMassAssignable,
883
+ hydrateValue,
884
+ registerModelRepository
885
885
  };
@@ -413,24 +413,24 @@ function buildDeleteByIdQuery(table, id) {
413
413
  };
414
414
  }
415
415
  export {
416
- resolveSoftDeleteColumn,
417
- resolveQualifiedColumn,
418
- quoteIdentifier,
419
- qualifyColumn,
420
- parseQualifiedColumn,
421
- buildWhereClause,
422
- buildUpdateQuery,
423
- buildSoftDeleteByIdQuery,
424
- buildSelectQuery,
425
- buildRestoreByIdQuery,
426
- buildQueryWhereClause,
427
- buildProjectionQuery,
428
- buildOrderByClause,
429
- buildJoinClause,
430
- buildInsertQuery,
431
- buildGroupedCountQuery,
432
- buildDeleteByIdQuery,
433
- buildCountQuery,
416
+ assertSafeProjectionExpression,
434
417
  buildAdvancedWhereClause,
435
- assertSafeProjectionExpression
418
+ buildCountQuery,
419
+ buildDeleteByIdQuery,
420
+ buildGroupedCountQuery,
421
+ buildInsertQuery,
422
+ buildJoinClause,
423
+ buildOrderByClause,
424
+ buildProjectionQuery,
425
+ buildQueryWhereClause,
426
+ buildRestoreByIdQuery,
427
+ buildSelectQuery,
428
+ buildSoftDeleteByIdQuery,
429
+ buildUpdateQuery,
430
+ buildWhereClause,
431
+ parseQualifiedColumn,
432
+ qualifyColumn,
433
+ quoteIdentifier,
434
+ resolveQualifiedColumn,
435
+ resolveSoftDeleteColumn
436
436
  };
@@ -145,18 +145,18 @@ function indexMorphToRelation(children, parentsByType, relation) {
145
145
  return result;
146
146
  }
147
147
  export {
148
- morphTo,
149
- morphOne,
150
- morphMany,
151
- indexMorphToRelation,
152
- indexMorphOneRelation,
153
- indexMorphManyRelation,
154
- indexHasOneRelation,
155
- indexHasManyRelation,
156
- indexBelongsToRelation,
157
- indexBelongsToManyRelation,
158
- hasOne,
159
- hasMany,
148
+ belongsTo,
160
149
  belongsToMany,
161
- belongsTo
150
+ hasMany,
151
+ hasOne,
152
+ indexBelongsToManyRelation,
153
+ indexBelongsToRelation,
154
+ indexHasManyRelation,
155
+ indexHasOneRelation,
156
+ indexMorphManyRelation,
157
+ indexMorphOneRelation,
158
+ indexMorphToRelation,
159
+ morphMany,
160
+ morphOne,
161
+ morphTo
162
162
  };
@@ -1037,18 +1037,18 @@ function createSchemaBuilder(db, driver) {
1037
1037
  });
1038
1038
  }
1039
1039
  export {
1040
- resolveDatabaseDriver,
1041
- inferReferencedTable,
1042
- grammarForDriver,
1043
- createSchemaBuilder,
1044
- compileBlueprint,
1045
- UnsupportedSchemaFeatureError,
1046
- SqliteGrammar,
1047
- SchemaBuilder,
1048
- Schema,
1049
- PostgresGrammar,
1050
- MySqlGrammar,
1051
- ForeignIdColumnDefinition,
1040
+ Blueprint,
1052
1041
  ColumnDefinition,
1053
- Blueprint
1042
+ ForeignIdColumnDefinition,
1043
+ MySqlGrammar,
1044
+ PostgresGrammar,
1045
+ Schema,
1046
+ SchemaBuilder,
1047
+ SqliteGrammar,
1048
+ UnsupportedSchemaFeatureError,
1049
+ compileBlueprint,
1050
+ createSchemaBuilder,
1051
+ grammarForDriver,
1052
+ inferReferencedTable,
1053
+ resolveDatabaseDriver
1054
1054
  };
@@ -25,6 +25,6 @@ async function runSeedersFromDirectory(directory, db, options) {
25
25
  return seeders.length;
26
26
  }
27
27
  export {
28
- runSeedersFromDirectory,
29
- loadSeedersFromDirectory
28
+ loadSeedersFromDirectory,
29
+ runSeedersFromDirectory
30
30
  };
@@ -366,13 +366,13 @@ function storageFacade() {
366
366
  return storage();
367
367
  }
368
368
  export {
369
- storageFacade as storage,
370
- queue,
371
- policyGate,
372
- mail,
373
- log,
374
- events,
375
- config,
369
+ auth,
376
370
  cache,
377
- auth
371
+ config,
372
+ events,
373
+ log,
374
+ mail,
375
+ policyGate,
376
+ queue,
377
+ storageFacade as storage
378
378
  };
@@ -20,6 +20,6 @@ function createAuthMiddleware(auth) {
20
20
  };
21
21
  }
22
22
  export {
23
- createAuthMiddleware,
24
- authContext
23
+ authContext,
24
+ createAuthMiddleware
25
25
  };
@@ -27,6 +27,6 @@ function createBodySizeLimitMiddleware(maxBytes = resolveMaxBodyBytes()) {
27
27
  };
28
28
  }
29
29
  export {
30
- resolveMaxBodyBytes,
31
- createBodySizeLimitMiddleware
30
+ createBodySizeLimitMiddleware,
31
+ resolveMaxBodyBytes
32
32
  };
@@ -0,0 +1,19 @@
1
+ // @bun
2
+ // ../../src/core/http/clientIp.ts
3
+ function trustForwardedFor(env = process.env) {
4
+ return (env.TRUST_FORWARDED_FOR ?? "false") === "true";
5
+ }
6
+ function readClientIp(request, env = process.env) {
7
+ if (!trustForwardedFor(env)) {
8
+ return;
9
+ }
10
+ const forwarded = request.headers.get("x-forwarded-for")?.split(",")[0]?.trim();
11
+ if (forwarded) {
12
+ return forwarded;
13
+ }
14
+ return request.headers.get("x-real-ip")?.trim() || undefined;
15
+ }
16
+ export {
17
+ readClientIp,
18
+ trustForwardedFor
19
+ };
@@ -27,6 +27,6 @@ function readBunRequestCookie(request, name) {
27
27
  return request.cookies.get(name) ?? readRequestCookie(request, name);
28
28
  }
29
29
  export {
30
- readRequestCookie,
31
- readBunRequestCookie
30
+ readBunRequestCookie,
31
+ readRequestCookie
32
32
  };
@@ -78,9 +78,10 @@ function tokensMatch(left, right) {
78
78
  }
79
79
  function createCsrfTokenCookie() {
80
80
  const token = Bun.CSRF.generate(resolveCsrfSecret(), { expiresIn: CSRF_TTL_MS });
81
+ const secure = process.env.APP_ENV === "production" ? "; Secure" : "";
81
82
  return {
82
83
  token,
83
- cookie: `${CSRF_COOKIE}=${encodeURIComponent(token)}; Path=/; SameSite=Lax; Max-Age=${Math.floor(CSRF_TTL_MS / 1000)}`
84
+ cookie: `${CSRF_COOKIE}=${encodeURIComponent(token)}; Path=/; SameSite=Lax; Max-Age=${Math.floor(CSRF_TTL_MS / 1000)}${secure}`
84
85
  };
85
86
  }
86
87
  function resolveCsrfToken(request) {
@@ -18,6 +18,6 @@ function createCsrfProtection(secret, options = {}) {
18
18
  };
19
19
  }
20
20
  export {
21
- createCsrfProtection,
22
- DEFAULT_CSRF_TTL_MS
21
+ DEFAULT_CSRF_TTL_MS,
22
+ createCsrfProtection
23
23
  };
@@ -75,9 +75,10 @@ function tokensMatch(left, right) {
75
75
  }
76
76
  function createCsrfTokenCookie() {
77
77
  const token = Bun.CSRF.generate(resolveCsrfSecret(), { expiresIn: CSRF_TTL_MS });
78
+ const secure = process.env.APP_ENV === "production" ? "; Secure" : "";
78
79
  return {
79
80
  token,
80
- cookie: `${CSRF_COOKIE}=${encodeURIComponent(token)}; Path=/; SameSite=Lax; Max-Age=${Math.floor(CSRF_TTL_MS / 1000)}`
81
+ cookie: `${CSRF_COOKIE}=${encodeURIComponent(token)}; Path=/; SameSite=Lax; Max-Age=${Math.floor(CSRF_TTL_MS / 1000)}${secure}`
81
82
  };
82
83
  }
83
84
  function resolveCsrfToken(request) {
@@ -134,11 +135,11 @@ function resolveCsrfTokenForRequest(request) {
134
135
  return resolveCsrfToken(request).token;
135
136
  }
136
137
  export {
137
- verifyCsrfToken,
138
- resolveCsrfTokenForRequest,
139
- resolveCsrfToken,
140
- readSubmittedCsrfTokenFromBody,
141
- readSubmittedCsrfToken,
138
+ CSRF_COOKIE,
142
139
  createCsrfTokenCookie,
143
- CSRF_COOKIE
140
+ readSubmittedCsrfToken,
141
+ readSubmittedCsrfTokenFromBody,
142
+ resolveCsrfToken,
143
+ resolveCsrfTokenForRequest,
144
+ verifyCsrfToken
144
145
  };
@@ -97,13 +97,13 @@ function applyConditionalGet(request, response, etag) {
97
97
  });
98
98
  }
99
99
  export {
100
- notModifiedResponse,
101
- isEtagEnabled,
102
- ifNoneMatchSatisfied,
103
- ifMatchSatisfied,
104
- etagValuesMatch,
105
- etagFromResource,
106
- computeEtagFromJson,
100
+ applyConditionalGet,
107
101
  assertIfMatch,
108
- applyConditionalGet
102
+ computeEtagFromJson,
103
+ etagFromResource,
104
+ etagValuesMatch,
105
+ ifMatchSatisfied,
106
+ ifNoneMatchSatisfied,
107
+ isEtagEnabled,
108
+ notModifiedResponse
109
109
  };
@@ -98,9 +98,9 @@ function withFlashClear(response) {
98
98
  });
99
99
  }
100
100
  export {
101
- withFlashClear,
102
- pullFlash,
103
- flashResponse,
101
+ clearFlashCookie,
104
102
  createFlashCookie,
105
- clearFlashCookie
103
+ flashResponse,
104
+ pullFlash,
105
+ withFlashClear
106
106
  };
@@ -150,6 +150,6 @@ class QueryFormRequest {
150
150
  }
151
151
  }
152
152
  export {
153
- QueryFormRequest,
154
- FormRequest
153
+ FormRequest,
154
+ QueryFormRequest
155
155
  };
@@ -1,8 +1,25 @@
1
1
  // @bun
2
2
  // ../../src/core/http/loginThrottleMiddleware.ts
3
3
  var {RedisClient } = globalThis.Bun;
4
+
5
+ // ../../src/core/http/clientIp.ts
6
+ function trustForwardedFor(env = process.env) {
7
+ return (env.TRUST_FORWARDED_FOR ?? "false") === "true";
8
+ }
9
+ function readClientIp(request, env = process.env) {
10
+ if (!trustForwardedFor(env)) {
11
+ return;
12
+ }
13
+ const forwarded = request.headers.get("x-forwarded-for")?.split(",")[0]?.trim();
14
+ if (forwarded) {
15
+ return forwarded;
16
+ }
17
+ return request.headers.get("x-real-ip")?.trim() || undefined;
18
+ }
19
+
20
+ // ../../src/core/http/loginThrottleMiddleware.ts
4
21
  function resolveLoginIdentity(request) {
5
- return request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? "unknown";
22
+ return readClientIp(request) ?? "unknown";
6
23
  }
7
24
  async function resolveLoginEmail(request) {
8
25
  const contentType = request.headers.get("content-type")?.toLowerCase() ?? "";
@@ -41,6 +58,6 @@ function createLoginThrottleMiddleware(options) {
41
58
  };
42
59
  }
43
60
  export {
44
- resolveLoginIdentity,
45
- createLoginThrottleMiddleware
61
+ createLoginThrottleMiddleware,
62
+ resolveLoginIdentity
46
63
  };
@@ -1,11 +1,26 @@
1
1
  // @bun
2
+ // ../../src/core/http/clientIp.ts
3
+ function trustForwardedFor(env = process.env) {
4
+ return (env.TRUST_FORWARDED_FOR ?? "false") === "true";
5
+ }
6
+ function readClientIp(request, env = process.env) {
7
+ if (!trustForwardedFor(env)) {
8
+ return;
9
+ }
10
+ const forwarded = request.headers.get("x-forwarded-for")?.split(",")[0]?.trim();
11
+ if (forwarded) {
12
+ return forwarded;
13
+ }
14
+ return request.headers.get("x-real-ip")?.trim() || undefined;
15
+ }
16
+
2
17
  // ../../src/core/http/memoryThrottleMiddleware.ts
3
18
  var buckets = new Map;
4
19
  function createMemoryThrottleMiddleware(options) {
5
20
  const prefix = options.keyPrefix ?? "workhub:memory-throttle:";
6
21
  return async (request, next) => {
7
22
  const path = new URL(request.url).pathname;
8
- const identity = request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? request.headers.get("authorization")?.slice(0, 32) ?? "unknown";
23
+ const identity = readClientIp(request) ?? request.headers.get("authorization")?.slice(0, 32) ?? "unknown";
9
24
  const key = `${prefix}${identity}:${path}`;
10
25
  const now = Date.now();
11
26
  const existing = buckets.get(key);
@@ -86,6 +86,6 @@ function createMetricsMiddleware() {
86
86
  };
87
87
  }
88
88
  export {
89
- normalizeMetricPath,
90
- createMetricsMiddleware
89
+ createMetricsMiddleware,
90
+ normalizeMetricPath
91
91
  };
@@ -174,9 +174,9 @@ function paginatedResponse(data, meta, init = {}) {
174
174
  return Response.json({ data, meta }, init);
175
175
  }
176
176
  export {
177
- parsePaginationQuery,
178
- paginatedResponse,
179
- buildPaginationMeta,
177
+ DEFAULT_PER_PAGE,
180
178
  MAX_PER_PAGE,
181
- DEFAULT_PER_PAGE
179
+ buildPaginationMeta,
180
+ paginatedResponse,
181
+ parsePaginationQuery
182
182
  };
@@ -18,6 +18,6 @@ function formDataToRecord(formData) {
18
18
  return values;
19
19
  }
20
20
  export {
21
- parseFormBody,
22
- formDataToRecord
21
+ formDataToRecord,
22
+ parseFormBody
23
23
  };
@@ -76,6 +76,6 @@ async function parseMultipartUpload(request, fieldName = "file") {
76
76
  };
77
77
  }
78
78
  export {
79
- sanitizeUploadFileName,
80
- parseMultipartUpload
79
+ parseMultipartUpload,
80
+ sanitizeUploadFileName
81
81
  };
@@ -13,7 +13,7 @@ function toPaginatedResourceCollection(items, meta, transformer) {
13
13
  };
14
14
  }
15
15
  export {
16
- toResourceCollection,
16
+ serializeDate,
17
17
  toPaginatedResourceCollection,
18
- serializeDate
18
+ toResourceCollection
19
19
  };