@getstrata/bootstrap 0.2.66 → 0.2.68
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.
- package/CHANGELOG.md +11 -0
- package/dist/bootstrap/createWebRoutes.d.ts +7 -3
- package/dist/bootstrap/dogfoodApp.d.ts +7 -0
- package/dist/bootstrap/public-api.d.ts +1 -0
- package/dist/bootstrap/web/session.d.ts +18 -3
- package/dist/entries/buildModuleRoutes.js +6 -1
- package/dist/entries/buildWebModuleRoutes.js +6 -1
- package/dist/entries/cache/modelCacheTags.js +6 -1
- package/dist/entries/context.js +11 -161
- package/dist/entries/createRoutes.js +31 -856
- package/dist/entries/createWebRoutes.js +11 -5
- package/dist/entries/dependencies.js +11 -161
- package/dist/entries/discoverModules.js +6 -1
- package/dist/entries/listeners/invalidateCacheOnModelWrite.js +6 -1
- package/dist/entries/providers/view.js +5 -160
- package/dist/entries/providers.js +11 -161
- package/dist/entries/web/session.js +24 -10
- package/dist/index.js +40 -175
- package/package.json +1 -1
- package/dist/bootstrap/scimRoutes.d.ts +0 -24
|
@@ -349,7 +349,12 @@ function readDiscoverModulesState() {
|
|
|
349
349
|
return state;
|
|
350
350
|
}
|
|
351
351
|
function configureModulesDirectory(modulesDir) {
|
|
352
|
-
readDiscoverModulesState()
|
|
352
|
+
const state = readDiscoverModulesState();
|
|
353
|
+
if (state.configuredModulesDir !== modulesDir) {
|
|
354
|
+
state.appModules.length = 0;
|
|
355
|
+
state.modulesReady = undefined;
|
|
356
|
+
}
|
|
357
|
+
state.configuredModulesDir = modulesDir;
|
|
353
358
|
}
|
|
354
359
|
function resolveModulesDirectory(options) {
|
|
355
360
|
const state = readDiscoverModulesState();
|
|
@@ -506,9 +511,10 @@ function buildWebModuleRoutes(dependencies, options = {}) {
|
|
|
506
511
|
function registerRoute(method, path, middleware) {
|
|
507
512
|
routeRegistry.register({ method, path, middleware });
|
|
508
513
|
}
|
|
509
|
-
function createWebRoutes(dependencies) {
|
|
514
|
+
function createWebRoutes(dependencies, options = {}) {
|
|
510
515
|
const wrappedRoutes = buildWebModuleRoutes(dependencies, {
|
|
511
|
-
clearRegistry: false
|
|
516
|
+
clearRegistry: false,
|
|
517
|
+
modules: options.modules
|
|
512
518
|
});
|
|
513
519
|
registerRoute("GET", "/", ["global", "web"]);
|
|
514
520
|
wrappedRoutes["/assets/*"] = async (request) => {
|
|
@@ -524,12 +530,12 @@ function createWebRoutes(dependencies) {
|
|
|
524
530
|
registerRoute("GET", "/assets/*", ["global", "web"]);
|
|
525
531
|
return wrappedRoutes;
|
|
526
532
|
}
|
|
527
|
-
function mergeWebRoutes(dependencies, routes) {
|
|
533
|
+
function mergeWebRoutes(dependencies, routes, options = {}) {
|
|
528
534
|
if (!isViewsEnabled2()) {
|
|
529
535
|
return routes;
|
|
530
536
|
}
|
|
531
537
|
return {
|
|
532
|
-
...createWebRoutes(dependencies),
|
|
538
|
+
...createWebRoutes(dependencies, options),
|
|
533
539
|
...routes
|
|
534
540
|
};
|
|
535
541
|
}
|
|
@@ -40,7 +40,12 @@ function readDiscoverModulesState() {
|
|
|
40
40
|
return state;
|
|
41
41
|
}
|
|
42
42
|
function configureModulesDirectory(modulesDir) {
|
|
43
|
-
readDiscoverModulesState()
|
|
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();
|
|
@@ -480,7 +485,6 @@ var storageProvider = {
|
|
|
480
485
|
var storage_default = storageProvider;
|
|
481
486
|
|
|
482
487
|
// ../../src/bootstrap/providers/view.ts
|
|
483
|
-
import { resolveMembershipLookup } from "@getstrata/core/auth/membershipContext";
|
|
484
488
|
import { currentRequestMeta } from "@getstrata/core/http/requestMetaContext";
|
|
485
489
|
import { appDisplayName } from "@getstrata/core/runtime/appKeyPrefix";
|
|
486
490
|
import { isViewsEnabled } from "@getstrata/core/runtime/frontendMode";
|
|
@@ -492,148 +496,6 @@ import {
|
|
|
492
496
|
errorTemplateName,
|
|
493
497
|
resolveWebLayoutData
|
|
494
498
|
} 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
499
|
var CORE_VIEW_TOKEN = "core.view";
|
|
638
500
|
var VIEW_DIRECTORY_CONFIG_KEY = "view.directory";
|
|
639
501
|
var viewProvider = {
|
|
@@ -647,23 +509,11 @@ var viewProvider = {
|
|
|
647
509
|
const engine = new EtaViewEngine(viewsDirectory, (request) => resolveWebLayoutData(container, request ?? currentRequestMeta().request));
|
|
648
510
|
container.set(CORE_VIEW_TOKEN, engine);
|
|
649
511
|
configureWebLayoutData({
|
|
650
|
-
extra: async (
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
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
|
-
}
|
|
512
|
+
extra: async () => ({
|
|
513
|
+
appName: appDisplayName(),
|
|
514
|
+
currentOrganization: null,
|
|
515
|
+
organizations: []
|
|
516
|
+
})
|
|
667
517
|
});
|
|
668
518
|
configureWebErrorView({
|
|
669
519
|
render: async (input) => engine.render(errorTemplateName(input.status), {
|
|
@@ -16,7 +16,12 @@ function readDiscoverModulesState() {
|
|
|
16
16
|
return state;
|
|
17
17
|
}
|
|
18
18
|
function configureModulesDirectory(modulesDir) {
|
|
19
|
-
readDiscoverModulesState()
|
|
19
|
+
const state = readDiscoverModulesState();
|
|
20
|
+
if (state.configuredModulesDir !== modulesDir) {
|
|
21
|
+
state.appModules.length = 0;
|
|
22
|
+
state.modulesReady = undefined;
|
|
23
|
+
}
|
|
24
|
+
state.configuredModulesDir = modulesDir;
|
|
20
25
|
}
|
|
21
26
|
function resolveModulesDirectory(options) {
|
|
22
27
|
const state = readDiscoverModulesState();
|
|
@@ -34,7 +34,12 @@ function readDiscoverModulesState() {
|
|
|
34
34
|
return state;
|
|
35
35
|
}
|
|
36
36
|
function configureModulesDirectory(modulesDir) {
|
|
37
|
-
readDiscoverModulesState()
|
|
37
|
+
const state = readDiscoverModulesState();
|
|
38
|
+
if (state.configuredModulesDir !== modulesDir) {
|
|
39
|
+
state.appModules.length = 0;
|
|
40
|
+
state.modulesReady = undefined;
|
|
41
|
+
}
|
|
42
|
+
state.configuredModulesDir = modulesDir;
|
|
38
43
|
}
|
|
39
44
|
function resolveModulesDirectory(options) {
|
|
40
45
|
const state = readDiscoverModulesState();
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
var __jsonParse = (a) => JSON.parse(a);
|
|
3
3
|
|
|
4
4
|
// ../../src/bootstrap/providers/view.ts
|
|
5
|
-
import { resolveMembershipLookup } from "@getstrata/core/auth/membershipContext";
|
|
6
5
|
import { currentRequestMeta } from "@getstrata/core/http/requestMetaContext";
|
|
7
6
|
import { appDisplayName } from "@getstrata/core/runtime/appKeyPrefix";
|
|
8
7
|
import { isViewsEnabled } from "@getstrata/core/runtime/frontendMode";
|
|
@@ -14,148 +13,6 @@ import {
|
|
|
14
13
|
errorTemplateName,
|
|
15
14
|
resolveWebLayoutData
|
|
16
15
|
} from "@getstrata/core/view";
|
|
17
|
-
|
|
18
|
-
// ../../src/modules/organization/repository.ts
|
|
19
|
-
import { BaseRepository } from "@getstrata/core/database/baseRepository";
|
|
20
|
-
import { NotFoundError } from "@getstrata/core/errors/http";
|
|
21
|
-
import { currentTenantId } from "@getstrata/core/tenant/tenantContext";
|
|
22
|
-
|
|
23
|
-
// ../../src/modules/organization/table.ts
|
|
24
|
-
import { defineTable } from "@getstrata/core/database/table";
|
|
25
|
-
|
|
26
|
-
// ../../src/domain/workhub.ts
|
|
27
|
-
var ORGANIZATION_TABLE = "organization";
|
|
28
|
-
|
|
29
|
-
// ../../src/modules/organization/table.ts
|
|
30
|
-
var organizationTable = defineTable({
|
|
31
|
-
name: ORGANIZATION_TABLE,
|
|
32
|
-
primaryKey: "id",
|
|
33
|
-
columns: ["id", "tenant_id", "name", "slug", "created_at", "updated_at", "deleted_at"],
|
|
34
|
-
softDeletes: true,
|
|
35
|
-
defaultOrderBy: { column: "id", direction: "ASC" }
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
// ../../src/modules/organization/repository.ts
|
|
39
|
-
class OrganizationRepository extends BaseRepository {
|
|
40
|
-
constructor() {
|
|
41
|
-
super(organizationTable);
|
|
42
|
-
}
|
|
43
|
-
async findBySlug(slug) {
|
|
44
|
-
return await this.firstOrNull({ slug });
|
|
45
|
-
}
|
|
46
|
-
async listForTenant(options) {
|
|
47
|
-
return await this.findAll({
|
|
48
|
-
limit: options.limit,
|
|
49
|
-
offset: options.offset,
|
|
50
|
-
where: { tenant_id: options.tenantId ?? currentTenantId() }
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
async countForTenant(tenantId = currentTenantId()) {
|
|
54
|
-
return await this.countWhere({ tenant_id: tenantId });
|
|
55
|
-
}
|
|
56
|
-
async findForTenantOrThrow(id, tenantId = currentTenantId()) {
|
|
57
|
-
const organization = await this.findById(id);
|
|
58
|
-
if (!organization || organization.tenant_id !== tenantId) {
|
|
59
|
-
throw new NotFoundError(`SCIM group ${id} not found.`);
|
|
60
|
-
}
|
|
61
|
-
return organization;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
var repository_default = OrganizationRepository;
|
|
65
|
-
|
|
66
|
-
// ../../src/modules/user/repository.ts
|
|
67
|
-
import {
|
|
68
|
-
emailLookupForQuery,
|
|
69
|
-
protectEmail,
|
|
70
|
-
revealEmail
|
|
71
|
-
} from "@getstrata/core/crypto/fieldEncryption";
|
|
72
|
-
import { revealMfaSecret } from "@getstrata/core/crypto/mfaSecret";
|
|
73
|
-
import { BaseRepository as BaseRepository2 } from "@getstrata/core/database/baseRepository";
|
|
74
|
-
import { currentTenantId as currentTenantId2 } from "@getstrata/core/tenant/tenantContext";
|
|
75
|
-
|
|
76
|
-
// ../../src/modules/user/table.ts
|
|
77
|
-
import { defineTable as defineTable2 } from "@getstrata/core/database/table";
|
|
78
|
-
var userTable = defineTable2({
|
|
79
|
-
name: "users",
|
|
80
|
-
primaryKey: "id",
|
|
81
|
-
columns: [
|
|
82
|
-
"id",
|
|
83
|
-
"name",
|
|
84
|
-
"email",
|
|
85
|
-
"email_lookup",
|
|
86
|
-
"role",
|
|
87
|
-
"tenant_id",
|
|
88
|
-
"password_hash",
|
|
89
|
-
"email_verified_at",
|
|
90
|
-
"mfa_secret",
|
|
91
|
-
"mfa_enabled",
|
|
92
|
-
"mfa_recovery_codes",
|
|
93
|
-
"profile_photo_path",
|
|
94
|
-
"session_valid_after",
|
|
95
|
-
"current_organization_id",
|
|
96
|
-
"created_at",
|
|
97
|
-
"updated_at"
|
|
98
|
-
],
|
|
99
|
-
defaultOrderBy: { column: "id", direction: "ASC" }
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
// ../../src/modules/user/repository.ts
|
|
103
|
-
class UserRepository extends BaseRepository2 {
|
|
104
|
-
constructor() {
|
|
105
|
-
super(userTable);
|
|
106
|
-
}
|
|
107
|
-
decode(record) {
|
|
108
|
-
return {
|
|
109
|
-
...record,
|
|
110
|
-
email: revealEmail(record.email),
|
|
111
|
-
mfa_secret: revealMfaSecret(record.mfa_secret)
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
async findById(id) {
|
|
115
|
-
const record = await super.findById(id);
|
|
116
|
-
return record ? this.decode(record) : null;
|
|
117
|
-
}
|
|
118
|
-
async findAll(options = {}) {
|
|
119
|
-
const records = await super.findAll(options);
|
|
120
|
-
return records.map((record) => this.decode(record));
|
|
121
|
-
}
|
|
122
|
-
async create(values) {
|
|
123
|
-
const email = values.email;
|
|
124
|
-
if (!email) {
|
|
125
|
-
throw new Error("Email is required.");
|
|
126
|
-
}
|
|
127
|
-
const protectedEmail = protectEmail(email);
|
|
128
|
-
const record = await super.create({
|
|
129
|
-
...values,
|
|
130
|
-
tenant_id: values.tenant_id ?? currentTenantId2(),
|
|
131
|
-
email: protectedEmail.storedEmail,
|
|
132
|
-
email_lookup: protectedEmail.emailLookup,
|
|
133
|
-
password_hash: values.password_hash ?? ""
|
|
134
|
-
});
|
|
135
|
-
return this.decode(record);
|
|
136
|
-
}
|
|
137
|
-
async updateByIdOrThrow(id, values, errorFactory) {
|
|
138
|
-
const changes = { ...values };
|
|
139
|
-
if (values.email !== undefined) {
|
|
140
|
-
const protectedEmail = protectEmail(values.email);
|
|
141
|
-
changes.email = protectedEmail.storedEmail;
|
|
142
|
-
changes.email_lookup = protectedEmail.emailLookup;
|
|
143
|
-
}
|
|
144
|
-
const record = await super.updateByIdOrThrow(id, changes, errorFactory);
|
|
145
|
-
return this.decode(record);
|
|
146
|
-
}
|
|
147
|
-
async findByEmail(email) {
|
|
148
|
-
const records = await this.findWhere({ email_lookup: emailLookupForQuery(email) }, { limit: 1 });
|
|
149
|
-
const record = records[0];
|
|
150
|
-
return record ? this.decode(record) : null;
|
|
151
|
-
}
|
|
152
|
-
async countForTenant(tenantId = currentTenantId2()) {
|
|
153
|
-
return await this.countWhere({ tenant_id: tenantId });
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
var repository_default2 = UserRepository;
|
|
157
|
-
|
|
158
|
-
// ../../src/bootstrap/providers/view.ts
|
|
159
16
|
var CORE_VIEW_TOKEN = "core.view";
|
|
160
17
|
var VIEW_DIRECTORY_CONFIG_KEY = "view.directory";
|
|
161
18
|
var viewProvider = {
|
|
@@ -169,23 +26,11 @@ var viewProvider = {
|
|
|
169
26
|
const engine = new EtaViewEngine(viewsDirectory, (request) => resolveWebLayoutData(container, request ?? currentRequestMeta().request));
|
|
170
27
|
container.set(CORE_VIEW_TOKEN, engine);
|
|
171
28
|
configureWebLayoutData({
|
|
172
|
-
extra: async (
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
try {
|
|
178
|
-
const record = await new repository_default2().findByIdOrThrow(user.id);
|
|
179
|
-
const memberships = await resolveMembershipLookup().listForUser(record.id);
|
|
180
|
-
const organizationsRepo = new repository_default;
|
|
181
|
-
const organizations = (await Promise.all(memberships.map((membership) => organizationsRepo.findById(membership.organization_id)))).filter((organization) => Boolean(organization && !organization.deleted_at));
|
|
182
|
-
const currentId = record.current_organization_id ?? null;
|
|
183
|
-
const currentOrganization = organizations.find((organization) => organization.id === currentId) ?? organizations[0] ?? null;
|
|
184
|
-
return { appName, currentOrganization, organizations };
|
|
185
|
-
} catch {
|
|
186
|
-
return { appName, currentOrganization: null, organizations: [] };
|
|
187
|
-
}
|
|
188
|
-
}
|
|
29
|
+
extra: async () => ({
|
|
30
|
+
appName: appDisplayName(),
|
|
31
|
+
currentOrganization: null,
|
|
32
|
+
organizations: []
|
|
33
|
+
})
|
|
189
34
|
});
|
|
190
35
|
configureWebErrorView({
|
|
191
36
|
render: async (input) => engine.render(errorTemplateName(input.status), {
|
|
@@ -306,7 +306,12 @@ function readDiscoverModulesState() {
|
|
|
306
306
|
return state;
|
|
307
307
|
}
|
|
308
308
|
function configureModulesDirectory(modulesDir) {
|
|
309
|
-
readDiscoverModulesState()
|
|
309
|
+
const state = readDiscoverModulesState();
|
|
310
|
+
if (state.configuredModulesDir !== modulesDir) {
|
|
311
|
+
state.appModules.length = 0;
|
|
312
|
+
state.modulesReady = undefined;
|
|
313
|
+
}
|
|
314
|
+
state.configuredModulesDir = modulesDir;
|
|
310
315
|
}
|
|
311
316
|
function resolveModulesDirectory(options) {
|
|
312
317
|
const state = readDiscoverModulesState();
|
|
@@ -470,7 +475,6 @@ var storageProvider = {
|
|
|
470
475
|
var storage_default = storageProvider;
|
|
471
476
|
|
|
472
477
|
// ../../src/bootstrap/providers/view.ts
|
|
473
|
-
import { resolveMembershipLookup } from "@getstrata/core/auth/membershipContext";
|
|
474
478
|
import { currentRequestMeta } from "@getstrata/core/http/requestMetaContext";
|
|
475
479
|
import { appDisplayName } from "@getstrata/core/runtime/appKeyPrefix";
|
|
476
480
|
import { isViewsEnabled } from "@getstrata/core/runtime/frontendMode";
|
|
@@ -482,148 +486,6 @@ import {
|
|
|
482
486
|
errorTemplateName,
|
|
483
487
|
resolveWebLayoutData
|
|
484
488
|
} from "@getstrata/core/view";
|
|
485
|
-
|
|
486
|
-
// ../../src/modules/organization/repository.ts
|
|
487
|
-
import { BaseRepository } from "@getstrata/core/database/baseRepository";
|
|
488
|
-
import { NotFoundError } from "@getstrata/core/errors/http";
|
|
489
|
-
import { currentTenantId } from "@getstrata/core/tenant/tenantContext";
|
|
490
|
-
|
|
491
|
-
// ../../src/modules/organization/table.ts
|
|
492
|
-
import { defineTable } from "@getstrata/core/database/table";
|
|
493
|
-
|
|
494
|
-
// ../../src/domain/workhub.ts
|
|
495
|
-
var ORGANIZATION_TABLE = "organization";
|
|
496
|
-
|
|
497
|
-
// ../../src/modules/organization/table.ts
|
|
498
|
-
var organizationTable = defineTable({
|
|
499
|
-
name: ORGANIZATION_TABLE,
|
|
500
|
-
primaryKey: "id",
|
|
501
|
-
columns: ["id", "tenant_id", "name", "slug", "created_at", "updated_at", "deleted_at"],
|
|
502
|
-
softDeletes: true,
|
|
503
|
-
defaultOrderBy: { column: "id", direction: "ASC" }
|
|
504
|
-
});
|
|
505
|
-
|
|
506
|
-
// ../../src/modules/organization/repository.ts
|
|
507
|
-
class OrganizationRepository extends BaseRepository {
|
|
508
|
-
constructor() {
|
|
509
|
-
super(organizationTable);
|
|
510
|
-
}
|
|
511
|
-
async findBySlug(slug) {
|
|
512
|
-
return await this.firstOrNull({ slug });
|
|
513
|
-
}
|
|
514
|
-
async listForTenant(options) {
|
|
515
|
-
return await this.findAll({
|
|
516
|
-
limit: options.limit,
|
|
517
|
-
offset: options.offset,
|
|
518
|
-
where: { tenant_id: options.tenantId ?? currentTenantId() }
|
|
519
|
-
});
|
|
520
|
-
}
|
|
521
|
-
async countForTenant(tenantId = currentTenantId()) {
|
|
522
|
-
return await this.countWhere({ tenant_id: tenantId });
|
|
523
|
-
}
|
|
524
|
-
async findForTenantOrThrow(id, tenantId = currentTenantId()) {
|
|
525
|
-
const organization = await this.findById(id);
|
|
526
|
-
if (!organization || organization.tenant_id !== tenantId) {
|
|
527
|
-
throw new NotFoundError(`SCIM group ${id} not found.`);
|
|
528
|
-
}
|
|
529
|
-
return organization;
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
var repository_default = OrganizationRepository;
|
|
533
|
-
|
|
534
|
-
// ../../src/modules/user/repository.ts
|
|
535
|
-
import {
|
|
536
|
-
emailLookupForQuery,
|
|
537
|
-
protectEmail,
|
|
538
|
-
revealEmail
|
|
539
|
-
} from "@getstrata/core/crypto/fieldEncryption";
|
|
540
|
-
import { revealMfaSecret } from "@getstrata/core/crypto/mfaSecret";
|
|
541
|
-
import { BaseRepository as BaseRepository2 } from "@getstrata/core/database/baseRepository";
|
|
542
|
-
import { currentTenantId as currentTenantId2 } from "@getstrata/core/tenant/tenantContext";
|
|
543
|
-
|
|
544
|
-
// ../../src/modules/user/table.ts
|
|
545
|
-
import { defineTable as defineTable2 } from "@getstrata/core/database/table";
|
|
546
|
-
var userTable = defineTable2({
|
|
547
|
-
name: "users",
|
|
548
|
-
primaryKey: "id",
|
|
549
|
-
columns: [
|
|
550
|
-
"id",
|
|
551
|
-
"name",
|
|
552
|
-
"email",
|
|
553
|
-
"email_lookup",
|
|
554
|
-
"role",
|
|
555
|
-
"tenant_id",
|
|
556
|
-
"password_hash",
|
|
557
|
-
"email_verified_at",
|
|
558
|
-
"mfa_secret",
|
|
559
|
-
"mfa_enabled",
|
|
560
|
-
"mfa_recovery_codes",
|
|
561
|
-
"profile_photo_path",
|
|
562
|
-
"session_valid_after",
|
|
563
|
-
"current_organization_id",
|
|
564
|
-
"created_at",
|
|
565
|
-
"updated_at"
|
|
566
|
-
],
|
|
567
|
-
defaultOrderBy: { column: "id", direction: "ASC" }
|
|
568
|
-
});
|
|
569
|
-
|
|
570
|
-
// ../../src/modules/user/repository.ts
|
|
571
|
-
class UserRepository extends BaseRepository2 {
|
|
572
|
-
constructor() {
|
|
573
|
-
super(userTable);
|
|
574
|
-
}
|
|
575
|
-
decode(record) {
|
|
576
|
-
return {
|
|
577
|
-
...record,
|
|
578
|
-
email: revealEmail(record.email),
|
|
579
|
-
mfa_secret: revealMfaSecret(record.mfa_secret)
|
|
580
|
-
};
|
|
581
|
-
}
|
|
582
|
-
async findById(id) {
|
|
583
|
-
const record = await super.findById(id);
|
|
584
|
-
return record ? this.decode(record) : null;
|
|
585
|
-
}
|
|
586
|
-
async findAll(options = {}) {
|
|
587
|
-
const records = await super.findAll(options);
|
|
588
|
-
return records.map((record) => this.decode(record));
|
|
589
|
-
}
|
|
590
|
-
async create(values) {
|
|
591
|
-
const email = values.email;
|
|
592
|
-
if (!email) {
|
|
593
|
-
throw new Error("Email is required.");
|
|
594
|
-
}
|
|
595
|
-
const protectedEmail = protectEmail(email);
|
|
596
|
-
const record = await super.create({
|
|
597
|
-
...values,
|
|
598
|
-
tenant_id: values.tenant_id ?? currentTenantId2(),
|
|
599
|
-
email: protectedEmail.storedEmail,
|
|
600
|
-
email_lookup: protectedEmail.emailLookup,
|
|
601
|
-
password_hash: values.password_hash ?? ""
|
|
602
|
-
});
|
|
603
|
-
return this.decode(record);
|
|
604
|
-
}
|
|
605
|
-
async updateByIdOrThrow(id, values, errorFactory) {
|
|
606
|
-
const changes = { ...values };
|
|
607
|
-
if (values.email !== undefined) {
|
|
608
|
-
const protectedEmail = protectEmail(values.email);
|
|
609
|
-
changes.email = protectedEmail.storedEmail;
|
|
610
|
-
changes.email_lookup = protectedEmail.emailLookup;
|
|
611
|
-
}
|
|
612
|
-
const record = await super.updateByIdOrThrow(id, changes, errorFactory);
|
|
613
|
-
return this.decode(record);
|
|
614
|
-
}
|
|
615
|
-
async findByEmail(email) {
|
|
616
|
-
const records = await this.findWhere({ email_lookup: emailLookupForQuery(email) }, { limit: 1 });
|
|
617
|
-
const record = records[0];
|
|
618
|
-
return record ? this.decode(record) : null;
|
|
619
|
-
}
|
|
620
|
-
async countForTenant(tenantId = currentTenantId2()) {
|
|
621
|
-
return await this.countWhere({ tenant_id: tenantId });
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
var repository_default2 = UserRepository;
|
|
625
|
-
|
|
626
|
-
// ../../src/bootstrap/providers/view.ts
|
|
627
489
|
var CORE_VIEW_TOKEN = "core.view";
|
|
628
490
|
var VIEW_DIRECTORY_CONFIG_KEY = "view.directory";
|
|
629
491
|
var viewProvider = {
|
|
@@ -637,23 +499,11 @@ var viewProvider = {
|
|
|
637
499
|
const engine = new EtaViewEngine(viewsDirectory, (request) => resolveWebLayoutData(container, request ?? currentRequestMeta().request));
|
|
638
500
|
container.set(CORE_VIEW_TOKEN, engine);
|
|
639
501
|
configureWebLayoutData({
|
|
640
|
-
extra: async (
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
try {
|
|
646
|
-
const record = await new repository_default2().findByIdOrThrow(user.id);
|
|
647
|
-
const memberships = await resolveMembershipLookup().listForUser(record.id);
|
|
648
|
-
const organizationsRepo = new repository_default;
|
|
649
|
-
const organizations = (await Promise.all(memberships.map((membership) => organizationsRepo.findById(membership.organization_id)))).filter((organization) => Boolean(organization && !organization.deleted_at));
|
|
650
|
-
const currentId = record.current_organization_id ?? null;
|
|
651
|
-
const currentOrganization = organizations.find((organization) => organization.id === currentId) ?? organizations[0] ?? null;
|
|
652
|
-
return { appName, currentOrganization, organizations };
|
|
653
|
-
} catch {
|
|
654
|
-
return { appName, currentOrganization: null, organizations: [] };
|
|
655
|
-
}
|
|
656
|
-
}
|
|
502
|
+
extra: async () => ({
|
|
503
|
+
appName: appDisplayName(),
|
|
504
|
+
currentOrganization: null,
|
|
505
|
+
organizations: []
|
|
506
|
+
})
|
|
657
507
|
});
|
|
658
508
|
configureWebErrorView({
|
|
659
509
|
render: async (input) => engine.render(errorTemplateName(input.status), {
|