3636 */
3737
3838import type { SessionData , SessionStore } from '@stacksjs/bun-router'
39- import { decrypt , encrypt } from '@stacksjs/security'
39+
40+ type SecurityModule = typeof import ( '@stacksjs/security' )
41+
42+ let securityModuleLoad : Promise < SecurityModule > | undefined
43+
44+ /**
45+ * Encryption is optional session-store work, not router boot work.
46+ *
47+ * Keeping this import behind the first encrypted read/write prevents the
48+ * normal `@stacksjs/router` barrel from evaluating the security package and
49+ * its transitive cryptography/config graph in apps that do not use encrypted
50+ * sessions. The promise is cached so an active store resolves the module once.
51+ */
52+ function loadSecurityModule ( ) : Promise < SecurityModule > {
53+ securityModuleLoad ??= import ( '@stacksjs/security' )
54+ return securityModuleLoad
55+ }
4056
4157/**
4258 * Envelope shape persisted to the underlying store. The `_enc`
@@ -143,6 +159,7 @@ export class EncryptedSessionStore implements SessionStore<SessionData> {
143159 // Don't encrypt the `id` field — middleware reads it back without
144160 // decrypting (for SID-match) and the value is already in the URL/cookie.
145161 const { id, ...rest } = session
162+ const { encrypt } = await loadSecurityModule ( )
146163 const ciphertext = await encrypt ( JSON . stringify ( rest ) , this . opts . appKey )
147164 return {
148165 _enc : true ,
@@ -166,6 +183,7 @@ export class EncryptedSessionStore implements SessionStore<SessionData> {
166183
167184 if ( candidate . _enc === true && typeof candidate . data === 'string' ) {
168185 try {
186+ const { decrypt } = await loadSecurityModule ( )
169187 const decrypted = await decrypt ( candidate . data , this . opts . appKey )
170188 const parsed = JSON . parse ( decrypted ) as SessionData
171189 if ( candidate . id !== undefined ) parsed . id = candidate . id
0 commit comments