@objectstack/plugin-auth 6.7.0 → 6.8.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.
- package/LICENSE +93 -202
- package/README.md +2 -1
- package/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +120 -42
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +121 -42
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/LICENSE
CHANGED
|
@@ -1,202 +1,93 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
(a) You must give any other recipients of the Work or
|
|
95
|
-
Derivative Works a copy of this License; and
|
|
96
|
-
|
|
97
|
-
(b) You must cause any modified files to carry prominent notices
|
|
98
|
-
stating that You changed the files; and
|
|
99
|
-
|
|
100
|
-
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
-
that You distribute, all copyright, patent, trademark, and
|
|
102
|
-
attribution notices from the Source form of the Work,
|
|
103
|
-
excluding those notices that do not pertain to any part of
|
|
104
|
-
the Derivative Works; and
|
|
105
|
-
|
|
106
|
-
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
-
distribution, then any Derivative Works that You distribute
|
|
108
|
-
must include a readable copy of the attribution notices
|
|
109
|
-
contained within such NOTICE file, excluding those notices
|
|
110
|
-
that do not pertain to any part of the Derivative Works,
|
|
111
|
-
in at least one of the following places: within a NOTICE
|
|
112
|
-
text file distributed as part of the Derivative Works; within
|
|
113
|
-
the Source form or documentation, if provided along with
|
|
114
|
-
the Derivative Works; or, within a display generated by the
|
|
115
|
-
Derivative Works, if and wherever such third-party notices
|
|
116
|
-
normally appear. The contents of the NOTICE file are for
|
|
117
|
-
informational purposes only and do not modify the License.
|
|
118
|
-
You may add Your own attribution notices within Derivative
|
|
119
|
-
Works that You distribute, alongside or as an addendum to
|
|
120
|
-
the NOTICE text from the Work, provided that such additional
|
|
121
|
-
attribution notices cannot be construed as modifying the
|
|
122
|
-
License.
|
|
123
|
-
|
|
124
|
-
You may add Your own copyright statement to Your modifications and
|
|
125
|
-
may provide additional or different license terms and conditions
|
|
126
|
-
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
-
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
-
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
-
the conditions stated in this License.
|
|
130
|
-
|
|
131
|
-
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
-
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
-
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
-
this License, without any additional terms or conditions.
|
|
135
|
-
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
-
the terms of any separate license agreement you may have executed
|
|
137
|
-
with Licensor regarding such Contributions.
|
|
138
|
-
|
|
139
|
-
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
-
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
-
except as required for reasonable and customary use in describing the
|
|
142
|
-
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
-
|
|
144
|
-
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
-
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
-
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
-
implied, including, without limitation, any warranties or conditions
|
|
149
|
-
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
-
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
-
appropriateness of using or redistributing the Work and assume any
|
|
152
|
-
risks associated with Your exercise of permissions under this License.
|
|
153
|
-
|
|
154
|
-
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
-
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
-
unless required by applicable law (such as deliberate and grossly
|
|
157
|
-
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
-
liable to You for damages, including any direct, indirect, special,
|
|
159
|
-
incidental, or consequential damages of any character arising as a
|
|
160
|
-
result of this License or out of the use or inability to use the
|
|
161
|
-
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
-
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
-
other commercial damages or losses), even if such Contributor
|
|
164
|
-
has been advised of the possibility of such damages.
|
|
165
|
-
|
|
166
|
-
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
-
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
-
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
-
or other liability obligations and/or rights consistent with this
|
|
170
|
-
License. However, in accepting such obligations, You may act only
|
|
171
|
-
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
-
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
-
defend, and hold each Contributor harmless for any liability
|
|
174
|
-
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
-
of your accepting any such warranty or additional liability.
|
|
176
|
-
|
|
177
|
-
END OF TERMS AND CONDITIONS
|
|
178
|
-
|
|
179
|
-
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
-
|
|
181
|
-
To apply the Apache License to your work, attach the following
|
|
182
|
-
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
-
replaced with your own identifying information. (Don't include
|
|
184
|
-
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
-
comment syntax for the file format. We also recommend that a
|
|
186
|
-
file or class name and description of purpose be included on the
|
|
187
|
-
same "printed page" as the copyright notice for easier
|
|
188
|
-
identification within third-party archives.
|
|
189
|
-
|
|
190
|
-
Copyright 2026 ObjectStack
|
|
191
|
-
|
|
192
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
-
you may not use this file except in compliance with the License.
|
|
194
|
-
You may obtain a copy of the License at
|
|
195
|
-
|
|
196
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
-
|
|
198
|
-
Unless required by applicable law or agreed to in writing, software
|
|
199
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
-
See the License for the specific language governing permissions and
|
|
202
|
-
limitations under the License.
|
|
1
|
+
License text copyright (c) 2020 MariaDB Corporation Ab, All Rights Reserved.
|
|
2
|
+
"Business Source License" is a trademark of MariaDB Corporation Ab.
|
|
3
|
+
|
|
4
|
+
Parameters
|
|
5
|
+
|
|
6
|
+
Licensor: ObjectStack AI LLC
|
|
7
|
+
Licensed Work: ObjectStack Runtime: the BSL-licensed packages
|
|
8
|
+
of the ObjectStack monorepo as listed in LICENSING.md.
|
|
9
|
+
Copyright (c) 2026 ObjectStack AI LLC.
|
|
10
|
+
Additional Use Grant: You may make production use of the Licensed Work, provided
|
|
11
|
+
Your use does not include offering the Licensed Work to third
|
|
12
|
+
parties on a hosted or embedded basis in order to compete with
|
|
13
|
+
ObjectStack AI LLC's paid version(s) of the Licensed Work. For purposes
|
|
14
|
+
of this license:
|
|
15
|
+
|
|
16
|
+
A "competitive offering" is a Product that is offered to third
|
|
17
|
+
parties on a paid basis, including through paid support
|
|
18
|
+
arrangements, that significantly overlaps with the capabilities
|
|
19
|
+
of ObjectStack AI LLC's paid version(s) of the Licensed Work. If Your
|
|
20
|
+
Product is not a competitive offering when You first make it
|
|
21
|
+
generally available, it will not become a competitive offering
|
|
22
|
+
later due to ObjectStack AI LLC releasing a new version of the Licensed
|
|
23
|
+
Work with additional capabilities. In addition, Products that
|
|
24
|
+
are not provided on a paid basis are not competitive.
|
|
25
|
+
|
|
26
|
+
"Product" means software that is offered to end users to manage
|
|
27
|
+
in their own environments or offered as a service on a hosted
|
|
28
|
+
basis.
|
|
29
|
+
|
|
30
|
+
"Embedded" means including the source code or executable code
|
|
31
|
+
from the Licensed Work in a competitive offering. "Embedded"
|
|
32
|
+
also means packaging the competitive offering in such a way
|
|
33
|
+
that the Licensed Work must be accessed or downloaded for the
|
|
34
|
+
competitive offering to operate.
|
|
35
|
+
|
|
36
|
+
Hosting or using the Licensed Work(s) for internal purposes
|
|
37
|
+
within an organization is not considered a competitive
|
|
38
|
+
offering. ObjectStack AI LLC considers your organization to include all
|
|
39
|
+
of your affiliates under common control.
|
|
40
|
+
|
|
41
|
+
For binding interpretive guidance on using ObjectStack AI LLC products
|
|
42
|
+
under the Business Source License, please visit our FAQ.
|
|
43
|
+
(see LICENSING.md in this repository)
|
|
44
|
+
Change Date: Four years from the date the Licensed Work is published.
|
|
45
|
+
Change License: Apache License, Version 2.0
|
|
46
|
+
|
|
47
|
+
For information about alternative licensing arrangements for the Licensed Work,
|
|
48
|
+
please contact licensing@objectstack.dev.
|
|
49
|
+
|
|
50
|
+
Notice
|
|
51
|
+
|
|
52
|
+
Business Source License 1.1
|
|
53
|
+
|
|
54
|
+
Terms
|
|
55
|
+
|
|
56
|
+
The Licensor hereby grants you the right to copy, modify, create derivative
|
|
57
|
+
works, redistribute, and make non-production use of the Licensed Work. The
|
|
58
|
+
Licensor may make an Additional Use Grant, above, permitting limited production use.
|
|
59
|
+
|
|
60
|
+
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
61
|
+
available distribution of a specific version of the Licensed Work under this
|
|
62
|
+
License, whichever comes first, the Licensor hereby grants you rights under
|
|
63
|
+
the terms of the Change License, and the rights granted in the paragraph
|
|
64
|
+
above terminate.
|
|
65
|
+
|
|
66
|
+
If your use of the Licensed Work does not comply with the requirements
|
|
67
|
+
currently in effect as described in this License, you must purchase a
|
|
68
|
+
commercial license from the Licensor, its affiliated entities, or authorized
|
|
69
|
+
resellers, or you must refrain from using the Licensed Work.
|
|
70
|
+
|
|
71
|
+
All copies of the original and modified Licensed Work, and derivative works
|
|
72
|
+
of the Licensed Work, are subject to this License. This License applies
|
|
73
|
+
separately for each version of the Licensed Work and the Change Date may vary
|
|
74
|
+
for each version of the Licensed Work released by Licensor.
|
|
75
|
+
|
|
76
|
+
You must conspicuously display this License on each original or modified copy
|
|
77
|
+
of the Licensed Work. If you receive the Licensed Work in original or
|
|
78
|
+
modified form from a third party, the terms and conditions set forth in this
|
|
79
|
+
License apply to your use of that work.
|
|
80
|
+
|
|
81
|
+
Any use of the Licensed Work in violation of this License will automatically
|
|
82
|
+
terminate your rights under this License for the current and all other
|
|
83
|
+
versions of the Licensed Work.
|
|
84
|
+
|
|
85
|
+
This License does not grant you any right in any trademark or logo of
|
|
86
|
+
Licensor or its affiliates (provided that you may use a trademark or logo of
|
|
87
|
+
Licensor as expressly required by this License).
|
|
88
|
+
|
|
89
|
+
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
|
|
90
|
+
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
|
|
91
|
+
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
|
|
92
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
|
|
93
|
+
TITLE.
|
package/README.md
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -332,10 +332,13 @@ declare class AuthManager {
|
|
|
332
332
|
type: "oidc";
|
|
333
333
|
})[];
|
|
334
334
|
features: {
|
|
335
|
+
privacyUrl?: string | undefined;
|
|
336
|
+
termsUrl?: string | undefined;
|
|
335
337
|
twoFactor: boolean;
|
|
336
338
|
passkeys: boolean;
|
|
337
339
|
magicLink: boolean;
|
|
338
340
|
organization: boolean;
|
|
341
|
+
multiOrgEnabled: boolean;
|
|
339
342
|
oidcProvider: boolean;
|
|
340
343
|
deviceAuthorization: boolean;
|
|
341
344
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -332,10 +332,13 @@ declare class AuthManager {
|
|
|
332
332
|
type: "oidc";
|
|
333
333
|
})[];
|
|
334
334
|
features: {
|
|
335
|
+
privacyUrl?: string | undefined;
|
|
336
|
+
termsUrl?: string | undefined;
|
|
335
337
|
twoFactor: boolean;
|
|
336
338
|
passkeys: boolean;
|
|
337
339
|
magicLink: boolean;
|
|
338
340
|
organization: boolean;
|
|
341
|
+
multiOrgEnabled: boolean;
|
|
339
342
|
oidcProvider: boolean;
|
|
340
343
|
deviceAuthorization: boolean;
|
|
341
344
|
};
|
package/dist/index.js
CHANGED
|
@@ -592,6 +592,7 @@ var AuthManager = class {
|
|
|
592
592
|
*/
|
|
593
593
|
async createAuthInstance() {
|
|
594
594
|
const { betterAuth } = await import("better-auth");
|
|
595
|
+
const { createAuthMiddleware } = await import("better-auth/api");
|
|
595
596
|
const plugins = await this.buildPluginList();
|
|
596
597
|
const passwordHasher = await this.resolvePasswordHasher();
|
|
597
598
|
const betterAuthConfig = {
|
|
@@ -650,46 +651,55 @@ var AuthManager = class {
|
|
|
650
651
|
},
|
|
651
652
|
// Social / OAuth providers
|
|
652
653
|
...this.config.socialProviders ? { socialProviders: this.config.socialProviders } : {},
|
|
653
|
-
// Email and password configuration
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
654
|
+
// Email and password configuration.
|
|
655
|
+
// `disableSignUp`: the env var `OS_DISABLE_SIGNUP=true` overrides
|
|
656
|
+
// the config-file value so deployments can flip the toggle without
|
|
657
|
+
// a code change (`getPublicConfig()` applies the same precedence so
|
|
658
|
+
// `/auth/config` stays consistent with the server enforcement).
|
|
659
|
+
emailAndPassword: (() => {
|
|
660
|
+
const disableSignUpEnv = globalThis?.process?.env?.OS_DISABLE_SIGNUP;
|
|
661
|
+
const disableSignUpFromEnv = disableSignUpEnv != null ? String(disableSignUpEnv).toLowerCase() === "true" : void 0;
|
|
662
|
+
const effectiveDisableSignUp = disableSignUpFromEnv ?? this.config.emailAndPassword?.disableSignUp;
|
|
663
|
+
return {
|
|
664
|
+
enabled: this.config.emailAndPassword?.enabled ?? true,
|
|
665
|
+
...passwordHasher ? { password: passwordHasher } : {},
|
|
666
|
+
...effectiveDisableSignUp != null ? { disableSignUp: effectiveDisableSignUp } : {},
|
|
667
|
+
...this.config.emailAndPassword?.requireEmailVerification != null ? { requireEmailVerification: this.config.emailAndPassword.requireEmailVerification } : {},
|
|
668
|
+
...this.config.emailAndPassword?.minPasswordLength != null ? { minPasswordLength: this.config.emailAndPassword.minPasswordLength } : {},
|
|
669
|
+
...this.config.emailAndPassword?.maxPasswordLength != null ? { maxPasswordLength: this.config.emailAndPassword.maxPasswordLength } : {},
|
|
670
|
+
...this.config.emailAndPassword?.resetPasswordTokenExpiresIn != null ? { resetPasswordTokenExpiresIn: this.config.emailAndPassword.resetPasswordTokenExpiresIn } : {},
|
|
671
|
+
...this.config.emailAndPassword?.autoSignIn != null ? { autoSignIn: this.config.emailAndPassword.autoSignIn } : {},
|
|
672
|
+
...this.config.emailAndPassword?.revokeSessionsOnPasswordReset != null ? { revokeSessionsOnPasswordReset: this.config.emailAndPassword.revokeSessionsOnPasswordReset } : {},
|
|
673
|
+
sendResetPassword: async ({ user, url, token }) => {
|
|
674
|
+
const email = this.getEmailService();
|
|
675
|
+
if (!email) {
|
|
676
|
+
console.warn(
|
|
677
|
+
`[AuthManager] Password-reset requested for ${user.email} but no email service is wired. URL: ${url}`
|
|
678
|
+
);
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
const ttlSec = this.config.emailAndPassword?.resetPasswordTokenExpiresIn ?? 60 * 60;
|
|
682
|
+
try {
|
|
683
|
+
await email.sendTemplate({
|
|
684
|
+
template: "auth.password_reset",
|
|
685
|
+
to: { address: user.email, ...user.name ? { name: user.name } : {} },
|
|
686
|
+
data: {
|
|
687
|
+
user: { name: user.name || user.email, email: user.email, id: user.id },
|
|
688
|
+
resetUrl: url,
|
|
689
|
+
token,
|
|
690
|
+
expiresInMinutes: Math.round(ttlSec / 60),
|
|
691
|
+
appName: this.getAppName()
|
|
692
|
+
},
|
|
693
|
+
relatedObject: "sys_user",
|
|
694
|
+
relatedId: user.id
|
|
695
|
+
});
|
|
696
|
+
} catch (err) {
|
|
697
|
+
console.error(`[AuthManager] sendResetPassword failed: ${err?.message ?? err}`);
|
|
698
|
+
throw err;
|
|
699
|
+
}
|
|
690
700
|
}
|
|
691
|
-
}
|
|
692
|
-
},
|
|
701
|
+
};
|
|
702
|
+
})(),
|
|
693
703
|
// Email verification
|
|
694
704
|
...this.config.emailVerification || this.config.emailService ? {
|
|
695
705
|
emailVerification: {
|
|
@@ -741,6 +751,38 @@ var AuthManager = class {
|
|
|
741
751
|
// for SSO JIT-provisioning too, unlike kernel-level ObjectQL
|
|
742
752
|
// middleware which better-auth's adapter bypasses).
|
|
743
753
|
...this.config.databaseHooks ? { databaseHooks: this.config.databaseHooks } : {},
|
|
754
|
+
// Bootstrap bypass for `disableSignUp`. The first-run owner wizard
|
|
755
|
+
// (`/_account/setup`) calls `POST /auth/sign-up/email` to create
|
|
756
|
+
// the very first user — if `OS_DISABLE_SIGNUP=true` is set on a
|
|
757
|
+
// fresh install we'd lock the operator out of their own instance.
|
|
758
|
+
// Solution: when the request hits `/sign-up/email` AND no users
|
|
759
|
+
// exist yet, temporarily flip `disableSignUp` off for *this*
|
|
760
|
+
// request's context. Once the owner is created the next request
|
|
761
|
+
// sees `userCount > 0` and the toggle is enforced again.
|
|
762
|
+
hooks: {
|
|
763
|
+
before: createAuthMiddleware(async (ctx) => {
|
|
764
|
+
if (ctx?.path !== "/sign-up/email") return;
|
|
765
|
+
const ep = ctx?.context?.options?.emailAndPassword;
|
|
766
|
+
if (!ep?.disableSignUp) return;
|
|
767
|
+
try {
|
|
768
|
+
const adapter = ctx.context.adapter;
|
|
769
|
+
const existing = await adapter.findOne({ model: "user", where: [] });
|
|
770
|
+
if (!existing) {
|
|
771
|
+
ctx.context.__osDisableSignUpOrig = ep.disableSignUp;
|
|
772
|
+
ep.disableSignUp = false;
|
|
773
|
+
}
|
|
774
|
+
} catch {
|
|
775
|
+
}
|
|
776
|
+
}),
|
|
777
|
+
after: createAuthMiddleware(async (ctx) => {
|
|
778
|
+
if (ctx?.path !== "/sign-up/email") return;
|
|
779
|
+
const ep = ctx?.context?.options?.emailAndPassword;
|
|
780
|
+
if (ep && ctx.context.__osDisableSignUpOrig !== void 0) {
|
|
781
|
+
ep.disableSignUp = ctx.context.__osDisableSignUpOrig;
|
|
782
|
+
delete ctx.context.__osDisableSignUpOrig;
|
|
783
|
+
}
|
|
784
|
+
})
|
|
785
|
+
},
|
|
744
786
|
// Trusted origins for CSRF protection (supports wildcards like "https://*.example.com")
|
|
745
787
|
// Auto-includes origins from CORS_ORIGIN env var so CORS and CSRF stay in sync.
|
|
746
788
|
...(() => {
|
|
@@ -895,6 +937,22 @@ var AuthManager = class {
|
|
|
895
937
|
// never seed `sys_environment`) keep working: any lookup error
|
|
896
938
|
// is treated as "no envs to protect".
|
|
897
939
|
organizationHooks: {
|
|
940
|
+
// Gate fresh organization creation behind `OS_MULTI_ORG_ENABLED`.
|
|
941
|
+
// The plugin itself is always installed (so list/update/invite endpoints
|
|
942
|
+
// keep responding); only the `create` operation is denied when the
|
|
943
|
+
// deployment is provisioned in single-org mode. Default is enabled
|
|
944
|
+
// to preserve historical behaviour.
|
|
945
|
+
beforeCreateOrganization: async () => {
|
|
946
|
+
const flag = String(
|
|
947
|
+
globalThis?.process?.env?.OS_MULTI_ORG_ENABLED ?? "true"
|
|
948
|
+
).toLowerCase();
|
|
949
|
+
if (flag === "false") {
|
|
950
|
+
const { APIError } = await import("better-auth/api");
|
|
951
|
+
throw new APIError("FORBIDDEN", {
|
|
952
|
+
message: "Creating additional organizations is disabled on this deployment."
|
|
953
|
+
});
|
|
954
|
+
}
|
|
955
|
+
},
|
|
898
956
|
beforeUpdateOrganization: async ({ organization: organization2, member }) => {
|
|
899
957
|
const newSlug = organization2?.slug;
|
|
900
958
|
const orgId = member?.organizationId;
|
|
@@ -1268,20 +1326,40 @@ var AuthManager = class {
|
|
|
1268
1326
|
}
|
|
1269
1327
|
}
|
|
1270
1328
|
const emailPasswordConfig = this.config.emailAndPassword ?? {};
|
|
1329
|
+
const disableSignUpEnv = globalThis?.process?.env?.OS_DISABLE_SIGNUP;
|
|
1330
|
+
const disableSignUpFromEnv = disableSignUpEnv != null ? String(disableSignUpEnv).toLowerCase() === "true" : void 0;
|
|
1271
1331
|
const emailPassword = {
|
|
1272
1332
|
enabled: emailPasswordConfig.enabled !== false,
|
|
1273
1333
|
// Default to true
|
|
1274
|
-
disableSignUp: emailPasswordConfig.disableSignUp ?? false,
|
|
1334
|
+
disableSignUp: disableSignUpFromEnv ?? emailPasswordConfig.disableSignUp ?? false,
|
|
1275
1335
|
requireEmailVerification: emailPasswordConfig.requireEmailVerification ?? false
|
|
1276
1336
|
};
|
|
1277
1337
|
const pluginConfig = this.config.plugins ?? {};
|
|
1338
|
+
const multiOrgEnabled = String(
|
|
1339
|
+
globalThis?.process?.env?.OS_MULTI_ORG_ENABLED ?? "true"
|
|
1340
|
+
).toLowerCase() !== "false";
|
|
1341
|
+
const DEFAULT_TERMS_URL = "https://objectstack.ai/terms";
|
|
1342
|
+
const DEFAULT_PRIVACY_URL = "https://objectstack.ai/privacy";
|
|
1343
|
+
const rawTermsUrl = globalThis?.process?.env?.OS_TERMS_URL;
|
|
1344
|
+
const rawPrivacyUrl = globalThis?.process?.env?.OS_PRIVACY_URL;
|
|
1345
|
+
const resolveLegalUrl = (raw, fallback) => {
|
|
1346
|
+
if (typeof raw !== "string") return fallback;
|
|
1347
|
+
const trimmed = raw.trim();
|
|
1348
|
+
if (trimmed === "") return void 0;
|
|
1349
|
+
return trimmed;
|
|
1350
|
+
};
|
|
1351
|
+
const termsUrl = resolveLegalUrl(rawTermsUrl, DEFAULT_TERMS_URL);
|
|
1352
|
+
const privacyUrl = resolveLegalUrl(rawPrivacyUrl, DEFAULT_PRIVACY_URL);
|
|
1278
1353
|
const features = {
|
|
1279
1354
|
twoFactor: pluginConfig.twoFactor ?? false,
|
|
1280
1355
|
passkeys: pluginConfig.passkeys ?? false,
|
|
1281
1356
|
magicLink: pluginConfig.magicLink ?? false,
|
|
1282
1357
|
organization: pluginConfig.organization ?? true,
|
|
1358
|
+
multiOrgEnabled,
|
|
1283
1359
|
oidcProvider: pluginConfig.oidcProvider ?? false,
|
|
1284
|
-
deviceAuthorization: pluginConfig.deviceAuthorization ?? false
|
|
1360
|
+
deviceAuthorization: pluginConfig.deviceAuthorization ?? false,
|
|
1361
|
+
...termsUrl ? { termsUrl } : {},
|
|
1362
|
+
...privacyUrl ? { privacyUrl } : {}
|
|
1285
1363
|
};
|
|
1286
1364
|
return {
|
|
1287
1365
|
emailPassword,
|
|
@@ -1370,7 +1448,7 @@ var AuthPlugin = class {
|
|
|
1370
1448
|
// @objectstack/platform-objects/apps). plugin-auth is the natural
|
|
1371
1449
|
// owner of its registration since it loads first among the trio
|
|
1372
1450
|
// (auth + security + audit) that supplies the underlying objects.
|
|
1373
|
-
apps: [import_apps.SETUP_APP],
|
|
1451
|
+
apps: [import_apps.SETUP_APP, import_apps.STUDIO_APP],
|
|
1374
1452
|
// List views for each Setup-nav object are defined on the schema
|
|
1375
1453
|
// itself via the canonical `listViews` map (e.g.
|
|
1376
1454
|
// sys_user.listViews.{all_users,unverified,two_factor}). Registering
|