@getstrata/bootstrap 0.4.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +1 -1
  3. package/dist/_.._/_.._/index.html +1 -1
  4. package/dist/bootstrap/web/session.d.ts +1 -0
  5. package/dist/entries/applicationRegistry.js +0 -2
  6. package/dist/entries/buildModuleRoutes.js +2 -4
  7. package/dist/entries/buildWebModuleRoutes.js +2 -4
  8. package/dist/entries/cache/modelCacheTags.js +0 -2
  9. package/dist/entries/config.js +0 -2
  10. package/dist/entries/context.js +0 -2
  11. package/dist/entries/contracts.js +0 -2
  12. package/dist/entries/createRoutes.js +4 -4
  13. package/dist/entries/createSpaRoutes.js +1 -3
  14. package/dist/entries/createWebRoutes.js +2 -4
  15. package/dist/entries/dependencies.js +0 -2
  16. package/dist/entries/discoverModules.js +0 -2
  17. package/dist/entries/health.js +0 -2
  18. package/dist/entries/http/securedRouteModelBinding.js +0 -2
  19. package/dist/entries/httpKernel.js +2 -4
  20. package/dist/entries/listeners/invalidateCacheOnModelWrite.js +0 -2
  21. package/dist/entries/membershipService.js +0 -2
  22. package/dist/entries/metricsRoutes.js +0 -2
  23. package/dist/entries/providers/view.js +0 -2
  24. package/dist/entries/providers.js +0 -2
  25. package/dist/entries/queue/defaultJobs.js +0 -2
  26. package/dist/entries/routeRegistry.js +0 -2
  27. package/dist/entries/schedule.js +0 -2
  28. package/dist/entries/secretsGuard.js +0 -2
  29. package/dist/entries/web/forms.js +0 -2
  30. package/dist/entries/web/routing.js +2 -4
  31. package/dist/entries/web/server.js +0 -2
  32. package/dist/entries/web/session.js +5 -5
  33. package/dist/entries/web/slug.js +0 -2
  34. package/dist/index.js +7 -5
  35. package/package.json +2 -2
  36. /package/dist/{index-sfreg6q3.js → index-a3tzxvag.js} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @getstrata/bootstrap changelog
2
2
 
3
+ ## 1.0.0
4
+
5
+ - First stable release of `@getstrata/bootstrap`.
6
+
7
+ ## 0.4.3
8
+
9
+ - Cookie session `mapUser` / row mapping can pass `email_verified_at` through as `emailVerifiedAt` so HTML email verification works.
10
+ - Session insert binds `expires_at` as an ISO string so SQLite cookie login does not fail parameter binding.
11
+
3
12
  ## 0.4.2
4
13
 
5
14
  - `HttpKernel.wrapApi` uses `withJsonErrorHandling`. Hybrid views do not turn API errors into HTML.
package/README.md CHANGED
@@ -38,4 +38,4 @@ HTML apps should bind `createCookieSessionAuthManager` from `@getstrata/bootstra
38
38
 
39
39
  `registerDefaultJobs()` registers `cache.invalidate-tags` and `audit.export` only. Apps that dispatch model webhooks should call `registerWebhookJobs()` themselves.
40
40
 
41
- These subpaths assemble leftover fixture HTTP for framework tests and are not a generic starter API: `@getstrata/bootstrap/createRoutes`, `@getstrata/bootstrap/schedule`, `@getstrata/bootstrap/createWebRoutes`. New apps should use `buildWebModuleRoutes` / `buildModuleRoutes`. HiroApp uses `createApp()` in `apps/hiroapp`.
41
+ These subpaths assemble leftover fixture HTTP for framework tests and are not a generic starter API: `@getstrata/bootstrap/createRoutes`, `@getstrata/bootstrap/schedule`, `@getstrata/bootstrap/createWebRoutes`. New apps should use `buildWebModuleRoutes` / `buildModuleRoutes`. Generated examples use `createApp()` in `apps/hiroapp`.
@@ -75,7 +75,7 @@
75
75
  font-size: 0.95rem;
76
76
  }
77
77
  </style>
78
- <script type="module" crossorigin src="../../index-sfreg6q3.js"></script></head>
78
+ <script type="module" crossorigin src="../../index-a3tzxvag.js"></script></head>
79
79
 
80
80
  <body>
81
81
  <h1>Strata</h1>
@@ -6,6 +6,7 @@ export interface SessionUser {
6
6
  email: string;
7
7
  learn_subscriber?: boolean;
8
8
  is_admin?: boolean;
9
+ email_verified_at?: Date | string | null;
9
10
  }
10
11
  type SqlClient = {
11
12
  unsafe<T>(query: string, params?: readonly unknown[]): Promise<T[]>;
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/applicationRegistry.ts
5
3
  import {
6
4
  resolveApplicationAuth,
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/buildModuleRoutes.ts
5
3
  import { conditionalJsonResponse } from "@getstrata/core/http/conditionalResponse";
6
4
  import { applyMiddlewareToRoutes } from "@getstrata/core/http/middleware";
@@ -146,10 +144,10 @@ class HttpKernel {
146
144
  const config = this.dependencies.container.resolve(CORE_CONFIG_TOKEN);
147
145
  const redisUrl = config.get(REDIS_URL_CONFIG_KEY)?.trim() ?? "";
148
146
  if (!redisUrl) {
149
- const maxAttempts2 = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
147
+ const maxAttempts = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
150
148
  return [
151
149
  createMemoryThrottleMiddleware({
152
- maxAttempts: Number.isFinite(maxAttempts2) ? maxAttempts2 : 120,
150
+ maxAttempts: Number.isFinite(maxAttempts) ? maxAttempts : 120,
153
151
  decaySeconds: 60
154
152
  })
155
153
  ];
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/buildWebModuleRoutes.ts
5
3
  import { applyMiddlewareToRoutes as applyMiddlewareToRoutes2 } from "@getstrata/core/http/middleware";
6
4
 
@@ -149,10 +147,10 @@ class HttpKernel {
149
147
  const config = this.dependencies.container.resolve(CORE_CONFIG_TOKEN);
150
148
  const redisUrl = config.get(REDIS_URL_CONFIG_KEY)?.trim() ?? "";
151
149
  if (!redisUrl) {
152
- const maxAttempts2 = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
150
+ const maxAttempts = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
153
151
  return [
154
152
  createMemoryThrottleMiddleware({
155
- maxAttempts: Number.isFinite(maxAttempts2) ? maxAttempts2 : 120,
153
+ maxAttempts: Number.isFinite(maxAttempts) ? maxAttempts : 120,
156
154
  decaySeconds: 60
157
155
  })
158
156
  ];
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/discoverModules.ts
5
3
  import { readdirSync } from "fs";
6
4
  import { join } from "path";
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/config.ts
5
3
  import {
6
4
  CORE_ABILITY_CHECKER_TOKEN,
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/applicationRegistry.ts
5
3
  import {
6
4
  resolveApplicationAuth,
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/contracts.ts
5
3
  import {
6
4
  ConfigStore,
@@ -7,7 +7,7 @@ import { isSpaEnabled as isSpaEnabled2, isViewsEnabled as isViewsEnabled4 } from
7
7
  import { notFoundHtmlResponse as notFoundHtmlResponse2 } from "@getstrata/core/view";
8
8
 
9
9
  // ../../index.html
10
- var strata_default = __jsonParse("{\"index\":\"_.._/_.._/index.html\",\"files\":[{\"input\":\"../../index.html\",\"path\":\"./index-sfreg6q3.js\",\"loader\":\"js\",\"isEntry\":true,\"headers\":{\"etag\":\"Oc_YLpCmV6M\",\"content-type\":\"text/javascript;charset=utf-8\"}},{\"input\":\"../../index.html\",\"path\":\"_.._/_.._/index.html\",\"loader\":\"html\",\"isEntry\":true,\"headers\":{\"etag\":\"ojosdcZCk7g\",\"content-type\":\"text/html;charset=utf-8\"}}]}");
10
+ var strata_default = __jsonParse("{\"index\":\"_.._/_.._/index.html\",\"files\":[{\"input\":\"../../index.html\",\"path\":\"./index-a3tzxvag.js\",\"loader\":\"js\",\"isEntry\":true,\"headers\":{\"etag\":\"qoOafz0bKrA\",\"content-type\":\"text/javascript;charset=utf-8\"}},{\"input\":\"../../index.html\",\"path\":\"_.._/_.._/index.html\",\"loader\":\"html\",\"isEntry\":true,\"headers\":{\"etag\":\"g_F9s_nobLw\",\"content-type\":\"text/html;charset=utf-8\"}}]}");
11
11
 
12
12
  // ../../src/config/app.ts
13
13
  var appConfig = {
@@ -163,10 +163,10 @@ class HttpKernel {
163
163
  const config = this.dependencies.container.resolve(CORE_CONFIG_TOKEN);
164
164
  const redisUrl = config.get(REDIS_URL_CONFIG_KEY)?.trim() ?? "";
165
165
  if (!redisUrl) {
166
- const maxAttempts2 = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
166
+ const maxAttempts = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
167
167
  return [
168
168
  createMemoryThrottleMiddleware({
169
- maxAttempts: Number.isFinite(maxAttempts2) ? maxAttempts2 : 120,
169
+ maxAttempts: Number.isFinite(maxAttempts) ? maxAttempts : 120,
170
170
  decaySeconds: 60
171
171
  })
172
172
  ];
@@ -534,7 +534,7 @@ function createSpaDocumentHandler(prefix, distDirectory) {
534
534
  function createSpaRoutes(_dependencies, options = {}) {
535
535
  const prefix = options.prefix ?? readSpaPrefix();
536
536
  const distDirectory = options.distDirectory ?? SPA_DIST_DIRECTORY;
537
- const wrap = options.wrap ?? ((handler2) => handler2);
537
+ const wrap = options.wrap ?? ((handler) => handler);
538
538
  const handler = wrap(createSpaDocumentHandler(prefix, distDirectory));
539
539
  const routes = {
540
540
  [prefix]: handler,
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/createSpaRoutes.ts
5
3
  import { join } from "path";
6
4
  import { jsonResponse } from "@getstrata/core/http/response";
@@ -41,7 +39,7 @@ function createSpaDocumentHandler(prefix, distDirectory) {
41
39
  function createSpaRoutes(_dependencies, options = {}) {
42
40
  const prefix = options.prefix ?? readSpaPrefix();
43
41
  const distDirectory = options.distDirectory ?? SPA_DIST_DIRECTORY;
44
- const wrap = options.wrap ?? ((handler2) => handler2);
42
+ const wrap = options.wrap ?? ((handler) => handler);
45
43
  const handler = wrap(createSpaDocumentHandler(prefix, distDirectory));
46
44
  const routes = {
47
45
  [prefix]: handler,
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/createWebRoutes.ts
5
3
  import { join as join2 } from "path";
6
4
  import { isViewsEnabled as isViewsEnabled2 } from "@getstrata/core/runtime/frontendMode";
@@ -154,10 +152,10 @@ class HttpKernel {
154
152
  const config = this.dependencies.container.resolve(CORE_CONFIG_TOKEN);
155
153
  const redisUrl = config.get(REDIS_URL_CONFIG_KEY)?.trim() ?? "";
156
154
  if (!redisUrl) {
157
- const maxAttempts2 = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
155
+ const maxAttempts = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
158
156
  return [
159
157
  createMemoryThrottleMiddleware({
160
- maxAttempts: Number.isFinite(maxAttempts2) ? maxAttempts2 : 120,
158
+ maxAttempts: Number.isFinite(maxAttempts) ? maxAttempts : 120,
161
159
  decaySeconds: 60
162
160
  })
163
161
  ];
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/applicationRegistry.ts
5
3
  import {
6
4
  resolveApplicationAuth,
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/discoverModules.ts
5
3
  import { readdirSync } from "fs";
6
4
  import { join } from "path";
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/health.ts
5
3
  import { getBoundDatabaseConnection } from "@getstrata/core/database/boundConnection";
6
4
  import { getDefaultDatabasePool } from "@getstrata/core/database/defaultConnection";
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/http/securedRouteModelBinding.ts
5
3
  import {
6
4
  securedBindRouteModel,
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/httpKernel.ts
5
3
  import {
6
4
  hasVerifiedEmail,
@@ -142,10 +140,10 @@ class HttpKernel {
142
140
  const config = this.dependencies.container.resolve(CORE_CONFIG_TOKEN);
143
141
  const redisUrl = config.get(REDIS_URL_CONFIG_KEY)?.trim() ?? "";
144
142
  if (!redisUrl) {
145
- const maxAttempts2 = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
143
+ const maxAttempts = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
146
144
  return [
147
145
  createMemoryThrottleMiddleware({
148
- maxAttempts: Number.isFinite(maxAttempts2) ? maxAttempts2 : 120,
146
+ maxAttempts: Number.isFinite(maxAttempts) ? maxAttempts : 120,
149
147
  decaySeconds: 60
150
148
  })
151
149
  ];
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/listeners/invalidateCacheOnModelWrite.ts
5
3
  import { eventBus, modelEventName } from "@getstrata/core/events";
6
4
  import { InvalidateCacheTagsJob } from "@getstrata/core/jobs/invalidateCacheTagsJob";
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/membershipService.ts
5
3
  import { resolveMembershipService } from "@getstrata/core/auth/membershipService";
6
4
  export {
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/metricsRoutes.ts
5
3
  import { timingSafeEqual } from "crypto";
6
4
  import { prometheusRegistry } from "@getstrata/core/metrics/prometheus";
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/providers/view.ts
5
3
  import { currentRequestMeta } from "@getstrata/core/http/requestMetaContext";
6
4
  import { appDisplayName } from "@getstrata/core/runtime/appKeyPrefix";
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/providers/auth.ts
5
3
  import { BasicAuthGuard } from "@getstrata/core/auth/basicAuthGuard";
6
4
  import {
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/queue/defaultJobs.ts
5
3
  import { ExportAuditLogsJob } from "@getstrata/core/jobs/exportAuditLogsJob";
6
4
  import { InvalidateCacheTagsJob } from "@getstrata/core/jobs/invalidateCacheTagsJob";
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/routeRegistry.ts
5
3
  class RouteRegistry {
6
4
  routes = [];
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/schedule.ts
5
3
  import { ExportAuditLogsJob } from "@getstrata/core/jobs/exportAuditLogsJob";
6
4
  import { appLogger } from "@getstrata/core/logging/logger";
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/secretsGuard.ts
5
3
  import { isViewsMode, parseFrontendMode } from "@getstrata/core/runtime/frontendMode";
6
4
  var PUBLISHED_TEST_ADMIN_API_TOKEN = "strata-admin-test-token";
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/web/forms.ts
5
3
  import {
6
4
  createCsrfProtection
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/web/routing.ts
5
3
  import { requestPrefersJson } from "@getstrata/core/http/contentNegotiation";
6
4
  import { withErrorHandling as withErrorHandling2 } from "@getstrata/core/http/response";
@@ -152,10 +150,10 @@ class HttpKernel {
152
150
  const config = this.dependencies.container.resolve(CORE_CONFIG_TOKEN);
153
151
  const redisUrl = config.get(REDIS_URL_CONFIG_KEY)?.trim() ?? "";
154
152
  if (!redisUrl) {
155
- const maxAttempts2 = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
153
+ const maxAttempts = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
156
154
  return [
157
155
  createMemoryThrottleMiddleware({
158
- maxAttempts: Number.isFinite(maxAttempts2) ? maxAttempts2 : 120,
156
+ maxAttempts: Number.isFinite(maxAttempts) ? maxAttempts : 120,
159
157
  decaySeconds: 60
160
158
  })
161
159
  ];
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/web/server.ts
5
3
  import { currentRequestMeta, runWithRequestMeta } from "@getstrata/core/http/requestMetaContext";
6
4
  import { notFoundHtmlResponse } from "@getstrata/core/view";
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/web/session.ts
5
3
  import { createHmac, randomBytes } from "crypto";
6
4
  import { AuthManager } from "@getstrata/core/auth/guard";
@@ -34,7 +32,8 @@ function defaultSessionSql() {
34
32
  function defaultMapSessionUser(user) {
35
33
  return {
36
34
  id: user.id,
37
- role: user.is_admin ? "admin" : "member"
35
+ role: user.is_admin ? "admin" : "member",
36
+ ...user.email_verified_at !== undefined ? { emailVerifiedAt: user.email_verified_at } : {}
38
37
  };
39
38
  }
40
39
  function sessionDisplayName(row, email) {
@@ -53,7 +52,8 @@ function mapSessionUserRow(row) {
53
52
  name: sessionDisplayName(row, email),
54
53
  email,
55
54
  learn_subscriber: Boolean(row.learn_subscriber),
56
- is_admin: Boolean(row.is_admin)
55
+ is_admin: Boolean(row.is_admin),
56
+ ...row.email_verified_at !== undefined ? { email_verified_at: row.email_verified_at } : {}
57
57
  };
58
58
  }
59
59
  async function defaultLoadSessionUser(sql, sessionId) {
@@ -120,7 +120,7 @@ class CookieSessionStore {
120
120
  const id = randomBytes(32).toString("hex");
121
121
  const expires = new Date(Date.now() + this.maxAgeSeconds * 1000);
122
122
  await this.sql().unsafe(`INSERT INTO sessions (id, user_id, expires_at, user_agent, ip_address, last_active_at)
123
- VALUES (${sqlPlaceholder(1)}, ${sqlPlaceholder(2)}, ${sqlPlaceholder(3)}, ${sqlPlaceholder(4)}, ${sqlPlaceholder(5)}, ${sqlNow()})`, [id, user.id, expires, meta.userAgent ?? null, meta.ipAddress ?? null]);
123
+ VALUES (${sqlPlaceholder(1)}, ${sqlPlaceholder(2)}, ${sqlPlaceholder(3)}, ${sqlPlaceholder(4)}, ${sqlPlaceholder(5)}, ${sqlNow()})`, [id, user.id, expires.toISOString(), meta.userAgent ?? null, meta.ipAddress ?? null]);
124
124
  return id;
125
125
  }
126
126
  async destroy(sessionId) {
@@ -1,6 +1,4 @@
1
1
  // @bun
2
- var __jsonParse = (a) => JSON.parse(a);
3
-
4
2
  // ../../src/bootstrap/web/slug.ts
5
3
  function slugify(value) {
6
4
  return value.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
package/dist/index.js CHANGED
@@ -158,10 +158,10 @@ class HttpKernel {
158
158
  const config = this.dependencies.container.resolve(CORE_CONFIG_TOKEN);
159
159
  const redisUrl = config.get(REDIS_URL_CONFIG_KEY)?.trim() ?? "";
160
160
  if (!redisUrl) {
161
- const maxAttempts2 = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
161
+ const maxAttempts = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
162
162
  return [
163
163
  createMemoryThrottleMiddleware({
164
- maxAttempts: Number.isFinite(maxAttempts2) ? maxAttempts2 : 120,
164
+ maxAttempts: Number.isFinite(maxAttempts) ? maxAttempts : 120,
165
165
  decaySeconds: 60
166
166
  })
167
167
  ];
@@ -1423,7 +1423,8 @@ function defaultSessionSql() {
1423
1423
  function defaultMapSessionUser(user) {
1424
1424
  return {
1425
1425
  id: user.id,
1426
- role: user.is_admin ? "admin" : "member"
1426
+ role: user.is_admin ? "admin" : "member",
1427
+ ...user.email_verified_at !== undefined ? { emailVerifiedAt: user.email_verified_at } : {}
1427
1428
  };
1428
1429
  }
1429
1430
  function sessionDisplayName(row, email) {
@@ -1442,7 +1443,8 @@ function mapSessionUserRow(row) {
1442
1443
  name: sessionDisplayName(row, email),
1443
1444
  email,
1444
1445
  learn_subscriber: Boolean(row.learn_subscriber),
1445
- is_admin: Boolean(row.is_admin)
1446
+ is_admin: Boolean(row.is_admin),
1447
+ ...row.email_verified_at !== undefined ? { email_verified_at: row.email_verified_at } : {}
1446
1448
  };
1447
1449
  }
1448
1450
  async function defaultLoadSessionUser(sql, sessionId) {
@@ -1509,7 +1511,7 @@ class CookieSessionStore {
1509
1511
  const id = randomBytes(32).toString("hex");
1510
1512
  const expires = new Date(Date.now() + this.maxAgeSeconds * 1000);
1511
1513
  await this.sql().unsafe(`INSERT INTO sessions (id, user_id, expires_at, user_agent, ip_address, last_active_at)
1512
- VALUES (${sqlPlaceholder(1)}, ${sqlPlaceholder(2)}, ${sqlPlaceholder(3)}, ${sqlPlaceholder(4)}, ${sqlPlaceholder(5)}, ${sqlNow()})`, [id, user.id, expires, meta.userAgent ?? null, meta.ipAddress ?? null]);
1514
+ VALUES (${sqlPlaceholder(1)}, ${sqlPlaceholder(2)}, ${sqlPlaceholder(3)}, ${sqlPlaceholder(4)}, ${sqlPlaceholder(5)}, ${sqlNow()})`, [id, user.id, expires.toISOString(), meta.userAgent ?? null, meta.ipAddress ?? null]);
1513
1515
  return id;
1514
1516
  }
1515
1517
  async destroy(sessionId) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getstrata/bootstrap",
3
- "version": "0.4.2",
3
+ "version": "1.0.0",
4
4
  "description": "Strata application bootstrap: HttpKernel, DI, web session helpers",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -180,7 +180,7 @@
180
180
  "access": "public"
181
181
  },
182
182
  "peerDependencies": {
183
- "@getstrata/core": "^0.7.2",
183
+ "@getstrata/core": "^1.0.0",
184
184
  "typescript": "^5.9.0"
185
185
  }
186
186
  }
File without changes