@eminuckan/spine 0.3.1 → 0.3.3

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 (86) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/SECURITY.md +5 -15
  3. package/dist/access/index.mjs +2 -0
  4. package/dist/{access-CGrsDMwu.js → access-BHy1v5sr.mjs} +6 -8
  5. package/dist/access-BHy1v5sr.mjs.map +1 -0
  6. package/dist/api-client/index.mjs +3 -0
  7. package/dist/api-client/server.mjs +4 -0
  8. package/dist/{api-client-CgZUMukO.js → api-client-CB7XZaMg.mjs} +8 -10
  9. package/dist/api-client-CB7XZaMg.mjs.map +1 -0
  10. package/dist/auth/auth.server.d.ts +1 -0
  11. package/dist/auth/auth.server.d.ts.map +1 -1
  12. package/dist/auth/index.mjs +1 -0
  13. package/dist/auth/route-protection.server.d.ts.map +1 -1
  14. package/dist/auth/server.mjs +3 -0
  15. package/dist/{identity-C5un-xAs.js → identity/index.mjs} +24 -21
  16. package/dist/identity/index.mjs.map +1 -0
  17. package/dist/{server-Dxsww9v9.js → identity/server.mjs} +7 -8
  18. package/dist/identity/server.mjs.map +1 -0
  19. package/dist/{index.js → index.mjs} +11 -13
  20. package/dist/{logging-DviiAkLx.js → logging/index.mjs} +22 -24
  21. package/dist/logging/index.mjs.map +1 -0
  22. package/dist/{permission-service-CvGpwI0d.js → permission-service-DUyKomU3.mjs} +6 -10
  23. package/dist/permission-service-DUyKomU3.mjs.map +1 -0
  24. package/dist/permissions/index.mjs +3 -0
  25. package/dist/{permissions-_n1hIG7Q.js → permissions-C5dTP9y4.mjs} +23 -15
  26. package/dist/permissions-C5dTP9y4.mjs.map +1 -0
  27. package/dist/query-client/index.mjs +2 -0
  28. package/dist/{query-client-Bh3TyB8W.js → query-client-_xB300gc.mjs} +49 -15
  29. package/dist/query-client-_xB300gc.mjs.map +1 -0
  30. package/dist/react-router/{index.js → index.mjs} +11 -13
  31. package/dist/react-router/server.mjs +17 -0
  32. package/dist/{redis-session-storage.server-v2VcpFsQ.js → redis-session-storage.server-DGgQcJ9B.mjs} +30 -42
  33. package/dist/redis-session-storage.server-DGgQcJ9B.mjs.map +1 -0
  34. package/dist/{server-C96NMFBy.js → server-ByScGRXA.mjs} +39 -36
  35. package/dist/server-ByScGRXA.mjs.map +1 -0
  36. package/dist/{auth.server-D5oiz9aF.js → server-CqX2yCa4.mjs} +388 -119
  37. package/dist/server-CqX2yCa4.mjs.map +1 -0
  38. package/dist/server.mjs +90 -0
  39. package/dist/server.mjs.map +1 -0
  40. package/dist/signalr/index.mjs +2 -0
  41. package/dist/{signalr-k-70VHKo.js → signalr-C-TA8nEE.mjs} +11 -6
  42. package/dist/signalr-C-TA8nEE.mjs.map +1 -0
  43. package/dist/{tenant-DfLemb6n.js → tenant/index.mjs} +19 -12
  44. package/dist/tenant/index.mjs.map +1 -0
  45. package/dist/{server-Ca-3DJf2.js → tenant/server.mjs} +12 -12
  46. package/dist/tenant/server.mjs.map +1 -0
  47. package/dist/{types-BaaE6wjY.js → types-DqCXinAk.mjs} +3 -3
  48. package/dist/types-DqCXinAk.mjs.map +1 -0
  49. package/docs/codex-for-oss-application.md +4 -0
  50. package/package.json +33 -21
  51. package/dist/access/index.js +0 -4
  52. package/dist/access-CGrsDMwu.js.map +0 -1
  53. package/dist/api-client/index.js +0 -5
  54. package/dist/api-client/server.js +0 -6
  55. package/dist/api-client-CgZUMukO.js.map +0 -1
  56. package/dist/auth/index.js +0 -0
  57. package/dist/auth/server.js +0 -6
  58. package/dist/auth.server-D5oiz9aF.js.map +0 -1
  59. package/dist/auth.server-lC94lmlx.js +0 -5
  60. package/dist/identity/index.js +0 -3
  61. package/dist/identity/server.js +0 -5
  62. package/dist/identity-C5un-xAs.js.map +0 -1
  63. package/dist/logging/index.js +0 -3
  64. package/dist/logging-DviiAkLx.js.map +0 -1
  65. package/dist/permission-service-CvGpwI0d.js.map +0 -1
  66. package/dist/permissions/index.js +0 -4
  67. package/dist/permissions-_n1hIG7Q.js.map +0 -1
  68. package/dist/query-client/index.js +0 -3
  69. package/dist/query-client-Bh3TyB8W.js.map +0 -1
  70. package/dist/react-router/server.js +0 -20
  71. package/dist/redis-session-storage.server-v2VcpFsQ.js.map +0 -1
  72. package/dist/server-B6PCxc-T.js +0 -304
  73. package/dist/server-B6PCxc-T.js.map +0 -1
  74. package/dist/server-C96NMFBy.js.map +0 -1
  75. package/dist/server-Ca-3DJf2.js.map +0 -1
  76. package/dist/server-Dxsww9v9.js.map +0 -1
  77. package/dist/server-hGrElJMG.js +0 -78
  78. package/dist/server-hGrElJMG.js.map +0 -1
  79. package/dist/server.js +0 -20
  80. package/dist/signalr/index.js +0 -3
  81. package/dist/signalr-k-70VHKo.js.map +0 -1
  82. package/dist/src-B9rDUgSb.js +0 -0
  83. package/dist/tenant/index.js +0 -3
  84. package/dist/tenant/server.js +0 -5
  85. package/dist/tenant-DfLemb6n.js.map +0 -1
  86. package/dist/types-BaaE6wjY.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/logging/types.ts","../../src/logging/config.ts","../../src/logging/logger.ts"],"sourcesContent":["/**\n * Logging Types\n */\n\nexport enum LogLevel {\n DEBUG = 'debug',\n INFO = 'info',\n WARN = 'warn',\n ERROR = 'error',\n}\n\nexport interface LogContext {\n [key: string]: unknown;\n}\n\nexport interface LogEntry {\n timestamp: string;\n level: LogLevel;\n message: string;\n context?: LogContext;\n error?: Error;\n}\n\nexport interface LoggerConfig {\n minLevel: LogLevel;\n enableConsole: boolean;\n enableRemote: boolean;\n remoteEndpoint?: string;\n serviceName?: string;\n}\n","/**\n * Logger Configuration\n */\n\nimport { LogLevel, type LoggerConfig } from './types';\n\nexport const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {\n [LogLevel.DEBUG]: 0,\n [LogLevel.INFO]: 1,\n [LogLevel.WARN]: 2,\n [LogLevel.ERROR]: 3,\n};\n\nexport const defaultLoggerConfig: LoggerConfig = {\n minLevel: process.env.NODE_ENV === 'production' ? LogLevel.INFO : LogLevel.DEBUG,\n enableConsole: true,\n enableRemote: false,\n serviceName: 'spine',\n};\n","/**\n * Logger Service\n * \n * Centralized logging implementation with structured logging format.\n */\n\nimport { LogLevel, type LogContext, type LogEntry, type LoggerConfig } from './types';\nimport { defaultLoggerConfig, LOG_LEVEL_PRIORITY } from './config';\n\nexport class Logger {\n private config: LoggerConfig;\n\n constructor(config?: Partial<LoggerConfig>) {\n this.config = {\n ...defaultLoggerConfig,\n ...config,\n };\n }\n\n debug(message: string, context?: LogContext): void {\n this.log(LogLevel.DEBUG, message, context);\n }\n\n info(message: string, context?: LogContext): void {\n this.log(LogLevel.INFO, message, context);\n }\n\n warn(message: string, context?: LogContext): void {\n this.log(LogLevel.WARN, message, context);\n }\n\n error(message: string, error?: Error, context?: LogContext): void {\n this.log(LogLevel.ERROR, message, context, error);\n }\n\n private log(\n level: LogLevel,\n message: string,\n context?: LogContext,\n error?: Error\n ): void {\n if (!this.shouldLog(level)) {\n return;\n }\n\n const entry: LogEntry = {\n timestamp: new Date().toISOString(),\n level,\n message,\n context,\n error,\n };\n\n if (this.config.enableConsole) {\n this.logToConsole(entry);\n }\n\n if (this.config.enableRemote && this.config.remoteEndpoint) {\n this.sendToRemote(entry).catch((err) => {\n console.error('Failed to send log to remote endpoint:', err);\n });\n }\n }\n\n private shouldLog(level: LogLevel): boolean {\n return LOG_LEVEL_PRIORITY[level] >= LOG_LEVEL_PRIORITY[this.config.minLevel];\n }\n\n private logToConsole(entry: LogEntry): void {\n const formatted = this.formatEntry(entry);\n\n switch (entry.level) {\n case LogLevel.DEBUG:\n console.debug(formatted);\n break;\n case LogLevel.INFO:\n console.info(formatted);\n break;\n case LogLevel.WARN:\n console.warn(formatted);\n break;\n case LogLevel.ERROR:\n console.error(formatted);\n if (entry.error) {\n console.error(entry.error);\n }\n break;\n }\n }\n\n private formatEntry(entry: LogEntry): string {\n const parts = [\n `[${entry.timestamp}]`,\n `[${entry.level.toUpperCase()}]`,\n entry.message,\n ];\n\n if (entry.context && Object.keys(entry.context).length > 0) {\n parts.push(JSON.stringify(entry.context));\n }\n\n return parts.join(' ');\n }\n\n private async sendToRemote(entry: LogEntry): Promise<void> {\n if (!this.config.remoteEndpoint) return;\n\n await fetch(this.config.remoteEndpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n ...entry,\n serviceName: this.config.serviceName,\n error: entry.error\n ? {\n name: entry.error.name,\n message: entry.error.message,\n stack: entry.error.stack,\n }\n : undefined,\n }),\n });\n }\n}\n\n// Default logger instance\nexport const logger = new Logger();\n\n// Create logger with custom config\nexport function createLogger(config?: Partial<LoggerConfig>): Logger {\n return new Logger(config);\n}\n"],"mappings":";;;;AAIA,IAAY,WAAL,yBAAA,UAAA;CACL,SAAA,WAAA;CACA,SAAA,UAAA;CACA,SAAA,UAAA;CACA,SAAA,WAAA;;AACF,EAAA,CAAA,CAAA;;;ACHA,MAAa,qBAA+C;YACxC;WACD;WACA;YACC;AACpB;AAEA,MAAa,sBAAoC;CAC/C,UAAU,QAAQ,IAAI,aAAa,eAAA,SAAA;CACnC,eAAe;CACf,cAAc;CACd,aAAa;AACf;;;ACTA,IAAa,SAAb,MAAoB;CAClB;CAEA,YAAY,QAAgC;EAC1C,KAAK,SAAS;GACZ,GAAG;GACH,GAAG;EACL;CACF;CAEA,MAAM,SAAiB,SAA4B;EACjD,KAAK,IAAA,SAAoB,SAAS,OAAO;CAC3C;CAEA,KAAK,SAAiB,SAA4B;EAChD,KAAK,IAAA,QAAmB,SAAS,OAAO;CAC1C;CAEA,KAAK,SAAiB,SAA4B;EAChD,KAAK,IAAA,QAAmB,SAAS,OAAO;CAC1C;CAEA,MAAM,SAAiB,OAAe,SAA4B;EAChE,KAAK,IAAA,SAAoB,SAAS,SAAS,KAAK;CAClD;CAEA,IACE,OACA,SACA,SACA,OACM;EACN,IAAI,CAAC,KAAK,UAAU,KAAK,GACvB;EAGF,MAAM,QAAkB;GACtB,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;GAClC;GACA;GACA;GACA;EACF;EAEA,IAAI,KAAK,OAAO,eACd,KAAK,aAAa,KAAK;EAGzB,IAAI,KAAK,OAAO,gBAAgB,KAAK,OAAO,gBAC1C,KAAK,aAAa,KAAK,CAAC,CAAC,OAAO,QAAQ;GACtC,QAAQ,MAAM,0CAA0C,GAAG;EAC7D,CAAC;CAEL;CAEA,UAAkB,OAA0B;EAC1C,OAAO,mBAAmB,UAAU,mBAAmB,KAAK,OAAO;CACrE;CAEA,aAAqB,OAAuB;EAC1C,MAAM,YAAY,KAAK,YAAY,KAAK;EAExC,QAAQ,MAAM,OAAd;GACE,KAAA;IACE,QAAQ,MAAM,SAAS;IACvB;GACF,KAAA;IACE,QAAQ,KAAK,SAAS;IACtB;GACF,KAAA;IACE,QAAQ,KAAK,SAAS;IACtB;GACF,KAAA;IACE,QAAQ,MAAM,SAAS;IACvB,IAAI,MAAM,OACR,QAAQ,MAAM,MAAM,KAAK;IAE3B;EACJ;CACF;CAEA,YAAoB,OAAyB;EAC3C,MAAM,QAAQ;GACZ,IAAI,MAAM,UAAU;GACpB,IAAI,MAAM,MAAM,YAAY,EAAE;GAC9B,MAAM;EACR;EAEA,IAAI,MAAM,WAAW,OAAO,KAAK,MAAM,OAAO,CAAC,CAAC,SAAS,GACvD,MAAM,KAAK,KAAK,UAAU,MAAM,OAAO,CAAC;EAG1C,OAAO,MAAM,KAAK,GAAG;CACvB;CAEA,MAAc,aAAa,OAAgC;EACzD,IAAI,CAAC,KAAK,OAAO,gBAAgB;EAEjC,MAAM,MAAM,KAAK,OAAO,gBAAgB;GACtC,QAAQ;GACR,SAAS,EAAE,gBAAgB,mBAAmB;GAC9C,MAAM,KAAK,UAAU;IACnB,GAAG;IACH,aAAa,KAAK,OAAO;IACzB,OAAO,MAAM,QACT;KACE,MAAM,MAAM,MAAM;KAClB,SAAS,MAAM,MAAM;KACrB,OAAO,MAAM,MAAM;IACrB,IACA,KAAA;GACN,CAAC;EACH,CAAC;CACH;AACF;AAGA,MAAa,SAAS,IAAI,OAAO;AAGjC,SAAgB,aAAa,QAAwC;CACnE,OAAO,IAAI,OAAO,MAAM;AAC1B"}
@@ -24,14 +24,10 @@ var PermissionChecker = class {
24
24
  const { operator = "OR", wildcard = false } = options;
25
25
  const matchedPermissions = [];
26
26
  const missingPermissions = [];
27
- for (const permission of permissions) {
28
- const hasIt = wildcard ? this.hasWildcardPermission(permission) : this.hasPermission(permission);
29
- if (hasIt) matchedPermissions.push(permission);
30
- else missingPermissions.push(permission);
31
- }
32
- const hasPermission = operator === "AND" ? missingPermissions.length === 0 : matchedPermissions.length > 0;
27
+ for (const permission of permissions) if (wildcard ? this.hasWildcardPermission(permission) : this.hasPermission(permission)) matchedPermissions.push(permission);
28
+ else missingPermissions.push(permission);
33
29
  return {
34
- hasPermission,
30
+ hasPermission: operator === "AND" ? missingPermissions.length === 0 : matchedPermissions.length > 0,
35
31
  matchedPermissions,
36
32
  missingPermissions
37
33
  };
@@ -89,7 +85,7 @@ var PermissionChecker = class {
89
85
  return this.permissionArray.length;
90
86
  }
91
87
  };
92
-
93
88
  //#endregion
94
- export { PermissionChecker };
95
- //# sourceMappingURL=permission-service-CvGpwI0d.js.map
89
+ export { PermissionChecker as t };
90
+
91
+ //# sourceMappingURL=permission-service-DUyKomU3.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permission-service-DUyKomU3.mjs","names":[],"sources":["../src/permissions/permission-service.ts"],"sourcesContent":["/**\n * Permission Service\n * \n * Core permission checking logic.\n */\n\nimport type {\n PermissionCode,\n PermissionModule,\n PermissionCheckOptions,\n PermissionCheckResult,\n FieldPermissionResult,\n} from './types';\n\n/**\n * Permission Checker Class\n * \n * Provides methods for checking user permissions.\n */\nexport class PermissionChecker {\n private permissions: Set<PermissionCode>;\n private permissionArray: PermissionCode[];\n\n constructor(permissions: PermissionCode[]) {\n this.permissionArray = permissions;\n this.permissions = new Set(permissions);\n }\n\n /**\n * Check if user has a single permission\n */\n hasPermission(permission: PermissionCode): boolean {\n return this.permissions.has(permission);\n }\n\n /**\n * Check multiple permissions with AND/OR logic\n */\n hasPermissions(\n permissions: PermissionCode[],\n options: PermissionCheckOptions = {}\n ): PermissionCheckResult {\n const { operator = 'OR', wildcard = false } = options;\n\n const matchedPermissions: PermissionCode[] = [];\n const missingPermissions: PermissionCode[] = [];\n\n for (const permission of permissions) {\n const hasIt = wildcard\n ? this.hasWildcardPermission(permission)\n : this.hasPermission(permission);\n\n if (hasIt) {\n matchedPermissions.push(permission);\n } else {\n missingPermissions.push(permission);\n }\n }\n\n const hasPermission =\n operator === 'AND'\n ? missingPermissions.length === 0\n : matchedPermissions.length > 0;\n\n return {\n hasPermission,\n matchedPermissions,\n missingPermissions,\n };\n }\n\n /**\n * Check wildcard permission pattern\n */\n private hasWildcardPermission(pattern: PermissionCode): boolean {\n if (!pattern.includes('*')) {\n return this.hasPermission(pattern);\n }\n\n const regex = new RegExp(\n '^' + pattern.replace(/\\./g, '\\\\.').replace(/\\*/g, '.*') + '$'\n );\n\n return this.permissionArray.some((p) => regex.test(p));\n }\n\n /**\n * Check if user has any permission in a module\n */\n hasModulePermission(module: PermissionModule): boolean {\n const prefix = `${module}.`;\n return this.permissionArray.some((p) => p.startsWith(prefix));\n }\n\n /**\n * Get field-level permissions for an entity\n */\n getFieldPermissions(\n module: PermissionModule,\n entity: string\n ): FieldPermissionResult {\n const base = `${module}.${entity}`;\n\n return {\n canView: this.hasPermission(`${base}.View`),\n canEdit: this.hasPermission(`${base}.Edit`),\n canCreate: this.hasPermission(`${base}.Create`),\n canDelete: this.hasPermission(`${base}.Delete`),\n };\n }\n\n /**\n * Get all permissions\n */\n getAllPermissions(): readonly PermissionCode[] {\n return Object.freeze([...this.permissionArray]);\n }\n\n /**\n * Get permissions for a specific module\n */\n getModulePermissions(module: PermissionModule): PermissionCode[] {\n const prefix = `${module}.`;\n return this.permissionArray.filter((p) => p.startsWith(prefix));\n }\n\n /**\n * Check if user has any permissions\n */\n hasAnyPermissions(): boolean {\n return this.permissionArray.length > 0;\n }\n\n /**\n * Get permission count\n */\n getPermissionCount(): number {\n return this.permissionArray.length;\n }\n}\n"],"mappings":";;;;;;AAmBA,IAAa,oBAAb,MAA+B;CAC7B;CACA;CAEA,YAAY,aAA+B;EACzC,KAAK,kBAAkB;EACvB,KAAK,cAAc,IAAI,IAAI,WAAW;CACxC;;;;CAKA,cAAc,YAAqC;EACjD,OAAO,KAAK,YAAY,IAAI,UAAU;CACxC;;;;CAKA,eACE,aACA,UAAkC,CAAC,GACZ;EACvB,MAAM,EAAE,WAAW,MAAM,WAAW,UAAU;EAE9C,MAAM,qBAAuC,CAAC;EAC9C,MAAM,qBAAuC,CAAC;EAE9C,KAAK,MAAM,cAAc,aAKvB,IAJc,WACV,KAAK,sBAAsB,UAAU,IACrC,KAAK,cAAc,UAAU,GAG/B,mBAAmB,KAAK,UAAU;OAElC,mBAAmB,KAAK,UAAU;EAStC,OAAO;GACL,eALA,aAAa,QACT,mBAAmB,WAAW,IAC9B,mBAAmB,SAAS;GAIhC;GACA;EACF;CACF;;;;CAKA,sBAA8B,SAAkC;EAC9D,IAAI,CAAC,QAAQ,SAAS,GAAG,GACvB,OAAO,KAAK,cAAc,OAAO;EAGnC,MAAM,QAAQ,IAAI,OAChB,MAAM,QAAQ,QAAQ,OAAO,KAAK,CAAC,CAAC,QAAQ,OAAO,IAAI,IAAI,GAC7D;EAEA,OAAO,KAAK,gBAAgB,MAAM,MAAM,MAAM,KAAK,CAAC,CAAC;CACvD;;;;CAKA,oBAAoB,QAAmC;EACrD,MAAM,SAAS,GAAG,OAAO;EACzB,OAAO,KAAK,gBAAgB,MAAM,MAAM,EAAE,WAAW,MAAM,CAAC;CAC9D;;;;CAKA,oBACE,QACA,QACuB;EACvB,MAAM,OAAO,GAAG,OAAO,GAAG;EAE1B,OAAO;GACL,SAAS,KAAK,cAAc,GAAG,KAAK,MAAM;GAC1C,SAAS,KAAK,cAAc,GAAG,KAAK,MAAM;GAC1C,WAAW,KAAK,cAAc,GAAG,KAAK,QAAQ;GAC9C,WAAW,KAAK,cAAc,GAAG,KAAK,QAAQ;EAChD;CACF;;;;CAKA,oBAA+C;EAC7C,OAAO,OAAO,OAAO,CAAC,GAAG,KAAK,eAAe,CAAC;CAChD;;;;CAKA,qBAAqB,QAA4C;EAC/D,MAAM,SAAS,GAAG,OAAO;EACzB,OAAO,KAAK,gBAAgB,QAAQ,MAAM,EAAE,WAAW,MAAM,CAAC;CAChE;;;;CAKA,oBAA6B;EAC3B,OAAO,KAAK,gBAAgB,SAAS;CACvC;;;;CAKA,qBAA6B;EAC3B,OAAO,KAAK,gBAAgB;CAC9B;AACF"}
@@ -0,0 +1,3 @@
1
+ import { t as PermissionChecker } from "../permission-service-DUyKomU3.mjs";
2
+ import { _ as initializePermissions, a as ProtectedSection, c as useHasPermission, d as usePermission, f as usePermissionChecker, g as getPermissions, h as getPermissionChecker, i as ProtectedLink, l as useHasPermissions, m as PermissionInitializer, n as ProtectedAction, o as useAllPermissions, p as usePermissions, r as ProtectedButton, s as useHasModulePermission, t as PERMISSION_MODULES, u as useModulePermission, v as usePermissionStore } from "../permissions-C5dTP9y4.mjs";
3
+ export { PERMISSION_MODULES, PermissionChecker, PermissionInitializer, ProtectedAction, ProtectedButton, ProtectedLink, ProtectedSection, getPermissionChecker, getPermissions, initializePermissions, useAllPermissions, useHasModulePermission, useHasPermission, useHasPermissions, useModulePermission, usePermission, usePermissionChecker, usePermissionStore, usePermissions };
@@ -1,10 +1,14 @@
1
- import { PermissionChecker } from "./permission-service-CvGpwI0d.js";
1
+ import { t as PermissionChecker } from "./permission-service-DUyKomU3.mjs";
2
2
  import { create } from "zustand";
3
3
  import { useCallback, useEffect, useMemo } from "react";
4
4
  import { Fragment, jsx } from "react/jsx-runtime";
5
-
6
5
  //#region src/permissions/permission-store.ts
7
6
  /**
7
+ * Permission Store (Zustand)
8
+ *
9
+ * State management for permissions.
10
+ */
11
+ /**
8
12
  * Selectors for focused store reads
9
13
  */
10
14
  const selectChecker = (state) => state.checker;
@@ -53,10 +57,14 @@ function getPermissionChecker() {
53
57
  function getPermissions() {
54
58
  return usePermissionStore.getState().permissions;
55
59
  }
56
-
57
60
  //#endregion
58
61
  //#region src/permissions/permission-initializer.tsx
59
62
  /**
63
+ * Permission Initializer Component
64
+ *
65
+ * Initializes permission store from identity context.
66
+ */
67
+ /**
60
68
  * Component that initializes permissions from props
61
69
  */
62
70
  function PermissionInitializer({ permissions, isLoading = false, children }) {
@@ -65,10 +73,14 @@ function PermissionInitializer({ permissions, isLoading = false, children }) {
65
73
  }, [permissions, isLoading]);
66
74
  return /* @__PURE__ */ jsx(Fragment, { children });
67
75
  }
68
-
69
76
  //#endregion
70
77
  //#region src/permissions/hooks.ts
71
78
  /**
79
+ * Permission Hooks
80
+ *
81
+ * React hooks for permission checks.
82
+ */
83
+ /**
72
84
  * Hook for checking a single permission
73
85
  */
74
86
  function usePermission(permission) {
@@ -119,15 +131,13 @@ function useAllPermissions() {
119
131
  const checker = usePermissionStore(selectChecker);
120
132
  return useMemo(() => checker.getAllPermissions(), [checker]);
121
133
  }
122
-
123
134
  //#endregion
124
135
  //#region src/permissions/components.tsx
125
136
  /**
126
137
  * Button that only renders if user has the required permission
127
138
  */
128
- function ProtectedButton({ permission, fallback = null, children,...props }) {
129
- const hasPermission = usePermission(permission);
130
- if (!hasPermission) return /* @__PURE__ */ jsx(Fragment, { children: fallback });
139
+ function ProtectedButton({ permission, fallback = null, children, ...props }) {
140
+ if (!usePermission(permission)) return /* @__PURE__ */ jsx(Fragment, { children: fallback });
131
141
  return /* @__PURE__ */ jsx("button", {
132
142
  ...props,
133
143
  children
@@ -136,9 +146,8 @@ function ProtectedButton({ permission, fallback = null, children,...props }) {
136
146
  /**
137
147
  * Link that only renders if user has the required permission
138
148
  */
139
- function ProtectedLink({ permission, fallback = null, children,...props }) {
140
- const hasPermission = usePermission(permission);
141
- if (!hasPermission) return /* @__PURE__ */ jsx(Fragment, { children: fallback });
149
+ function ProtectedLink({ permission, fallback = null, children, ...props }) {
150
+ if (!usePermission(permission)) return /* @__PURE__ */ jsx(Fragment, { children: fallback });
142
151
  return /* @__PURE__ */ jsx("a", {
143
152
  ...props,
144
153
  children
@@ -167,7 +176,6 @@ function ProtectedAction({ permission, onAction, children }) {
167
176
  disabled: !hasPermission
168
177
  }) });
169
178
  }
170
-
171
179
  //#endregion
172
180
  //#region src/permissions/constants.ts
173
181
  /**
@@ -177,7 +185,7 @@ function ProtectedAction({ permission, onAction, children }) {
177
185
  * module constants in the consuming app instead.
178
186
  */
179
187
  const PERMISSION_MODULES = [];
180
-
181
188
  //#endregion
182
- export { PERMISSION_MODULES, PermissionInitializer, ProtectedAction, ProtectedButton, ProtectedLink, ProtectedSection, getPermissionChecker, getPermissions, initializePermissions, useAllPermissions, useHasModulePermission, useHasPermission, useHasPermissions, useModulePermission, usePermission, usePermissionChecker, usePermissionStore, usePermissions };
183
- //# sourceMappingURL=permissions-_n1hIG7Q.js.map
189
+ export { initializePermissions as _, ProtectedSection as a, useHasPermission as c, usePermission as d, usePermissionChecker as f, getPermissions as g, getPermissionChecker as h, ProtectedLink as i, useHasPermissions as l, PermissionInitializer as m, ProtectedAction as n, useAllPermissions as o, usePermissions as p, ProtectedButton as r, useHasModulePermission as s, PERMISSION_MODULES as t, useModulePermission as u, usePermissionStore as v };
190
+
191
+ //# sourceMappingURL=permissions-C5dTP9y4.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions-C5dTP9y4.mjs","names":[],"sources":["../src/permissions/permission-store.ts","../src/permissions/permission-initializer.tsx","../src/permissions/hooks.ts","../src/permissions/components.tsx","../src/permissions/constants.ts"],"sourcesContent":["/**\n * Permission Store (Zustand)\n * \n * State management for permissions.\n */\n\nimport { create } from 'zustand';\nimport { PermissionChecker } from './permission-service';\nimport type { PermissionCode } from './types';\n\n/**\n * Permission store state interface\n */\ninterface PermissionState {\n checker: PermissionChecker;\n permissions: PermissionCode[];\n isLoading: boolean;\n setPermissions: (permissions: PermissionCode[]) => void;\n setLoading: (isLoading: boolean) => void;\n reset: () => void;\n}\n\n/**\n * Selectors for focused store reads\n */\nexport const selectChecker = (state: PermissionState) => state.checker;\nexport const selectPermissions = (state: PermissionState) => state.permissions;\nexport const selectIsLoading = (state: PermissionState) => state.isLoading;\n\n/**\n * Initial state\n */\nconst initialState = {\n checker: new PermissionChecker([]),\n permissions: [] as PermissionCode[],\n isLoading: false,\n};\n\n/**\n * Permission store\n */\nexport const usePermissionStore = create<PermissionState>((set) => ({\n ...initialState,\n\n setPermissions: (permissions: PermissionCode[]) => {\n set({\n permissions,\n checker: new PermissionChecker(permissions),\n });\n },\n\n setLoading: (isLoading: boolean) => {\n set({ isLoading });\n },\n\n reset: () => {\n set(initialState);\n },\n}));\n\n/**\n * Initialize permission store\n */\nexport function initializePermissions(\n permissions: PermissionCode[],\n isLoading: boolean = false\n): void {\n usePermissionStore.getState().setPermissions(permissions);\n usePermissionStore.getState().setLoading(isLoading);\n}\n\n/**\n * Get permission checker outside React components\n */\nexport function getPermissionChecker(): PermissionChecker {\n return usePermissionStore.getState().checker;\n}\n\n/**\n * Get all permissions outside React components\n */\nexport function getPermissions(): PermissionCode[] {\n return usePermissionStore.getState().permissions;\n}\n","/**\n * Permission Initializer Component\n * \n * Initializes permission store from identity context.\n */\n\nimport { useEffect, type ReactNode } from 'react';\nimport { initializePermissions } from './permission-store';\nimport type { PermissionCode } from './types';\n\ninterface PermissionInitializerProps {\n permissions: PermissionCode[];\n isLoading?: boolean;\n children: ReactNode;\n}\n\n/**\n * Component that initializes permissions from props\n */\nexport function PermissionInitializer({\n permissions,\n isLoading = false,\n children,\n}: PermissionInitializerProps) {\n useEffect(() => {\n initializePermissions(permissions, isLoading);\n }, [permissions, isLoading]);\n\n return <>{children}</>;\n}\n","/**\n * Permission Hooks\n * \n * React hooks for permission checks.\n */\n\nimport { useMemo, useCallback } from 'react';\nimport { usePermissionStore, selectChecker } from './permission-store';\nimport type { PermissionCode, PermissionCheckOptions, PermissionModule } from './types';\n\n/**\n * Hook for checking a single permission\n */\nexport function usePermission(permission: PermissionCode): boolean {\n const checker = usePermissionStore(selectChecker);\n return useMemo(() => checker.hasPermission(permission), [checker, permission]);\n}\n\n/**\n * Alias for usePermission\n */\nexport const useHasPermission = usePermission;\n\n/**\n * Hook for checking multiple permissions\n */\nexport function usePermissions(\n permissions: PermissionCode[],\n options?: PermissionCheckOptions\n) {\n const checker = usePermissionStore(selectChecker);\n return useMemo(\n () => checker.hasPermissions(permissions, options),\n [checker, permissions, options]\n );\n}\n\n/**\n * Alias for usePermissions\n */\nexport const useHasPermissions = usePermissions;\n\n/**\n * Hook for checking module-level permissions\n */\nexport function useModulePermission(module: PermissionModule): boolean {\n const checker = usePermissionStore(selectChecker);\n return useMemo(() => checker.hasModulePermission(module), [checker, module]);\n}\n\n/**\n * Alias for useModulePermission\n */\nexport const useHasModulePermission = useModulePermission;\n\n/**\n * Hook for getting a memoized permission checker function\n */\nexport function usePermissionChecker() {\n const checker = usePermissionStore(selectChecker);\n return useCallback(\n (permission: PermissionCode) => checker.hasPermission(permission),\n [checker]\n );\n}\n\n/**\n * Hook for getting all user permissions\n */\nexport function useAllPermissions(): readonly PermissionCode[] {\n const checker = usePermissionStore(selectChecker);\n return useMemo(() => checker.getAllPermissions(), [checker]);\n}\n\n/**\n * Hook for field-level permissions\n */\nexport function useFieldPermissions(module: PermissionModule, entity: string) {\n const checker = usePermissionStore(selectChecker);\n return useMemo(\n () => checker.getFieldPermissions(module, entity),\n [checker, module, entity]\n );\n}\n\n/**\n * Hook for permission loading state\n */\nexport function usePermissionLoading(): boolean {\n return usePermissionStore((state) => state.isLoading);\n}\n","/**\n * Permission Components\n * \n * Protected UI components that conditionally render based on permissions.\n */\n\nimport React, { type ReactNode, type ComponentProps } from 'react';\nimport { usePermission, usePermissions } from './hooks';\nimport type { PermissionCode, PermissionCheckOptions } from './types';\n\n// ============================================================================\n// ProtectedButton\n// ============================================================================\n\ninterface ProtectedButtonProps extends ComponentProps<'button'> {\n permission: PermissionCode;\n fallback?: ReactNode;\n}\n\n/**\n * Button that only renders if user has the required permission\n */\nexport function ProtectedButton({\n permission,\n fallback = null,\n children,\n ...props\n}: ProtectedButtonProps) {\n const hasPermission = usePermission(permission);\n\n if (!hasPermission) {\n return <>{fallback}</>;\n }\n\n return <button {...props}>{children}</button>;\n}\n\n// ============================================================================\n// ProtectedLink\n// ============================================================================\n\ninterface ProtectedLinkProps extends ComponentProps<'a'> {\n permission: PermissionCode;\n fallback?: ReactNode;\n}\n\n/**\n * Link that only renders if user has the required permission\n */\nexport function ProtectedLink({\n permission,\n fallback = null,\n children,\n ...props\n}: ProtectedLinkProps) {\n const hasPermission = usePermission(permission);\n\n if (!hasPermission) {\n return <>{fallback}</>;\n }\n\n return <a {...props}>{children}</a>;\n}\n\n// ============================================================================\n// ProtectedSection\n// ============================================================================\n\ninterface ProtectedSectionProps {\n permission?: PermissionCode;\n permissions?: PermissionCode[];\n options?: PermissionCheckOptions;\n fallback?: ReactNode;\n children: ReactNode;\n}\n\n/**\n * Section that only renders if user has the required permission(s)\n */\nexport function ProtectedSection({\n permission,\n permissions,\n options,\n fallback = null,\n children,\n}: ProtectedSectionProps) {\n // Single permission check\n const singlePermissionResult = usePermission(permission || '');\n \n // Multiple permissions check\n const multiplePermissionsResult = usePermissions(permissions || [], options);\n\n // Determine if we should render\n let hasPermission = false;\n \n if (permission) {\n hasPermission = singlePermissionResult;\n } else if (permissions && permissions.length > 0) {\n hasPermission = multiplePermissionsResult.hasPermission;\n } else {\n // No permission specified, render by default\n hasPermission = true;\n }\n\n if (!hasPermission) {\n return <>{fallback}</>;\n }\n\n return <>{children}</>;\n}\n\n// ============================================================================\n// ProtectedAction\n// ============================================================================\n\ninterface ProtectedActionProps {\n permission: PermissionCode;\n onAction: () => void;\n children: (props: { onClick: () => void; disabled: boolean }) => ReactNode;\n}\n\n/**\n * Render prop component for protected actions\n */\nexport function ProtectedAction({\n permission,\n onAction,\n children,\n}: ProtectedActionProps) {\n const hasPermission = usePermission(permission);\n\n return (\n <>\n {children({\n onClick: hasPermission ? onAction : () => {},\n disabled: !hasPermission,\n })}\n </>\n );\n}\n","/**\n * Permission Constants\n */\n\nimport type { PermissionModule } from './types';\n\n/**\n * Available permission modules\n *\n * @deprecated Spine does not own an application's permission taxonomy. Define\n * module constants in the consuming app instead.\n */\nexport const PERMISSION_MODULES: PermissionModule[] = [];\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { i as invalidationHelpers, n as createQueryClient, r as createQueryKeyFactory, t as cachePresets } from "../query-client-_xB300gc.mjs";
2
+ export { cachePresets, createQueryClient, createQueryKeyFactory, invalidationHelpers };
@@ -1,12 +1,19 @@
1
1
  import { MutationCache, QueryCache, QueryClient } from "@tanstack/react-query";
2
-
3
2
  //#region src/query-client/query-config.ts
4
3
  /**
4
+ * Query Client Configuration
5
+ *
6
+ * Optimized caching strategy for different types of data:
7
+ * - Static data (rarely changes): Long staleTime and gcTime
8
+ * - Dynamic data (changes frequently): Short staleTime
9
+ * - Critical data (needs to be fresh): Very short staleTime with prefetching
10
+ */
11
+ /**
5
12
  * Default configuration
6
13
  */
7
14
  const DEFAULT_CONFIG = {
8
- staleTime: 5 * 60 * 1e3,
9
- gcTime: 10 * 60 * 1e3,
15
+ staleTime: 300 * 1e3,
16
+ gcTime: 600 * 1e3,
10
17
  maxRetries: 3,
11
18
  maxMutationRetries: 1,
12
19
  refetchOnWindowFocus: true,
@@ -54,7 +61,7 @@ function createQueryClient(config = {}) {
54
61
  ...config
55
62
  };
56
63
  const handleLogout = onLogout || createDefaultLogoutHandler();
57
- const queryClient = new QueryClient({
64
+ return new QueryClient({
58
65
  defaultOptions: {
59
66
  queries: {
60
67
  staleTime,
@@ -97,7 +104,6 @@ function createQueryClient(config = {}) {
97
104
  logger?.error?.("Mutation error", error instanceof Error ? error : void 0, { is401: is401Error(error) });
98
105
  } })
99
106
  });
100
- return queryClient;
101
107
  }
102
108
  /**
103
109
  * Cache Presets for different data types
@@ -105,24 +111,40 @@ function createQueryClient(config = {}) {
105
111
  * Use these presets for consistent caching across the application.
106
112
  */
107
113
  const cachePresets = {
114
+ /**
115
+ * Static data - rarely changes
116
+ * Good for: permissions, roles, system settings
117
+ */
108
118
  static: {
109
- staleTime: 30 * 60 * 1e3,
110
- gcTime: 60 * 60 * 1e3,
119
+ staleTime: 1800 * 1e3,
120
+ gcTime: 3600 * 1e3,
111
121
  refetchOnWindowFocus: false
112
122
  },
123
+ /**
124
+ * Normal data - changes occasionally
125
+ * Good for: resources, users, tenant data
126
+ */
113
127
  normal: {
114
- staleTime: 5 * 60 * 1e3,
115
- gcTime: 10 * 60 * 1e3,
128
+ staleTime: 300 * 1e3,
129
+ gcTime: 600 * 1e3,
116
130
  refetchOnWindowFocus: true
117
131
  },
132
+ /**
133
+ * Dynamic data - changes frequently
134
+ * Good for: transactions, activities, notifications
135
+ */
118
136
  dynamic: {
119
- staleTime: 1 * 60 * 1e3,
120
- gcTime: 5 * 60 * 1e3,
137
+ staleTime: 60 * 1e3,
138
+ gcTime: 300 * 1e3,
121
139
  refetchOnWindowFocus: true
122
140
  },
141
+ /**
142
+ * Realtime data - always fresh
143
+ * Good for: live status, counters, dashboards
144
+ */
123
145
  realtime: {
124
146
  staleTime: 0,
125
- gcTime: 1 * 60 * 1e3,
147
+ gcTime: 60 * 1e3,
126
148
  refetchOnWindowFocus: true
127
149
  }
128
150
  };
@@ -150,12 +172,21 @@ function createQueryKeyFactory(module) {
150
172
  * Invalidation helpers for common patterns
151
173
  */
152
174
  const invalidationHelpers = {
175
+ /**
176
+ * Invalidate all queries for a module
177
+ */
153
178
  invalidateModule: async (queryClient, module) => {
154
179
  await queryClient.invalidateQueries({ queryKey: [module] });
155
180
  },
181
+ /**
182
+ * Invalidate all list queries for a module
183
+ */
156
184
  invalidateLists: async (queryClient, module) => {
157
185
  await queryClient.invalidateQueries({ queryKey: [module, "list"] });
158
186
  },
187
+ /**
188
+ * Invalidate a specific detail query
189
+ */
159
190
  invalidateDetail: async (queryClient, module, id) => {
160
191
  await queryClient.invalidateQueries({ queryKey: [
161
192
  module,
@@ -163,12 +194,15 @@ const invalidationHelpers = {
163
194
  id
164
195
  ] });
165
196
  },
197
+ /**
198
+ * Invalidate and refetch (useful for critical data)
199
+ */
166
200
  invalidateAndRefetch: async (queryClient, queryKey) => {
167
201
  await queryClient.invalidateQueries({ queryKey });
168
202
  await queryClient.refetchQueries({ queryKey });
169
203
  }
170
204
  };
171
-
172
205
  //#endregion
173
- export { cachePresets, createQueryClient, createQueryKeyFactory, invalidationHelpers };
174
- //# sourceMappingURL=query-client-Bh3TyB8W.js.map
206
+ export { invalidationHelpers as i, createQueryClient as n, createQueryKeyFactory as r, cachePresets as t };
207
+
208
+ //# sourceMappingURL=query-client-_xB300gc.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-client-_xB300gc.mjs","names":[],"sources":["../src/query-client/query-config.ts"],"sourcesContent":["/**\n * Query Client Configuration\n * \n * Optimized caching strategy for different types of data:\n * - Static data (rarely changes): Long staleTime and gcTime\n * - Dynamic data (changes frequently): Short staleTime\n * - Critical data (needs to be fresh): Very short staleTime with prefetching\n */\n\nimport { QueryClient, QueryCache, MutationCache } from '@tanstack/react-query';\nimport type { QueryClientConfig, CachePresets } from './types';\n\n/**\n * Default configuration\n */\nconst DEFAULT_CONFIG: Required<Omit<QueryClientConfig, 'logger' | 'onLogout'>> = {\n staleTime: 5 * 60 * 1000, // 5 minutes\n gcTime: 10 * 60 * 1000, // 10 minutes\n maxRetries: 3,\n maxMutationRetries: 1,\n refetchOnWindowFocus: true,\n refetchOnReconnect: false,\n refetchOnMount: false,\n};\n\n/**\n * Check if error is a 401 Unauthorized error\n */\nfunction is401Error(error: unknown): boolean {\n if (error instanceof Response) {\n return error.status === 401;\n }\n\n if (error && typeof error === 'object' && 'status' in error) {\n return (error as any).status === 401;\n }\n\n return false;\n}\n\n/**\n * Check if error requires logout (refresh token expired)\n */\nfunction shouldLogout(error: unknown): boolean {\n if (error && typeof error === 'object') {\n // Check for shouldLogout flag from server\n if ('shouldLogout' in error && (error as any).shouldLogout === true) {\n return true;\n }\n\n // Check for SESSION_EXPIRED code\n if ('code' in error && (error as any).code === 'SESSION_EXPIRED') {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Create default logout handler\n */\nfunction createDefaultLogoutHandler(): (returnUrl?: string) => void {\n return (returnUrl?: string) => {\n if (typeof window !== 'undefined') {\n const currentUrl = returnUrl || window.location.pathname + window.location.search;\n window.location.href = `/auth/logout?logout=local&returnUrl=${encodeURIComponent(currentUrl)}`;\n }\n };\n}\n\n/**\n * Create optimized QueryClient instance\n * \n * @param config - Configuration options\n * @returns Configured QueryClient with optimized defaults\n */\nexport function createQueryClient(config: QueryClientConfig = {}): QueryClient {\n const {\n staleTime,\n gcTime,\n maxRetries,\n maxMutationRetries,\n refetchOnWindowFocus,\n refetchOnReconnect,\n refetchOnMount,\n logger,\n onLogout,\n } = { ...DEFAULT_CONFIG, ...config };\n\n const handleLogout = onLogout || createDefaultLogoutHandler();\n\n const queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime,\n gcTime,\n retry: (failureCount, error) => {\n // Don't retry 401 errors - the fetch client handles refresh flows separately\n if (is401Error(error)) {\n logger?.debug?.('Query failed with 401, not retrying');\n return false;\n }\n return failureCount < maxRetries;\n },\n retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),\n refetchOnWindowFocus,\n refetchOnReconnect,\n refetchOnMount,\n },\n mutations: {\n retry: (failureCount, error) => {\n if (is401Error(error)) {\n logger?.debug?.('Mutation failed with 401, not retrying');\n return false;\n }\n return failureCount < maxMutationRetries;\n },\n retryDelay: 1000,\n },\n },\n queryCache: new QueryCache({\n onError: (error) => {\n if (shouldLogout(error)) {\n handleLogout();\n return;\n }\n logger?.error?.('Query error', error instanceof Error ? error : undefined, {\n is401: is401Error(error),\n });\n },\n }),\n mutationCache: new MutationCache({\n onError: (error) => {\n if (shouldLogout(error)) {\n handleLogout();\n return;\n }\n logger?.error?.('Mutation error', error instanceof Error ? error : undefined, {\n is401: is401Error(error),\n });\n },\n }),\n });\n\n return queryClient;\n}\n\n/**\n * Cache Presets for different data types\n * \n * Use these presets for consistent caching across the application.\n */\nexport const cachePresets: CachePresets = {\n /**\n * Static data - rarely changes\n * Good for: permissions, roles, system settings\n */\n static: {\n staleTime: 30 * 60 * 1000, // 30 minutes\n gcTime: 60 * 60 * 1000, // 1 hour\n refetchOnWindowFocus: false,\n },\n\n /**\n * Normal data - changes occasionally\n * Good for: resources, users, tenant data\n */\n normal: {\n staleTime: 5 * 60 * 1000, // 5 minutes\n gcTime: 10 * 60 * 1000, // 10 minutes\n refetchOnWindowFocus: true,\n },\n\n /**\n * Dynamic data - changes frequently\n * Good for: transactions, activities, notifications\n */\n dynamic: {\n staleTime: 1 * 60 * 1000, // 1 minute\n gcTime: 5 * 60 * 1000, // 5 minutes\n refetchOnWindowFocus: true,\n },\n\n /**\n * Realtime data - always fresh\n * Good for: live status, counters, dashboards\n */\n realtime: {\n staleTime: 0, // Always stale\n gcTime: 1 * 60 * 1000, // 1 minute\n refetchOnWindowFocus: true,\n },\n};\n\n/**\n * Create base query keys for a module\n */\nexport function createQueryKeyFactory<T extends string>(\n module: T\n): {\n all: readonly [T];\n lists: () => readonly [T, 'list'];\n list: (filters?: Record<string, unknown>) => readonly [T, 'list', Record<string, unknown>?];\n details: () => readonly [T, 'detail'];\n detail: (id: string) => readonly [T, 'detail', string];\n} {\n return {\n all: [module] as const,\n lists: () => [module, 'list'] as const,\n list: (filters?: Record<string, unknown>) => [module, 'list', filters] as const,\n details: () => [module, 'detail'] as const,\n detail: (id: string) => [module, 'detail', id] as const,\n };\n}\n\n/**\n * Invalidation helpers for common patterns\n */\nexport const invalidationHelpers = {\n /**\n * Invalidate all queries for a module\n */\n invalidateModule: async (queryClient: QueryClient, module: string): Promise<void> => {\n await queryClient.invalidateQueries({ queryKey: [module] });\n },\n\n /**\n * Invalidate all list queries for a module\n */\n invalidateLists: async (queryClient: QueryClient, module: string): Promise<void> => {\n await queryClient.invalidateQueries({ queryKey: [module, 'list'] });\n },\n\n /**\n * Invalidate a specific detail query\n */\n invalidateDetail: async (\n queryClient: QueryClient,\n module: string,\n id: string\n ): Promise<void> => {\n await queryClient.invalidateQueries({ queryKey: [module, 'detail', id] });\n },\n\n /**\n * Invalidate and refetch (useful for critical data)\n */\n invalidateAndRefetch: async (queryClient: QueryClient, queryKey: readonly unknown[]): Promise<void> => {\n await queryClient.invalidateQueries({ queryKey });\n await queryClient.refetchQueries({ queryKey });\n },\n};\n"],"mappings":";;;;;;;;;;;;;AAeA,MAAM,iBAA2E;CAC/E,WAAW,MAAS;CACpB,QAAQ,MAAU;CAClB,YAAY;CACZ,oBAAoB;CACpB,sBAAsB;CACtB,oBAAoB;CACpB,gBAAgB;AAClB;;;;AAKA,SAAS,WAAW,OAAyB;CAC3C,IAAI,iBAAiB,UACnB,OAAO,MAAM,WAAW;CAG1B,IAAI,SAAS,OAAO,UAAU,YAAY,YAAY,OACpD,OAAQ,MAAc,WAAW;CAGnC,OAAO;AACT;;;;AAKA,SAAS,aAAa,OAAyB;CAC7C,IAAI,SAAS,OAAO,UAAU,UAAU;EAEtC,IAAI,kBAAkB,SAAU,MAAc,iBAAiB,MAC7D,OAAO;EAIT,IAAI,UAAU,SAAU,MAAc,SAAS,mBAC7C,OAAO;CAEX;CAEA,OAAO;AACT;;;;AAKA,SAAS,6BAA2D;CAClE,QAAQ,cAAuB;EAC7B,IAAI,OAAO,WAAW,aAAa;GACjC,MAAM,aAAa,aAAa,OAAO,SAAS,WAAW,OAAO,SAAS;GAC3E,OAAO,SAAS,OAAO,uCAAuC,mBAAmB,UAAU;EAC7F;CACF;AACF;;;;;;;AAQA,SAAgB,kBAAkB,SAA4B,CAAC,GAAgB;CAC7E,MAAM,EACJ,WACA,QACA,YACA,oBACA,sBACA,oBACA,gBACA,QACA,aACE;EAAE,GAAG;EAAgB,GAAG;CAAO;CAEnC,MAAM,eAAe,YAAY,2BAA2B;CAuD5D,OAAO,IArDiB,YAAY;EAClC,gBAAgB;GACd,SAAS;IACP;IACA;IACA,QAAQ,cAAc,UAAU;KAE9B,IAAI,WAAW,KAAK,GAAG;MACrB,QAAQ,QAAQ,qCAAqC;MACrD,OAAO;KACT;KACA,OAAO,eAAe;IACxB;IACA,aAAa,iBAAiB,KAAK,IAAI,MAAO,KAAK,cAAc,GAAK;IACtE;IACA;IACA;GACF;GACA,WAAW;IACT,QAAQ,cAAc,UAAU;KAC9B,IAAI,WAAW,KAAK,GAAG;MACrB,QAAQ,QAAQ,wCAAwC;MACxD,OAAO;KACT;KACA,OAAO,eAAe;IACxB;IACA,YAAY;GACd;EACF;EACA,YAAY,IAAI,WAAW,EACzB,UAAU,UAAU;GAClB,IAAI,aAAa,KAAK,GAAG;IACvB,aAAa;IACb;GACF;GACA,QAAQ,QAAQ,eAAe,iBAAiB,QAAQ,QAAQ,KAAA,GAAW,EACzE,OAAO,WAAW,KAAK,EACzB,CAAC;EACH,EACF,CAAC;EACD,eAAe,IAAI,cAAc,EAC/B,UAAU,UAAU;GAClB,IAAI,aAAa,KAAK,GAAG;IACvB,aAAa;IACb;GACF;GACA,QAAQ,QAAQ,kBAAkB,iBAAiB,QAAQ,QAAQ,KAAA,GAAW,EAC5E,OAAO,WAAW,KAAK,EACzB,CAAC;EACH,EACF,CAAC;CACH,CAEiB;AACnB;;;;;;AAOA,MAAa,eAA6B;;;;;CAKxC,QAAQ;EACN,WAAW,OAAU;EACrB,QAAQ,OAAU;EAClB,sBAAsB;CACxB;;;;;CAMA,QAAQ;EACN,WAAW,MAAS;EACpB,QAAQ,MAAU;EAClB,sBAAsB;CACxB;;;;;CAMA,SAAS;EACP,WAAW,KAAS;EACpB,QAAQ,MAAS;EACjB,sBAAsB;CACxB;;;;;CAMA,UAAU;EACR,WAAW;EACX,QAAQ,KAAS;EACjB,sBAAsB;CACxB;AACF;;;;AAKA,SAAgB,sBACd,QAOA;CACA,OAAO;EACL,KAAK,CAAC,MAAM;EACZ,aAAa,CAAC,QAAQ,MAAM;EAC5B,OAAO,YAAsC;GAAC;GAAQ;GAAQ;EAAO;EACrE,eAAe,CAAC,QAAQ,QAAQ;EAChC,SAAS,OAAe;GAAC;GAAQ;GAAU;EAAE;CAC/C;AACF;;;;AAKA,MAAa,sBAAsB;;;;CAIjC,kBAAkB,OAAO,aAA0B,WAAkC;EACnF,MAAM,YAAY,kBAAkB,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC;CAC5D;;;;CAKA,iBAAiB,OAAO,aAA0B,WAAkC;EAClF,MAAM,YAAY,kBAAkB,EAAE,UAAU,CAAC,QAAQ,MAAM,EAAE,CAAC;CACpE;;;;CAKA,kBAAkB,OAChB,aACA,QACA,OACkB;EAClB,MAAM,YAAY,kBAAkB,EAAE,UAAU;GAAC;GAAQ;GAAU;EAAE,EAAE,CAAC;CAC1E;;;;CAKA,sBAAsB,OAAO,aAA0B,aAAgD;EACrG,MAAM,YAAY,kBAAkB,EAAE,SAAS,CAAC;EAChD,MAAM,YAAY,eAAe,EAAE,SAAS,CAAC;CAC/C;AACF"}
@@ -1,13 +1,11 @@
1
- import { LOG_LEVEL_PRIORITY, LogLevel, Logger, createLogger, defaultLoggerConfig, logger } from "../logging-DviiAkLx.js";
2
- import { PermissionChecker } from "../permission-service-CvGpwI0d.js";
3
- import { PERMISSION_MODULES, PermissionInitializer, ProtectedAction, ProtectedButton, ProtectedLink, ProtectedSection, getPermissionChecker, getPermissions, initializePermissions, useAllPermissions, useHasModulePermission, useHasPermission, useHasPermissions, useModulePermission, usePermission, usePermissionChecker, usePermissionStore, usePermissions } from "../permissions-_n1hIG7Q.js";
4
- import { evaluateAccessRequirement } from "../access-CGrsDMwu.js";
5
- import { TenantProvider, configureTenantClient, configureTenantEndpoints, getTenantCookieName, initializeTenantStore, normalizeTenantDataPayload, normalizeTenantSwitchPayload, resetTenantClientConfig, useCurrentOrganization, useCurrentTenant, useCurrentTenantData, useOrganization, useTenant, useTenantData, useTenantStore, useTenantSwitcher } from "../tenant-DfLemb6n.js";
6
- import { IdentityContextProvider, configureIdentityEndpoints, configureIdentityStore, initialIdentityContext, normalizeIdentityContextPayload, normalizeIdentityPermissionsPayload, resetIdentityStoreConfig, useHasEntitlement, useHasSubscription, useIdentityContext, useIdentityStore, useIsOnboarded, useUserPermissions, useUserTenants } from "../identity-C5un-xAs.js";
7
- import { isApiClientError } from "../types-BaaE6wjY.js";
8
- import { ApiError, ErrorCodes, ErrorHandler, calculateBackoffDelay, createRetryFetch, fetchWithTimeout, handleApiError, isRetryableError, withRetry } from "../api-client-CgZUMukO.js";
9
- import { IdentitySignalRClient, SignalRClient, cleanupSignalR, createIdentitySignalRClient, getIdentitySignalRClient, initializeSignalR } from "../signalr-k-70VHKo.js";
10
- import { cachePresets, createQueryClient, createQueryKeyFactory, invalidationHelpers } from "../query-client-Bh3TyB8W.js";
11
- import "../src-B9rDUgSb.js";
12
-
13
- export { ApiError, ErrorCodes, ErrorHandler, IdentityContextProvider, IdentitySignalRClient, LOG_LEVEL_PRIORITY, LogLevel, Logger, PERMISSION_MODULES, PermissionChecker, PermissionInitializer, ProtectedAction, ProtectedButton, ProtectedLink, ProtectedSection, SignalRClient, TenantProvider, cachePresets, calculateBackoffDelay, cleanupSignalR, configureIdentityEndpoints, configureIdentityStore, configureTenantClient, configureTenantEndpoints, createIdentitySignalRClient, createLogger, createQueryClient, createQueryKeyFactory, createRetryFetch, defaultLoggerConfig, evaluateAccessRequirement, fetchWithTimeout, getIdentitySignalRClient, getPermissionChecker, getPermissions, getTenantCookieName, handleApiError, initialIdentityContext, initializePermissions, initializeSignalR, initializeTenantStore, invalidationHelpers, isApiClientError, isRetryableError, logger, normalizeIdentityContextPayload, normalizeIdentityPermissionsPayload, normalizeTenantDataPayload, normalizeTenantSwitchPayload, resetIdentityStoreConfig, resetTenantClientConfig, useAllPermissions, useCurrentOrganization, useCurrentTenant, useCurrentTenantData, useHasEntitlement, useHasModulePermission, useHasPermission, useHasPermissions, useHasSubscription, useIdentityContext, useIdentityStore, useIsOnboarded, useModulePermission, useOrganization, usePermission, usePermissionChecker, usePermissionStore, usePermissions, useTenant, useTenantData, useTenantStore, useTenantSwitcher, useUserPermissions, useUserTenants, withRetry };
1
+ import { LOG_LEVEL_PRIORITY, LogLevel, Logger, createLogger, defaultLoggerConfig, logger } from "../logging/index.mjs";
2
+ import { t as PermissionChecker } from "../permission-service-DUyKomU3.mjs";
3
+ import { _ as initializePermissions, a as ProtectedSection, c as useHasPermission, d as usePermission, f as usePermissionChecker, g as getPermissions, h as getPermissionChecker, i as ProtectedLink, l as useHasPermissions, m as PermissionInitializer, n as ProtectedAction, o as useAllPermissions, p as usePermissions, r as ProtectedButton, s as useHasModulePermission, t as PERMISSION_MODULES, u as useModulePermission, v as usePermissionStore } from "../permissions-C5dTP9y4.mjs";
4
+ import { t as evaluateAccessRequirement } from "../access-BHy1v5sr.mjs";
5
+ import { TenantProvider, configureTenantClient, configureTenantEndpoints, getTenantCookieName, initializeTenantStore, normalizeTenantDataPayload, normalizeTenantSwitchPayload, resetTenantClientConfig, useCurrentOrganization, useCurrentTenant, useCurrentTenantData, useOrganization, useTenant, useTenantData, useTenantStore, useTenantSwitcher } from "../tenant/index.mjs";
6
+ import { IdentityContextProvider, configureIdentityEndpoints, configureIdentityStore, initialIdentityContext, normalizeIdentityContextPayload, normalizeIdentityPermissionsPayload, resetIdentityStoreConfig, useHasEntitlement, useHasSubscription, useIdentityContext, useIdentityStore, useIsOnboarded, useUserPermissions, useUserTenants } from "../identity/index.mjs";
7
+ import { t as isApiClientError } from "../types-DqCXinAk.mjs";
8
+ import { a as withRetry, c as handleApiError, i as isRetryableError, l as ErrorCodes, n as createRetryFetch, o as ApiError, r as fetchWithTimeout, s as ErrorHandler, t as calculateBackoffDelay } from "../api-client-CB7XZaMg.mjs";
9
+ import { a as getIdentitySignalRClient, i as createIdentitySignalRClient, n as SignalRClient, o as initializeSignalR, r as cleanupSignalR, t as IdentitySignalRClient } from "../signalr-C-TA8nEE.mjs";
10
+ import { i as invalidationHelpers, n as createQueryClient, r as createQueryKeyFactory, t as cachePresets } from "../query-client-_xB300gc.mjs";
11
+ export { ApiError, ErrorCodes, ErrorHandler, IdentityContextProvider, IdentitySignalRClient, LOG_LEVEL_PRIORITY, LogLevel, Logger, PERMISSION_MODULES, PermissionChecker, PermissionInitializer, ProtectedAction, ProtectedButton, ProtectedLink, ProtectedSection, SignalRClient, TenantProvider, cachePresets, calculateBackoffDelay, cleanupSignalR, configureIdentityEndpoints, configureIdentityStore, configureTenantClient, configureTenantEndpoints, createIdentitySignalRClient, createLogger, createQueryClient, createQueryKeyFactory, createRetryFetch, defaultLoggerConfig, evaluateAccessRequirement, fetchWithTimeout, getIdentitySignalRClient, getPermissionChecker, getPermissions, getTenantCookieName, handleApiError, initialIdentityContext, initializePermissions, initializeSignalR, initializeTenantStore, invalidationHelpers, isApiClientError, isRetryableError, logger, normalizeIdentityContextPayload, normalizeIdentityPermissionsPayload, normalizeTenantDataPayload, normalizeTenantSwitchPayload, resetIdentityStoreConfig, resetTenantClientConfig, useAllPermissions, useCurrentOrganization, useCurrentTenant, useCurrentTenantData, useHasEntitlement, useHasModulePermission, useHasPermission, useHasPermissions, useHasSubscription, useIdentityContext, useIdentityStore, useIsOnboarded, useModulePermission, useOrganization, usePermission, usePermissionChecker, usePermissionStore, usePermissions, useTenant, useTenantData, useTenantStore, useTenantSwitcher, useUserPermissions, useUserTenants, withRetry };
@@ -0,0 +1,17 @@
1
+ import { LOG_LEVEL_PRIORITY, LogLevel, Logger, createLogger, defaultLoggerConfig, logger } from "../logging/index.mjs";
2
+ import { t as PermissionChecker } from "../permission-service-DUyKomU3.mjs";
3
+ import { _ as initializePermissions, a as ProtectedSection, c as useHasPermission, d as usePermission, f as usePermissionChecker, g as getPermissions, h as getPermissionChecker, i as ProtectedLink, l as useHasPermissions, m as PermissionInitializer, n as ProtectedAction, o as useAllPermissions, p as usePermissions, r as ProtectedButton, s as useHasModulePermission, t as PERMISSION_MODULES, u as useModulePermission, v as usePermissionStore } from "../permissions-C5dTP9y4.mjs";
4
+ import { t as evaluateAccessRequirement } from "../access-BHy1v5sr.mjs";
5
+ import { TenantProvider, configureTenantClient, configureTenantEndpoints, getTenantCookieName, initializeTenantStore, normalizeTenantDataPayload, normalizeTenantSwitchPayload, resetTenantClientConfig, useCurrentOrganization, useCurrentTenant, useCurrentTenantData, useOrganization, useTenant, useTenantData, useTenantStore, useTenantSwitcher } from "../tenant/index.mjs";
6
+ import { IdentityContextProvider, configureIdentityEndpoints, configureIdentityStore, initialIdentityContext, normalizeIdentityContextPayload, normalizeIdentityPermissionsPayload, resetIdentityStoreConfig, useHasEntitlement, useHasSubscription, useIdentityContext, useIdentityStore, useIsOnboarded, useUserPermissions, useUserTenants } from "../identity/index.mjs";
7
+ import { t as isApiClientError } from "../types-DqCXinAk.mjs";
8
+ import { a as withRetry, c as handleApiError, i as isRetryableError, l as ErrorCodes, n as createRetryFetch, o as ApiError, r as fetchWithTimeout, s as ErrorHandler, t as calculateBackoffDelay } from "../api-client-CB7XZaMg.mjs";
9
+ import { a as getIdentitySignalRClient, i as createIdentitySignalRClient, n as SignalRClient, o as initializeSignalR, r as cleanupSignalR, t as IdentitySignalRClient } from "../signalr-C-TA8nEE.mjs";
10
+ import { i as invalidationHelpers, n as createQueryClient, r as createQueryKeyFactory, t as cachePresets } from "../query-client-_xB300gc.mjs";
11
+ import { S as updateAuthSession, _ as isSessionValid, a as createOAuthState, b as listCurrentUserAuthSessions, c as destroyAuthSessionById, d as destroyAuthSessionsBySid, f as destroyAuthSessionsForUser, g as getOAuthState, h as getCurrentAuthSessionId, i as createAuthSession, l as destroyAuthSessionsByIdentitySession, m as getAuthSessionById, n as cleanupExpiredOAuthStates, o as deleteOAuthState, p as getAuthSession, r as closeRedisConnection, s as destroyAuthSession, t as AUTH_ERROR_COOKIE_PREFIX, u as destroyAuthSessionsBySessionState, v as listAuthSessionDataForUser, x as requireAuthSession, y as listAuthSessionsForUser } from "../redis-session-storage.server-DGgQcJ9B.mjs";
12
+ import { A as resetAuthClaimMapping, C as handleCallback, D as logout, E as login, O as refreshTokens, S as handleBackChannelLogout, T as hasAuthError, _ as createAuthorizationResponseUrl, a as configureRouteProtection, b as getAuthError, c as protectRoute, d as resetRouteProtectionConfig, f as shouldRefreshToken, g as configureAuthClaimMapping, h as clearAuthServerCache, i as authRoute, k as requireAuth, l as protectedRoute, m as clearAuthErrorHeaders, n as isTokenExpiredResponse, o as onboardingRoute, p as subscriptionRoute, r as shouldAttemptTokenRefresh, s as policyRoute, t as attemptTokenRefresh, u as publicRoute, v as extractUserInfo, w as handleFrontChannelLogout, x as getUser, y as getAccessToken } from "../server-CqX2yCa4.mjs";
13
+ import { clearActiveTenant, clearCurrentTenant, configureIdentityContextFetcher, configureTenantCookie, configureTenantResolution, getActiveTenant, getAvailableTenants, getCurrentTenant, getTenantFromIdentityContext, initializeTenant, resetTenantCookieConfig, resetTenantResolutionConfig, setActiveTenant, setCurrentTenant } from "../tenant/server.mjs";
14
+ import { clearIdentityContextCache, configureIdentityAPIFetcher, configurePermissionFetcher, contextToUserInfo, fetchIdentityContext, fetchUserPermissions, getIdentityContext, hasContextVersionChanged, updateContextVersion } from "../identity/server.mjs";
15
+ import { n as createFetchMiddleware, r as createAPIConfigFactory, t as createApiClient } from "../server-ByScGRXA.mjs";
16
+ import { checkPermission, configurePermissionRouteProtection, requirePermission, resetPermissionRouteProtection, withPermission } from "../server.mjs";
17
+ export { AUTH_ERROR_COOKIE_PREFIX, ApiError, ErrorCodes, ErrorHandler, IdentityContextProvider, IdentitySignalRClient, LOG_LEVEL_PRIORITY, LogLevel, Logger, PERMISSION_MODULES, PermissionChecker, PermissionInitializer, ProtectedAction, ProtectedButton, ProtectedLink, ProtectedSection, SignalRClient, TenantProvider, attemptTokenRefresh, authRoute, cachePresets, calculateBackoffDelay, checkPermission, cleanupExpiredOAuthStates, cleanupSignalR, clearActiveTenant, clearAuthErrorHeaders, clearAuthServerCache, clearCurrentTenant, clearIdentityContextCache, closeRedisConnection, configureAuthClaimMapping, configureIdentityAPIFetcher, configureIdentityContextFetcher, configureIdentityEndpoints, configureIdentityStore, configurePermissionFetcher, configurePermissionRouteProtection, configureRouteProtection, configureTenantClient, configureTenantCookie, configureTenantEndpoints, configureTenantResolution, contextToUserInfo, createAPIConfigFactory, createApiClient, createAuthSession, createAuthorizationResponseUrl, createFetchMiddleware, createIdentitySignalRClient, createLogger, createOAuthState, createQueryClient, createQueryKeyFactory, createRetryFetch, defaultLoggerConfig, deleteOAuthState, destroyAuthSession, destroyAuthSessionById, destroyAuthSessionsByIdentitySession, destroyAuthSessionsBySessionState, destroyAuthSessionsBySid, destroyAuthSessionsForUser, evaluateAccessRequirement, extractUserInfo, fetchIdentityContext, fetchUserPermissions, fetchWithTimeout, getAccessToken, getActiveTenant, getAuthError, getAuthSession, getAuthSessionById, getAvailableTenants, getCurrentAuthSessionId, getCurrentTenant, getIdentityContext, getIdentitySignalRClient, getOAuthState, getPermissionChecker, getPermissions, getTenantCookieName, getTenantFromIdentityContext, getUser, handleApiError, handleBackChannelLogout, handleCallback, handleFrontChannelLogout, hasAuthError, hasContextVersionChanged, initialIdentityContext, initializePermissions, initializeSignalR, initializeTenant, initializeTenantStore, invalidationHelpers, isApiClientError, isRetryableError, isSessionValid, isTokenExpiredResponse, listAuthSessionDataForUser, listAuthSessionsForUser, listCurrentUserAuthSessions, logger, login, logout, normalizeIdentityContextPayload, normalizeIdentityPermissionsPayload, normalizeTenantDataPayload, normalizeTenantSwitchPayload, onboardingRoute, policyRoute, protectRoute, protectedRoute, publicRoute, refreshTokens, requireAuth, requireAuthSession, requirePermission, resetAuthClaimMapping, resetIdentityStoreConfig, resetPermissionRouteProtection, resetRouteProtectionConfig, resetTenantClientConfig, resetTenantCookieConfig, resetTenantResolutionConfig, setActiveTenant, setCurrentTenant, shouldAttemptTokenRefresh, shouldRefreshToken, subscriptionRoute, updateAuthSession, updateContextVersion, useAllPermissions, useCurrentOrganization, useCurrentTenant, useCurrentTenantData, useHasEntitlement, useHasModulePermission, useHasPermission, useHasPermissions, useHasSubscription, useIdentityContext, useIdentityStore, useIsOnboarded, useModulePermission, useOrganization, usePermission, usePermissionChecker, usePermissionStore, usePermissions, useTenant, useTenantData, useTenantStore, useTenantSwitcher, useUserPermissions, useUserTenants, withPermission, withRetry };
@@ -1,8 +1,14 @@
1
- import { logger } from "./logging-DviiAkLx.js";
1
+ import { logger } from "./logging/index.mjs";
2
2
  import Redis from "ioredis";
3
3
  import { createCipheriv, createDecipheriv, createHmac, randomBytes, timingSafeEqual } from "node:crypto";
4
-
5
4
  //#region src/auth/redis-session-storage.server.ts
5
+ /**
6
+ * Redis Session Storage Server Module
7
+ *
8
+ * Redis-backed session storage for authentication.
9
+ * Provides secure session management with automatic expiration,
10
+ * without depending on a framework-specific session implementation.
11
+ */
6
12
  let redis = null;
7
13
  function getRedis() {
8
14
  if (!redis) {
@@ -25,9 +31,8 @@ const REDIS_KEYS = {
25
31
  sessionBySessionState: (sessionState) => `${KEY_PREFIX}session:index:session_state:${sessionState}`
26
32
  };
27
33
  const DEFAULT_SESSION_SECRET = "default-secret-change-in-production";
28
- const DEFAULT_SESSION_TTL = 60 * 60 * 24 * 7;
29
- const DEFAULT_OAUTH_STATE_TTL = 10 * 60;
30
- const OAUTH_STATE_TTL = resolvePositiveIntegerEnv("OAUTH_STATE_TTL", DEFAULT_OAUTH_STATE_TTL);
34
+ const DEFAULT_SESSION_TTL = 3600 * 24 * 7;
35
+ const OAUTH_STATE_TTL = resolvePositiveIntegerEnv("OAUTH_STATE_TTL", 600);
31
36
  const SESSION_TTL = resolvePositiveIntegerEnv("SESSION_DEFAULT_TTL", resolvePositiveIntegerEnv("SESSION_TTL", DEFAULT_SESSION_TTL));
32
37
  const SESSION_COOKIE_NAME = process.env.SESSION_COOKIE_NAME || "__session_id";
33
38
  const SESSION_SECRET = resolveSessionSecret();
@@ -120,8 +125,7 @@ function safelyCompareValues(left, right) {
120
125
  return timingSafeEqual(leftBuffer, rightBuffer);
121
126
  }
122
127
  function signSessionId(sessionId) {
123
- const signature = createCookieSignature(sessionId, SESSION_SECRET);
124
- return `${sessionId}.${signature}`;
128
+ return `${sessionId}.${createCookieSignature(sessionId, SESSION_SECRET)}`;
125
129
  }
126
130
  function unsignSessionId(cookieValue) {
127
131
  if (!cookieValue) return null;
@@ -134,9 +138,7 @@ function unsignSessionId(cookieValue) {
134
138
  const separatorIndex = decodedValue.lastIndexOf(".");
135
139
  if (separatorIndex <= 0 || separatorIndex === decodedValue.length - 1) return null;
136
140
  const sessionId = decodedValue.slice(0, separatorIndex);
137
- const signature = decodedValue.slice(separatorIndex + 1);
138
- const expectedSignature = createCookieSignature(sessionId, SESSION_SECRET);
139
- return safelyCompareValues(signature, expectedSignature) ? sessionId : null;
141
+ return safelyCompareValues(decodedValue.slice(separatorIndex + 1), createCookieSignature(sessionId, SESSION_SECRET)) ? sessionId : null;
140
142
  }
141
143
  function serializeSessionCookieValue(sessionId, options) {
142
144
  const signedValue = encodeURIComponent(signSessionId(sessionId));
@@ -164,11 +166,10 @@ function serializeExpiredSessionCookie() {
164
166
  return segments.join("; ");
165
167
  }
166
168
  async function getSessionIdFromRequest(request) {
167
- const cookies = parseCookieHeader(request.headers.get("Cookie"));
168
- return unsignSessionId(cookies[SESSION_COOKIE_NAME]);
169
+ return unsignSessionId(parseCookieHeader(request.headers.get("Cookie"))[SESSION_COOKIE_NAME]);
169
170
  }
170
171
  function getSessionIndexKeys(data) {
171
- const keys = new Set();
172
+ const keys = /* @__PURE__ */ new Set();
172
173
  if (data.userId) keys.add(REDIS_KEYS.sessionByUser(data.userId));
173
174
  if (data.sid) keys.add(REDIS_KEYS.sessionBySid(data.sid));
174
175
  if (data.sessionState) keys.add(REDIS_KEYS.sessionBySessionState(data.sessionState));
@@ -177,8 +178,7 @@ function getSessionIndexKeys(data) {
177
178
  async function registerSessionIndexes(sessionId, data) {
178
179
  const indexKeys = getSessionIndexKeys(data);
179
180
  if (indexKeys.length === 0) return;
180
- const redisClient = getRedis();
181
- const pipeline = redisClient.pipeline();
181
+ const pipeline = getRedis().pipeline();
182
182
  for (const indexKey of indexKeys) {
183
183
  pipeline.sadd(indexKey, sessionId);
184
184
  pipeline.expire(indexKey, SESSION_TTL);
@@ -188,8 +188,7 @@ async function registerSessionIndexes(sessionId, data) {
188
188
  async function unregisterSessionIndexes(sessionId, data) {
189
189
  const indexKeys = getSessionIndexKeys(data);
190
190
  if (indexKeys.length === 0) return;
191
- const redisClient = getRedis();
192
- const pipeline = redisClient.pipeline();
191
+ const pipeline = getRedis().pipeline();
193
192
  for (const indexKey of indexKeys) pipeline.srem(indexKey, sessionId);
194
193
  await pipeline.exec();
195
194
  }
@@ -279,11 +278,8 @@ async function getSessionIdsFromIndex(indexKey) {
279
278
  const sessionIds = await getRedis().smembers(indexKey);
280
279
  const activeSessionIds = [];
281
280
  const staleSessionIds = [];
282
- for (const sessionId of sessionIds) {
283
- const exists = await getRedis().exists(REDIS_KEYS.session(sessionId));
284
- if (exists) activeSessionIds.push(sessionId);
285
- else staleSessionIds.push(sessionId);
286
- }
281
+ for (const sessionId of sessionIds) if (await getRedis().exists(REDIS_KEYS.session(sessionId))) activeSessionIds.push(sessionId);
282
+ else staleSessionIds.push(sessionId);
287
283
  if (staleSessionIds.length > 0) await getRedis().srem(indexKey, ...staleSessionIds);
288
284
  return activeSessionIds;
289
285
  }
@@ -317,8 +313,7 @@ async function listSessionDataByIds(sessionIds) {
317
313
  return sessions;
318
314
  }
319
315
  function getRequestIpAddress(request) {
320
- const forwardedFor = request.headers.get("x-forwarded-for")?.split(",")[0]?.trim();
321
- return forwardedFor || request.headers.get("cf-connecting-ip")?.trim() || request.headers.get("x-real-ip")?.trim() || void 0;
316
+ return request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || request.headers.get("cf-connecting-ip")?.trim() || request.headers.get("x-real-ip")?.trim() || void 0;
322
317
  }
323
318
  async function createAuthSession(request, sessionData) {
324
319
  const currentSessionId = await getSessionIdFromRequest(request);
@@ -361,11 +356,10 @@ async function updateAuthSession(request, updates) {
361
356
  const currentSessionId = await getSessionIdFromRequest(request);
362
357
  const currentSessionData = currentSessionId ? await readSessionData(currentSessionId) ?? {} : {};
363
358
  const nextSessionId = currentSessionId ?? crypto.randomUUID();
364
- const nextSessionData = mergeSessionData(currentSessionData, {
359
+ await writeSessionData(nextSessionId, mergeSessionData(currentSessionData, {
365
360
  ...updates,
366
361
  sessionId: nextSessionId
367
- });
368
- await writeSessionData(nextSessionId, nextSessionData);
362
+ }));
369
363
  return new Headers({ "Set-Cookie": serializeSessionCookieValue(nextSessionId, { maxAge: SESSION_TTL }) });
370
364
  }
371
365
  async function destroyAuthSession(request) {
@@ -384,12 +378,10 @@ async function getAuthSessionById(sessionId) {
384
378
  } : null;
385
379
  }
386
380
  async function listAuthSessionDataForUser(userId) {
387
- const sessionIds = await getSessionIdsFromIndex(REDIS_KEYS.sessionByUser(userId));
388
- return await listSessionDataByIds(sessionIds);
381
+ return await listSessionDataByIds(await getSessionIdsFromIndex(REDIS_KEYS.sessionByUser(userId)));
389
382
  }
390
383
  async function listAuthSessionsForUser(userId, currentSessionId) {
391
- const sessions = await listAuthSessionDataForUser(userId);
392
- return sessions.map(({ sessionId, data }) => toAuthSessionSummary(sessionId, data, currentSessionId)).sort((left, right) => (right.lastActivity ?? right.createdAt ?? 0) - (left.lastActivity ?? left.createdAt ?? 0));
384
+ return (await listAuthSessionDataForUser(userId)).map(({ sessionId, data }) => toAuthSessionSummary(sessionId, data, currentSessionId)).sort((left, right) => (right.lastActivity ?? right.createdAt ?? 0) - (left.lastActivity ?? left.createdAt ?? 0));
393
385
  }
394
386
  async function listCurrentUserAuthSessions(request) {
395
387
  const currentSession = await getAuthSession(request);
@@ -397,8 +389,7 @@ async function listCurrentUserAuthSessions(request) {
397
389
  return await listAuthSessionsForUser(currentSession.userId, currentSession.sessionId);
398
390
  }
399
391
  async function destroyAuthSessionById(sessionId) {
400
- const session = await readSessionData(sessionId);
401
- if (!session) return false;
392
+ if (!await readSessionData(sessionId)) return false;
402
393
  await deleteSessionData(sessionId);
403
394
  return true;
404
395
  }
@@ -474,12 +465,9 @@ async function cleanupExpiredOAuthStates() {
474
465
  const pattern = REDIS_KEYS.oauthState("*");
475
466
  const keys = await getRedis().keys(pattern);
476
467
  let cleaned = 0;
477
- for (const key of keys) {
478
- const ttl = await getRedis().ttl(key);
479
- if (ttl === -1) {
480
- await getRedis().del(key);
481
- cleaned++;
482
- }
468
+ for (const key of keys) if (await getRedis().ttl(key) === -1) {
469
+ await getRedis().del(key);
470
+ cleaned++;
483
471
  }
484
472
  logger.info("OAuth state cleanup completed", {
485
473
  cleaned,
@@ -494,7 +482,7 @@ async function closeRedisConnection() {
494
482
  logger.info("Redis connection closed");
495
483
  }
496
484
  }
497
-
498
485
  //#endregion
499
- export { AUTH_ERROR_COOKIE_PREFIX, cleanupExpiredOAuthStates, closeRedisConnection, createAuthSession, createOAuthState, deleteOAuthState, destroyAuthSession, destroyAuthSessionById, destroyAuthSessionsByIdentitySession, destroyAuthSessionsBySessionState, destroyAuthSessionsBySid, destroyAuthSessionsForUser, getAuthSession, getAuthSessionById, getCurrentAuthSessionId, getOAuthState, isSessionValid, listAuthSessionDataForUser, listAuthSessionsForUser, listCurrentUserAuthSessions, requireAuthSession, updateAuthSession };
500
- //# sourceMappingURL=redis-session-storage.server-v2VcpFsQ.js.map
486
+ export { updateAuthSession as S, isSessionValid as _, createOAuthState as a, listCurrentUserAuthSessions as b, destroyAuthSessionById as c, destroyAuthSessionsBySid as d, destroyAuthSessionsForUser as f, getOAuthState as g, getCurrentAuthSessionId as h, createAuthSession as i, destroyAuthSessionsByIdentitySession as l, getAuthSessionById as m, cleanupExpiredOAuthStates as n, deleteOAuthState as o, getAuthSession as p, closeRedisConnection as r, destroyAuthSession as s, AUTH_ERROR_COOKIE_PREFIX as t, destroyAuthSessionsBySessionState as u, listAuthSessionDataForUser as v, requireAuthSession as x, listAuthSessionsForUser as y };
487
+
488
+ //# sourceMappingURL=redis-session-storage.server-DGgQcJ9B.mjs.map