@getstrata/bootstrap 0.2.66 → 0.4.2

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.
@@ -40,7 +40,12 @@ function readDiscoverModulesState() {
40
40
  return state;
41
41
  }
42
42
  function configureModulesDirectory(modulesDir) {
43
- readDiscoverModulesState().configuredModulesDir = modulesDir;
43
+ const state = readDiscoverModulesState();
44
+ if (state.configuredModulesDir !== modulesDir) {
45
+ state.appModules.length = 0;
46
+ state.modulesReady = undefined;
47
+ }
48
+ state.configuredModulesDir = modulesDir;
44
49
  }
45
50
  function resolveModulesDirectory(options) {
46
51
  const state = readDiscoverModulesState();
@@ -91,17 +96,19 @@ function resetDiscoverModulesForTests() {
91
96
  state.modulesReady = undefined;
92
97
  }
93
98
  // ../../src/bootstrap/providers/auth.ts
99
+ import { BasicAuthGuard } from "@getstrata/core/auth/basicAuthGuard";
94
100
  import {
95
101
  AuthManager,
96
102
  CompositeGuard,
97
103
  DatabaseTokenGuard,
98
104
  GuestGuard
99
105
  } from "@getstrata/core/auth/guard";
106
+ import { JwtGuard } from "@getstrata/core/auth/jwtGuard";
100
107
  import { SessionGuard } from "@getstrata/core/auth/sessionGuard";
101
108
 
102
109
  // ../../src/config/auth.ts
103
110
  var authConfig = {
104
- allowDevHeaders: (process.env.AUTH_DEV_HEADERS ?? "true") !== "false",
111
+ allowDevHeaders: process.env.AUTH_DEV_HEADERS === "true",
105
112
  tokenDefaultAbilities: ["*"]
106
113
  };
107
114
 
@@ -136,11 +143,22 @@ var authProvider = {
136
143
  name: "core.auth",
137
144
  register({ container, config }) {
138
145
  config.set("auth.allowDevHeaders", authConfig.allowDevHeaders);
139
- const guards = [new DatabaseTokenGuard(container), new SessionGuard(container)];
146
+ const apiGuard = new DatabaseTokenGuard(container);
147
+ const sessionGuard = new SessionGuard(container);
148
+ const jwtGuard = new JwtGuard;
149
+ const basicGuard = new BasicAuthGuard(container);
150
+ const guards = [apiGuard, jwtGuard, basicGuard, sessionGuard];
140
151
  if (authConfig.allowDevHeaders) {
141
152
  guards.push(new GuestGuard);
142
153
  }
143
- container.set(CORE_AUTH_TOKEN, new AuthManager(new CompositeGuard(guards)));
154
+ const auth = new AuthManager(new CompositeGuard(guards));
155
+ auth.registerGuard("api", apiGuard);
156
+ auth.registerGuard("access_token", apiGuard);
157
+ auth.registerGuard("jwt", jwtGuard);
158
+ auth.registerGuard("basic", basicGuard);
159
+ auth.registerGuard("web", sessionGuard);
160
+ auth.registerGuard("session", sessionGuard);
161
+ container.set(CORE_AUTH_TOKEN, auth);
144
162
  }
145
163
  };
146
164
  var auth_default = authProvider;
@@ -201,8 +219,12 @@ var queueConfig = {
201
219
  };
202
220
  // ../../src/bootstrap/env.ts
203
221
  import { defineEnvSchema } from "@getstrata/core/config/envSchema";
222
+ import { DEFAULT_SPA_PREFIX, FRONTEND_MODE_PATTERN } from "@getstrata/core/runtime/frontendMode";
204
223
  var appEnvSchema = defineEnvSchema({
205
- DATABASE_URL: { required: true, pattern: /^postgres(ql)?:\/\// },
224
+ DATABASE_URL: {
225
+ required: true,
226
+ pattern: /^(postgres(ql)?|mysql|sqlite):\/\//i
227
+ },
206
228
  PORT: {
207
229
  integer: true,
208
230
  minimum: 1,
@@ -230,9 +252,21 @@ var appEnvSchema = defineEnvSchema({
230
252
  pattern: /^(sync|async|redis)$/
231
253
  },
232
254
  AUTH_DEV_HEADERS: {
233
- default: "true",
255
+ default: "false",
234
256
  pattern: /^(true|false|0|1)$/
235
257
  },
258
+ DB_CONNECTION: {
259
+ default: "",
260
+ pattern: /^(pgsql|postgres|postgresql|mysql|mariadb|sqlite)?$/i
261
+ },
262
+ AUTH_DEFAULT_GUARD: {
263
+ default: "web"
264
+ },
265
+ JWT_TTL_SECONDS: {
266
+ integer: true,
267
+ minimum: 60,
268
+ default: "3600"
269
+ },
236
270
  APP_ENV: {
237
271
  default: "local"
238
272
  },
@@ -242,6 +276,13 @@ var appEnvSchema = defineEnvSchema({
242
276
  APP_URL: {
243
277
  default: "http://localhost:3000"
244
278
  },
279
+ FRONTEND_MODE: {
280
+ default: "api",
281
+ pattern: FRONTEND_MODE_PATTERN
282
+ },
283
+ SPA_PREFIX: {
284
+ default: DEFAULT_SPA_PREFIX
285
+ },
245
286
  API_PREFIX: {
246
287
  default: "/api/v1"
247
288
  },
@@ -480,7 +521,6 @@ var storageProvider = {
480
521
  var storage_default = storageProvider;
481
522
 
482
523
  // ../../src/bootstrap/providers/view.ts
483
- import { resolveMembershipLookup } from "@getstrata/core/auth/membershipContext";
484
524
  import { currentRequestMeta } from "@getstrata/core/http/requestMetaContext";
485
525
  import { appDisplayName } from "@getstrata/core/runtime/appKeyPrefix";
486
526
  import { isViewsEnabled } from "@getstrata/core/runtime/frontendMode";
@@ -492,148 +532,6 @@ import {
492
532
  errorTemplateName,
493
533
  resolveWebLayoutData
494
534
  } from "@getstrata/core/view";
495
-
496
- // ../../src/modules/organization/repository.ts
497
- import { BaseRepository } from "@getstrata/core/database/baseRepository";
498
- import { NotFoundError } from "@getstrata/core/errors/http";
499
- import { currentTenantId } from "@getstrata/core/tenant/tenantContext";
500
-
501
- // ../../src/modules/organization/table.ts
502
- import { defineTable } from "@getstrata/core/database/table";
503
-
504
- // ../../src/domain/workhub.ts
505
- var ORGANIZATION_TABLE = "organization";
506
-
507
- // ../../src/modules/organization/table.ts
508
- var organizationTable = defineTable({
509
- name: ORGANIZATION_TABLE,
510
- primaryKey: "id",
511
- columns: ["id", "tenant_id", "name", "slug", "created_at", "updated_at", "deleted_at"],
512
- softDeletes: true,
513
- defaultOrderBy: { column: "id", direction: "ASC" }
514
- });
515
-
516
- // ../../src/modules/organization/repository.ts
517
- class OrganizationRepository extends BaseRepository {
518
- constructor() {
519
- super(organizationTable);
520
- }
521
- async findBySlug(slug) {
522
- return await this.firstOrNull({ slug });
523
- }
524
- async listForTenant(options) {
525
- return await this.findAll({
526
- limit: options.limit,
527
- offset: options.offset,
528
- where: { tenant_id: options.tenantId ?? currentTenantId() }
529
- });
530
- }
531
- async countForTenant(tenantId = currentTenantId()) {
532
- return await this.countWhere({ tenant_id: tenantId });
533
- }
534
- async findForTenantOrThrow(id, tenantId = currentTenantId()) {
535
- const organization = await this.findById(id);
536
- if (!organization || organization.tenant_id !== tenantId) {
537
- throw new NotFoundError(`SCIM group ${id} not found.`);
538
- }
539
- return organization;
540
- }
541
- }
542
- var repository_default = OrganizationRepository;
543
-
544
- // ../../src/modules/user/repository.ts
545
- import {
546
- emailLookupForQuery,
547
- protectEmail,
548
- revealEmail
549
- } from "@getstrata/core/crypto/fieldEncryption";
550
- import { revealMfaSecret } from "@getstrata/core/crypto/mfaSecret";
551
- import { BaseRepository as BaseRepository2 } from "@getstrata/core/database/baseRepository";
552
- import { currentTenantId as currentTenantId2 } from "@getstrata/core/tenant/tenantContext";
553
-
554
- // ../../src/modules/user/table.ts
555
- import { defineTable as defineTable2 } from "@getstrata/core/database/table";
556
- var userTable = defineTable2({
557
- name: "users",
558
- primaryKey: "id",
559
- columns: [
560
- "id",
561
- "name",
562
- "email",
563
- "email_lookup",
564
- "role",
565
- "tenant_id",
566
- "password_hash",
567
- "email_verified_at",
568
- "mfa_secret",
569
- "mfa_enabled",
570
- "mfa_recovery_codes",
571
- "profile_photo_path",
572
- "session_valid_after",
573
- "current_organization_id",
574
- "created_at",
575
- "updated_at"
576
- ],
577
- defaultOrderBy: { column: "id", direction: "ASC" }
578
- });
579
-
580
- // ../../src/modules/user/repository.ts
581
- class UserRepository extends BaseRepository2 {
582
- constructor() {
583
- super(userTable);
584
- }
585
- decode(record) {
586
- return {
587
- ...record,
588
- email: revealEmail(record.email),
589
- mfa_secret: revealMfaSecret(record.mfa_secret)
590
- };
591
- }
592
- async findById(id) {
593
- const record = await super.findById(id);
594
- return record ? this.decode(record) : null;
595
- }
596
- async findAll(options = {}) {
597
- const records = await super.findAll(options);
598
- return records.map((record) => this.decode(record));
599
- }
600
- async create(values) {
601
- const email = values.email;
602
- if (!email) {
603
- throw new Error("Email is required.");
604
- }
605
- const protectedEmail = protectEmail(email);
606
- const record = await super.create({
607
- ...values,
608
- tenant_id: values.tenant_id ?? currentTenantId2(),
609
- email: protectedEmail.storedEmail,
610
- email_lookup: protectedEmail.emailLookup,
611
- password_hash: values.password_hash ?? ""
612
- });
613
- return this.decode(record);
614
- }
615
- async updateByIdOrThrow(id, values, errorFactory) {
616
- const changes = { ...values };
617
- if (values.email !== undefined) {
618
- const protectedEmail = protectEmail(values.email);
619
- changes.email = protectedEmail.storedEmail;
620
- changes.email_lookup = protectedEmail.emailLookup;
621
- }
622
- const record = await super.updateByIdOrThrow(id, changes, errorFactory);
623
- return this.decode(record);
624
- }
625
- async findByEmail(email) {
626
- const records = await this.findWhere({ email_lookup: emailLookupForQuery(email) }, { limit: 1 });
627
- const record = records[0];
628
- return record ? this.decode(record) : null;
629
- }
630
- async countForTenant(tenantId = currentTenantId2()) {
631
- return await this.countWhere({ tenant_id: tenantId });
632
- }
633
- }
634
- var repository_default2 = UserRepository;
635
-
636
- // ../../src/bootstrap/providers/view.ts
637
535
  var CORE_VIEW_TOKEN = "core.view";
638
536
  var VIEW_DIRECTORY_CONFIG_KEY = "view.directory";
639
537
  var viewProvider = {
@@ -647,23 +545,11 @@ var viewProvider = {
647
545
  const engine = new EtaViewEngine(viewsDirectory, (request) => resolveWebLayoutData(container, request ?? currentRequestMeta().request));
648
546
  container.set(CORE_VIEW_TOKEN, engine);
649
547
  configureWebLayoutData({
650
- extra: async (user) => {
651
- const appName = appDisplayName();
652
- if (!user || typeof user.id !== "number") {
653
- return { appName, currentOrganization: null, organizations: [] };
654
- }
655
- try {
656
- const record = await new repository_default2().findByIdOrThrow(user.id);
657
- const memberships = await resolveMembershipLookup().listForUser(record.id);
658
- const organizationsRepo = new repository_default;
659
- const organizations = (await Promise.all(memberships.map((membership) => organizationsRepo.findById(membership.organization_id)))).filter((organization) => Boolean(organization && !organization.deleted_at));
660
- const currentId = record.current_organization_id ?? null;
661
- const currentOrganization = organizations.find((organization) => organization.id === currentId) ?? organizations[0] ?? null;
662
- return { appName, currentOrganization, organizations };
663
- } catch {
664
- return { appName, currentOrganization: null, organizations: [] };
665
- }
666
- }
548
+ extra: async () => ({
549
+ appName: appDisplayName(),
550
+ currentOrganization: null,
551
+ organizations: []
552
+ })
667
553
  });
668
554
  configureWebErrorView({
669
555
  render: async (input) => engine.render(errorTemplateName(input.status), {