@stackframe/stack-shared 2.8.22 → 2.8.27
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 +30 -0
- package/dist/config/format.d.mts +20 -5
- package/dist/config/format.d.ts +20 -5
- package/dist/config/format.js +39 -14
- package/dist/config/format.js.map +1 -1
- package/dist/config/schema.d.mts +816 -294
- package/dist/config/schema.d.ts +816 -294
- package/dist/config/schema.js +471 -82
- package/dist/config/schema.js.map +1 -1
- package/dist/crud.d.mts +1 -0
- package/dist/crud.d.ts +1 -0
- package/dist/esm/config/format.js +37 -14
- package/dist/esm/config/format.js.map +1 -1
- package/dist/esm/config/schema.js +460 -78
- package/dist/esm/config/schema.js.map +1 -1
- package/dist/esm/helpers/emails.js +185 -0
- package/dist/esm/helpers/emails.js.map +1 -0
- package/dist/esm/interface/admin-interface.js +58 -36
- package/dist/esm/interface/admin-interface.js.map +1 -1
- package/dist/esm/interface/client-interface.js +41 -0
- package/dist/esm/interface/client-interface.js.map +1 -1
- package/dist/esm/interface/crud/{oauth.js → connected-accounts.js} +2 -2
- package/dist/esm/interface/crud/connected-accounts.js.map +1 -0
- package/dist/esm/interface/crud/oauth-providers.js +87 -0
- package/dist/esm/interface/crud/oauth-providers.js.map +1 -0
- package/dist/esm/interface/crud/projects.js +7 -5
- package/dist/esm/interface/crud/projects.js.map +1 -1
- package/dist/esm/interface/server-interface.js +51 -0
- package/dist/esm/interface/server-interface.js.map +1 -1
- package/dist/esm/known-errors.js +34 -1
- package/dist/esm/known-errors.js.map +1 -1
- package/dist/esm/schema-fields.js +112 -24
- package/dist/esm/schema-fields.js.map +1 -1
- package/dist/esm/utils/currencies.js +52 -0
- package/dist/esm/utils/currencies.js.map +1 -0
- package/dist/esm/utils/dates.js +55 -1
- package/dist/esm/utils/dates.js.map +1 -1
- package/dist/esm/utils/errors.js.map +1 -1
- package/dist/esm/utils/esbuild.js +14 -4
- package/dist/esm/utils/esbuild.js.map +1 -1
- package/dist/esm/utils/oauth.js +1 -1
- package/dist/esm/utils/oauth.js.map +1 -1
- package/dist/esm/utils/objects.js +2 -0
- package/dist/esm/utils/objects.js.map +1 -1
- package/dist/esm/utils/strings.js +4 -0
- package/dist/esm/utils/strings.js.map +1 -1
- package/dist/esm/utils/types.js +45 -0
- package/dist/esm/utils/types.js.map +1 -1
- package/dist/helpers/emails.d.mts +50 -0
- package/dist/helpers/emails.d.ts +50 -0
- package/dist/helpers/emails.js +216 -0
- package/dist/helpers/emails.js.map +1 -0
- package/dist/helpers/password.d.mts +1 -0
- package/dist/helpers/password.d.ts +1 -0
- package/dist/helpers/production-mode.d.mts +1 -0
- package/dist/helpers/production-mode.d.ts +1 -0
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/interface/admin-interface.d.mts +24 -15
- package/dist/interface/admin-interface.d.ts +24 -15
- package/dist/interface/admin-interface.js +58 -36
- package/dist/interface/admin-interface.js.map +1 -1
- package/dist/interface/client-interface.d.mts +25 -1
- package/dist/interface/client-interface.d.ts +25 -1
- package/dist/interface/client-interface.js +41 -0
- package/dist/interface/client-interface.js.map +1 -1
- package/dist/interface/crud/{oauth.d.mts → connected-accounts.d.mts} +1 -0
- package/dist/interface/crud/{oauth.d.ts → connected-accounts.d.ts} +1 -0
- package/dist/interface/crud/{oauth.js → connected-accounts.js} +5 -5
- package/dist/interface/crud/connected-accounts.js.map +1 -0
- package/dist/interface/crud/contact-channels.d.mts +1 -0
- package/dist/interface/crud/contact-channels.d.ts +1 -0
- package/dist/interface/crud/current-user.d.mts +1 -0
- package/dist/interface/crud/current-user.d.ts +1 -0
- package/dist/interface/crud/email-templates.d.mts +1 -0
- package/dist/interface/crud/email-templates.d.ts +1 -0
- package/dist/interface/crud/emails.d.mts +1 -0
- package/dist/interface/crud/emails.d.ts +1 -0
- package/dist/interface/crud/internal-api-keys.d.mts +1 -0
- package/dist/interface/crud/internal-api-keys.d.ts +1 -0
- package/dist/interface/crud/notification-preferences.d.mts +1 -0
- package/dist/interface/crud/notification-preferences.d.ts +1 -0
- package/dist/interface/crud/oauth-providers.d.mts +173 -0
- package/dist/interface/crud/oauth-providers.d.ts +173 -0
- package/dist/interface/crud/oauth-providers.js +107 -0
- package/dist/interface/crud/oauth-providers.js.map +1 -0
- package/dist/interface/crud/project-api-keys.d.mts +1 -0
- package/dist/interface/crud/project-api-keys.d.ts +1 -0
- package/dist/interface/crud/project-permissions.d.mts +1 -0
- package/dist/interface/crud/project-permissions.d.ts +1 -0
- package/dist/interface/crud/projects.d.mts +16 -12
- package/dist/interface/crud/projects.d.ts +16 -12
- package/dist/interface/crud/projects.js +5 -3
- package/dist/interface/crud/projects.js.map +1 -1
- package/dist/interface/crud/sessions.d.mts +1 -0
- package/dist/interface/crud/sessions.d.ts +1 -0
- package/dist/interface/crud/svix-token.d.mts +1 -0
- package/dist/interface/crud/svix-token.d.ts +1 -0
- package/dist/interface/crud/team-invitation-details.d.mts +1 -0
- package/dist/interface/crud/team-invitation-details.d.ts +1 -0
- package/dist/interface/crud/team-invitation.d.mts +1 -0
- package/dist/interface/crud/team-invitation.d.ts +1 -0
- package/dist/interface/crud/team-member-profiles.d.mts +1 -0
- package/dist/interface/crud/team-member-profiles.d.ts +1 -0
- package/dist/interface/crud/team-memberships.d.mts +1 -0
- package/dist/interface/crud/team-memberships.d.ts +1 -0
- package/dist/interface/crud/team-permissions.d.mts +1 -0
- package/dist/interface/crud/team-permissions.d.ts +1 -0
- package/dist/interface/crud/teams.d.mts +1 -0
- package/dist/interface/crud/teams.d.ts +1 -0
- package/dist/interface/crud/users.d.mts +1 -0
- package/dist/interface/crud/users.d.ts +1 -0
- package/dist/interface/server-interface.d.mts +46 -1
- package/dist/interface/server-interface.d.ts +46 -1
- package/dist/interface/server-interface.js +51 -0
- package/dist/interface/server-interface.js.map +1 -1
- package/dist/known-errors.d.mts +9 -0
- package/dist/known-errors.d.ts +9 -0
- package/dist/known-errors.js +34 -1
- package/dist/known-errors.js.map +1 -1
- package/dist/schema-fields.d.mts +51 -7
- package/dist/schema-fields.d.ts +51 -7
- package/dist/schema-fields.js +128 -24
- package/dist/schema-fields.js.map +1 -1
- package/dist/utils/currencies.d.mts +39 -0
- package/dist/utils/currencies.d.ts +39 -0
- package/dist/utils/currencies.js +78 -0
- package/dist/utils/currencies.js.map +1 -0
- package/dist/utils/dates.d.mts +5 -1
- package/dist/utils/dates.d.ts +5 -1
- package/dist/utils/dates.js +58 -2
- package/dist/utils/dates.js.map +1 -1
- package/dist/utils/errors.d.mts +9 -0
- package/dist/utils/errors.d.ts +9 -0
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/esbuild.d.mts +3 -0
- package/dist/utils/esbuild.d.ts +3 -0
- package/dist/utils/esbuild.js +14 -4
- package/dist/utils/esbuild.js.map +1 -1
- package/dist/utils/oauth.d.mts +2 -2
- package/dist/utils/oauth.d.ts +2 -2
- package/dist/utils/oauth.js +1 -1
- package/dist/utils/oauth.js.map +1 -1
- package/dist/utils/objects.d.mts +23 -8
- package/dist/utils/objects.d.ts +23 -8
- package/dist/utils/objects.js +2 -0
- package/dist/utils/objects.js.map +1 -1
- package/dist/utils/strings.d.mts +3 -1
- package/dist/utils/strings.d.ts +3 -1
- package/dist/utils/strings.js +5 -0
- package/dist/utils/strings.js.map +1 -1
- package/dist/utils/types.d.mts +73 -2
- package/dist/utils/types.d.ts +73 -2
- package/dist/utils/types.js +54 -0
- package/dist/utils/types.js.map +1 -1
- package/package.json +1 -1
- package/dist/esm/helpers/email-themes.js +0 -45
- package/dist/esm/helpers/email-themes.js.map +0 -1
- package/dist/esm/interface/crud/oauth.js.map +0 -1
- package/dist/helpers/email-themes.d.mts +0 -13
- package/dist/helpers/email-themes.d.ts +0 -13
- package/dist/helpers/email-themes.js +0 -71
- package/dist/helpers/email-themes.js.map +0 -1
- package/dist/interface/crud/oauth.js.map +0 -1
|
@@ -1,109 +1,122 @@
|
|
|
1
1
|
// src/config/schema.ts
|
|
2
|
+
import * as yup from "yup";
|
|
3
|
+
import { DEFAULT_EMAIL_TEMPLATES, DEFAULT_EMAIL_THEMES, DEFAULT_EMAIL_THEME_ID } from "../helpers/emails.js";
|
|
2
4
|
import * as schemaFields from "../schema-fields.js";
|
|
3
|
-
import { yupBoolean, yupObject, yupRecord, yupString, yupUnion } from "../schema-fields.js";
|
|
5
|
+
import { yupBoolean, yupDate, yupMixed, yupNever, yupNumber, yupObject, yupRecord, yupString, yupTuple, yupUnion } from "../schema-fields.js";
|
|
6
|
+
import { isShallowEqual } from "../utils/arrays.js";
|
|
7
|
+
import { StackAssertionError } from "../utils/errors.js";
|
|
4
8
|
import { allProviders } from "../utils/oauth.js";
|
|
5
|
-
import { get, has, isObjectLike, mapValues, set } from "../utils/objects.js";
|
|
6
|
-
import {
|
|
9
|
+
import { deleteKey, filterUndefined, get, has, isObjectLike, mapValues, set, typedAssign, typedFromEntries } from "../utils/objects.js";
|
|
10
|
+
import { Result } from "../utils/results.js";
|
|
11
|
+
import { typeAssert, typeAssertExtends, typeAssertIs } from "../utils/types.js";
|
|
12
|
+
import { NormalizationError, assertNormalized, getInvalidConfigReason, normalize } from "./format.js";
|
|
7
13
|
var configLevels = ["project", "branch", "environment", "organization"];
|
|
8
14
|
var permissionRegex = /^\$?[a-z0-9_:]+$/;
|
|
9
15
|
var customPermissionRegex = /^[a-z0-9_:]+$/;
|
|
16
|
+
function canNoLongerBeOverridden(schema, keys) {
|
|
17
|
+
const notOmitted = schema.concat(yupObject(
|
|
18
|
+
Object.fromEntries(keys.map((key) => [key, schema.getNested(key).meta({ stackConfigCanNoLongerBeOverridden: true })]))
|
|
19
|
+
));
|
|
20
|
+
return notOmitted;
|
|
21
|
+
}
|
|
10
22
|
var projectConfigSchema = yupObject({
|
|
11
23
|
sourceOfTruth: yupUnion(
|
|
12
24
|
yupObject({
|
|
13
|
-
type: yupString().oneOf(["hosted"]).
|
|
14
|
-
})
|
|
25
|
+
type: yupString().oneOf(["hosted"]).defined()
|
|
26
|
+
}),
|
|
15
27
|
yupObject({
|
|
16
|
-
type: yupString().oneOf(["neon"]).
|
|
28
|
+
type: yupString().oneOf(["neon"]).defined(),
|
|
17
29
|
connectionStrings: yupRecord(
|
|
18
30
|
yupString().defined(),
|
|
19
31
|
yupString().defined()
|
|
20
32
|
).defined()
|
|
21
|
-
})
|
|
33
|
+
}),
|
|
22
34
|
yupObject({
|
|
23
|
-
type: yupString().oneOf(["postgres"]).
|
|
35
|
+
type: yupString().oneOf(["postgres"]).defined(),
|
|
24
36
|
connectionString: yupString().defined()
|
|
25
|
-
})
|
|
26
|
-
)
|
|
37
|
+
})
|
|
38
|
+
)
|
|
27
39
|
});
|
|
28
40
|
var branchRbacDefaultPermissions = yupRecord(
|
|
29
|
-
yupString().
|
|
41
|
+
yupString().matches(permissionRegex),
|
|
30
42
|
yupBoolean().isTrue().optional()
|
|
31
|
-
)
|
|
43
|
+
);
|
|
32
44
|
var branchRbacSchema = yupObject({
|
|
33
45
|
permissions: yupRecord(
|
|
34
|
-
yupString().
|
|
46
|
+
yupString().matches(customPermissionRegex),
|
|
35
47
|
yupObject({
|
|
36
48
|
description: yupString().optional(),
|
|
37
49
|
scope: yupString().oneOf(["team", "project"]).optional(),
|
|
38
50
|
containedPermissionIds: yupRecord(
|
|
39
|
-
yupString().
|
|
51
|
+
yupString().matches(permissionRegex),
|
|
40
52
|
yupBoolean().isTrue().optional()
|
|
41
53
|
).optional()
|
|
42
54
|
}).optional()
|
|
43
|
-
)
|
|
55
|
+
),
|
|
44
56
|
defaultPermissions: yupObject({
|
|
45
57
|
teamCreator: branchRbacDefaultPermissions,
|
|
46
58
|
teamMember: branchRbacDefaultPermissions,
|
|
47
59
|
signUp: branchRbacDefaultPermissions
|
|
48
|
-
})
|
|
49
|
-
})
|
|
60
|
+
})
|
|
61
|
+
});
|
|
50
62
|
var branchApiKeysSchema = yupObject({
|
|
51
63
|
enabled: yupObject({
|
|
52
|
-
team: yupBoolean()
|
|
53
|
-
user: yupBoolean()
|
|
54
|
-
})
|
|
55
|
-
})
|
|
64
|
+
team: yupBoolean(),
|
|
65
|
+
user: yupBoolean()
|
|
66
|
+
})
|
|
67
|
+
});
|
|
56
68
|
var branchAuthSchema = yupObject({
|
|
57
|
-
allowSignUp: yupBoolean()
|
|
69
|
+
allowSignUp: yupBoolean(),
|
|
58
70
|
password: yupObject({
|
|
59
|
-
allowSignIn: yupBoolean()
|
|
60
|
-
})
|
|
71
|
+
allowSignIn: yupBoolean()
|
|
72
|
+
}),
|
|
61
73
|
otp: yupObject({
|
|
62
|
-
allowSignIn: yupBoolean()
|
|
63
|
-
})
|
|
74
|
+
allowSignIn: yupBoolean()
|
|
75
|
+
}),
|
|
64
76
|
passkey: yupObject({
|
|
65
|
-
allowSignIn: yupBoolean()
|
|
66
|
-
})
|
|
77
|
+
allowSignIn: yupBoolean()
|
|
78
|
+
}),
|
|
67
79
|
oauth: yupObject({
|
|
68
80
|
accountMergeStrategy: yupString().oneOf(["link_method", "raise_error", "allow_duplicates"]).optional(),
|
|
69
81
|
providers: yupRecord(
|
|
70
|
-
yupString().
|
|
82
|
+
yupString().matches(permissionRegex),
|
|
71
83
|
yupObject({
|
|
72
84
|
type: yupString().oneOf(allProviders).optional(),
|
|
73
|
-
allowSignIn: yupBoolean()
|
|
74
|
-
allowConnectedAccounts: yupBoolean()
|
|
75
|
-
})
|
|
76
|
-
)
|
|
77
|
-
})
|
|
78
|
-
})
|
|
85
|
+
allowSignIn: yupBoolean(),
|
|
86
|
+
allowConnectedAccounts: yupBoolean()
|
|
87
|
+
})
|
|
88
|
+
)
|
|
89
|
+
})
|
|
90
|
+
});
|
|
79
91
|
var branchDomain = yupObject({
|
|
80
|
-
allowLocalhost: yupBoolean()
|
|
81
|
-
})
|
|
82
|
-
var branchConfigSchema = projectConfigSchema
|
|
92
|
+
allowLocalhost: yupBoolean()
|
|
93
|
+
});
|
|
94
|
+
var branchConfigSchema = canNoLongerBeOverridden(projectConfigSchema, ["sourceOfTruth"]).concat(yupObject({
|
|
83
95
|
rbac: branchRbacSchema,
|
|
84
96
|
teams: yupObject({
|
|
85
|
-
createPersonalTeamOnSignUp: yupBoolean()
|
|
86
|
-
allowClientTeamCreation: yupBoolean()
|
|
87
|
-
})
|
|
97
|
+
createPersonalTeamOnSignUp: yupBoolean(),
|
|
98
|
+
allowClientTeamCreation: yupBoolean()
|
|
99
|
+
}),
|
|
88
100
|
users: yupObject({
|
|
89
|
-
allowClientUserDeletion: yupBoolean()
|
|
90
|
-
})
|
|
101
|
+
allowClientUserDeletion: yupBoolean()
|
|
102
|
+
}),
|
|
91
103
|
apiKeys: branchApiKeysSchema,
|
|
92
104
|
domains: branchDomain,
|
|
93
105
|
auth: branchAuthSchema,
|
|
94
106
|
emails: yupObject({
|
|
95
|
-
|
|
96
|
-
|
|
107
|
+
selectedThemeId: schemaFields.emailThemeSchema,
|
|
108
|
+
themes: schemaFields.emailThemeListSchema,
|
|
109
|
+
templates: schemaFields.emailTemplateListSchema
|
|
97
110
|
})
|
|
98
111
|
}));
|
|
99
112
|
var environmentConfigSchema = branchConfigSchema.concat(yupObject({
|
|
100
113
|
auth: branchConfigSchema.getNested("auth").concat(yupObject({
|
|
101
114
|
oauth: branchConfigSchema.getNested("auth").getNested("oauth").concat(yupObject({
|
|
102
115
|
providers: yupRecord(
|
|
103
|
-
yupString().
|
|
116
|
+
yupString().matches(permissionRegex),
|
|
104
117
|
yupObject({
|
|
105
118
|
type: yupString().oneOf(allProviders).optional(),
|
|
106
|
-
isShared: yupBoolean()
|
|
119
|
+
isShared: yupBoolean(),
|
|
107
120
|
clientId: schemaFields.oauthClientIdSchema.optional(),
|
|
108
121
|
clientSecret: schemaFields.oauthClientSecretSchema.optional(),
|
|
109
122
|
facebookConfigId: schemaFields.oauthFacebookConfigIdSchema.optional(),
|
|
@@ -111,12 +124,12 @@ var environmentConfigSchema = branchConfigSchema.concat(yupObject({
|
|
|
111
124
|
allowSignIn: yupBoolean().optional(),
|
|
112
125
|
allowConnectedAccounts: yupBoolean().optional()
|
|
113
126
|
})
|
|
114
|
-
)
|
|
115
|
-
})
|
|
127
|
+
)
|
|
128
|
+
}))
|
|
116
129
|
})),
|
|
117
130
|
emails: branchConfigSchema.getNested("emails").concat(yupObject({
|
|
118
131
|
server: yupObject({
|
|
119
|
-
isShared: yupBoolean()
|
|
132
|
+
isShared: yupBoolean(),
|
|
120
133
|
host: schemaFields.emailHostSchema.optional().nonEmpty(),
|
|
121
134
|
port: schemaFields.emailPortSchema.optional(),
|
|
122
135
|
username: schemaFields.emailUsernameSchema.optional().nonEmpty(),
|
|
@@ -124,32 +137,103 @@ var environmentConfigSchema = branchConfigSchema.concat(yupObject({
|
|
|
124
137
|
senderName: schemaFields.emailSenderNameSchema.optional().nonEmpty(),
|
|
125
138
|
senderEmail: schemaFields.emailSenderEmailSchema.optional().nonEmpty()
|
|
126
139
|
})
|
|
127
|
-
})
|
|
140
|
+
})),
|
|
128
141
|
domains: branchConfigSchema.getNested("domains").concat(yupObject({
|
|
129
142
|
trustedDomains: yupRecord(
|
|
130
|
-
yupString()
|
|
143
|
+
yupString(),
|
|
131
144
|
yupObject({
|
|
132
|
-
baseUrl: schemaFields.urlSchema
|
|
133
|
-
handlerPath: schemaFields.handlerPathSchema
|
|
145
|
+
baseUrl: schemaFields.urlSchema,
|
|
146
|
+
handlerPath: schemaFields.handlerPathSchema
|
|
134
147
|
})
|
|
135
|
-
)
|
|
148
|
+
)
|
|
136
149
|
}))
|
|
137
150
|
}));
|
|
138
151
|
var organizationConfigSchema = environmentConfigSchema.concat(yupObject({}));
|
|
152
|
+
function migrateConfigOverride(type, oldUnmigratedConfigOverride) {
|
|
153
|
+
const isBranchOrHigher = ["branch", "environment", "organization"].includes(type);
|
|
154
|
+
const isEnvironmentOrHigher = ["environment", "organization"].includes(type);
|
|
155
|
+
let res = oldUnmigratedConfigOverride;
|
|
156
|
+
if (isBranchOrHigher) {
|
|
157
|
+
res = renameProperty(res, "emails.theme", "emails.selectedThemeId");
|
|
158
|
+
}
|
|
159
|
+
if (isEnvironmentOrHigher) {
|
|
160
|
+
res = mapProperty(res, "domains.trustedDomains", (value) => {
|
|
161
|
+
if (Array.isArray(value)) {
|
|
162
|
+
return typedFromEntries(value.map((v, i) => [`${i}`, v]));
|
|
163
|
+
}
|
|
164
|
+
return value;
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
if (isBranchOrHigher) {
|
|
168
|
+
res = removeProperty(res, "emails.themeList");
|
|
169
|
+
res = removeProperty(res, "emails.templateList");
|
|
170
|
+
}
|
|
171
|
+
if (type === "environment") {
|
|
172
|
+
res = removeProperty(res, "sourceOfTruth");
|
|
173
|
+
}
|
|
174
|
+
return res;
|
|
175
|
+
}
|
|
176
|
+
function removeProperty(obj, path) {
|
|
177
|
+
return mapProperty(obj, path, () => void 0);
|
|
178
|
+
}
|
|
179
|
+
function mapProperty(obj, path, mapper) {
|
|
180
|
+
const keyParts = path.split(".");
|
|
181
|
+
for (let i = 0; i < keyParts.length; i++) {
|
|
182
|
+
const pathPrefix = keyParts.slice(0, i).join(".");
|
|
183
|
+
const pathSuffix = keyParts.slice(i).join(".");
|
|
184
|
+
if (has(obj, pathPrefix) && isObjectLike(get(obj, pathPrefix))) {
|
|
185
|
+
const newValue = mapProperty(get(obj, pathPrefix), pathSuffix, mapper);
|
|
186
|
+
set(obj, pathPrefix, newValue);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (has(obj, path)) {
|
|
190
|
+
const newValue = mapper(get(obj, path));
|
|
191
|
+
if (newValue !== void 0) {
|
|
192
|
+
set(obj, path, newValue);
|
|
193
|
+
} else {
|
|
194
|
+
deleteKey(obj, path);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return obj;
|
|
198
|
+
}
|
|
199
|
+
function renameProperty(obj, oldPath, newPath) {
|
|
200
|
+
const oldKeyParts = oldPath.split(".");
|
|
201
|
+
const newKeyParts = newPath.split(".");
|
|
202
|
+
if (!isShallowEqual(oldKeyParts.slice(0, -1), newKeyParts.slice(0, -1))) throw new StackAssertionError(`oldPath and newPath must have the same prefix. Provided: ${oldPath} and ${newPath}`);
|
|
203
|
+
for (let i = 0; i < oldKeyParts.length; i++) {
|
|
204
|
+
const pathPrefix = oldKeyParts.slice(0, i).join(".");
|
|
205
|
+
const oldPathSuffix = oldKeyParts.slice(i).join(".");
|
|
206
|
+
const newPathSuffix = newKeyParts.slice(i).join(".");
|
|
207
|
+
if (has(obj, pathPrefix) && isObjectLike(get(obj, pathPrefix))) {
|
|
208
|
+
set(obj, pathPrefix, renameProperty(get(obj, pathPrefix), oldPathSuffix, newPathSuffix));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (has(obj, oldPath)) {
|
|
212
|
+
set(obj, newPath, get(obj, oldPath));
|
|
213
|
+
deleteKey(obj, oldPath);
|
|
214
|
+
}
|
|
215
|
+
return obj;
|
|
216
|
+
}
|
|
139
217
|
var projectConfigDefaults = {
|
|
140
218
|
sourceOfTruth: {
|
|
141
|
-
type: "hosted"
|
|
219
|
+
type: "hosted",
|
|
220
|
+
connectionStrings: void 0,
|
|
221
|
+
connectionString: void 0
|
|
142
222
|
}
|
|
143
223
|
};
|
|
144
224
|
var branchConfigDefaults = {};
|
|
145
225
|
var environmentConfigDefaults = {};
|
|
146
226
|
var organizationConfigDefaults = {
|
|
147
227
|
rbac: {
|
|
148
|
-
permissions: (key) => ({
|
|
228
|
+
permissions: (key) => ({
|
|
229
|
+
containedPermissionIds: (key2) => void 0,
|
|
230
|
+
description: void 0,
|
|
231
|
+
scope: void 0
|
|
232
|
+
}),
|
|
149
233
|
defaultPermissions: {
|
|
150
|
-
teamCreator:
|
|
151
|
-
teamMember:
|
|
152
|
-
signUp:
|
|
234
|
+
teamCreator: (key) => void 0,
|
|
235
|
+
teamMember: (key) => void 0,
|
|
236
|
+
signUp: (key) => void 0
|
|
153
237
|
}
|
|
154
238
|
},
|
|
155
239
|
apiKeys: {
|
|
@@ -168,6 +252,7 @@ var organizationConfigDefaults = {
|
|
|
168
252
|
domains: {
|
|
169
253
|
allowLocalhost: false,
|
|
170
254
|
trustedDomains: (key) => ({
|
|
255
|
+
baseUrl: void 0,
|
|
171
256
|
handlerPath: "/handler"
|
|
172
257
|
})
|
|
173
258
|
},
|
|
@@ -185,44 +270,341 @@ var organizationConfigDefaults = {
|
|
|
185
270
|
oauth: {
|
|
186
271
|
accountMergeStrategy: "link_method",
|
|
187
272
|
providers: (key) => ({
|
|
273
|
+
type: void 0,
|
|
188
274
|
isShared: true,
|
|
189
275
|
allowSignIn: false,
|
|
190
|
-
allowConnectedAccounts: false
|
|
276
|
+
allowConnectedAccounts: false,
|
|
277
|
+
clientId: void 0,
|
|
278
|
+
clientSecret: void 0,
|
|
279
|
+
facebookConfigId: void 0,
|
|
280
|
+
microsoftTenantId: void 0
|
|
191
281
|
})
|
|
192
282
|
}
|
|
193
283
|
},
|
|
194
284
|
emails: {
|
|
195
285
|
server: {
|
|
196
|
-
isShared: true
|
|
286
|
+
isShared: true,
|
|
287
|
+
host: void 0,
|
|
288
|
+
port: void 0,
|
|
289
|
+
username: void 0,
|
|
290
|
+
password: void 0,
|
|
291
|
+
senderName: void 0,
|
|
292
|
+
senderEmail: void 0
|
|
197
293
|
},
|
|
198
|
-
|
|
199
|
-
|
|
294
|
+
selectedThemeId: DEFAULT_EMAIL_THEME_ID,
|
|
295
|
+
themes: typedAssign((key) => ({
|
|
296
|
+
displayName: "Unnamed Theme",
|
|
297
|
+
tsxSource: "Error: Theme config is missing TypeScript source code."
|
|
298
|
+
}), DEFAULT_EMAIL_THEMES),
|
|
299
|
+
templates: typedAssign((key) => ({
|
|
300
|
+
displayName: "Unnamed Template",
|
|
301
|
+
tsxSource: "Error: Template config is missing TypeScript source code.",
|
|
302
|
+
themeId: void 0
|
|
303
|
+
}), DEFAULT_EMAIL_TEMPLATES)
|
|
200
304
|
}
|
|
201
305
|
};
|
|
306
|
+
typeAssertIs()();
|
|
307
|
+
typeAssertIs()();
|
|
308
|
+
function deepReplaceFunctionsWithObjects(obj) {
|
|
309
|
+
return mapValues({ ...obj }, (v) => isObjectLike(v) ? deepReplaceFunctionsWithObjects(v) : v);
|
|
310
|
+
}
|
|
202
311
|
function applyDefaults(defaults, config) {
|
|
203
|
-
const res =
|
|
204
|
-
for (const [key, mergeValue] of Object.entries(config)) {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
312
|
+
const res = deepReplaceFunctionsWithObjects(defaults);
|
|
313
|
+
outer: for (const [key, mergeValue] of Object.entries(config)) {
|
|
314
|
+
if (mergeValue === void 0) continue;
|
|
315
|
+
const keyParts = key.split(".");
|
|
316
|
+
let baseValue = defaults;
|
|
317
|
+
let currentRes = res;
|
|
318
|
+
for (const [index, part] of keyParts.entries()) {
|
|
319
|
+
baseValue = has(baseValue, part) ? get(baseValue, part) : typeof baseValue === "function" ? baseValue(part) : void 0;
|
|
320
|
+
if (baseValue === void 0 || !isObjectLike(baseValue)) {
|
|
321
|
+
set(res, key, mergeValue);
|
|
322
|
+
continue outer;
|
|
210
323
|
}
|
|
324
|
+
if (!has(currentRes, part)) set(currentRes, part, deepReplaceFunctionsWithObjects(baseValue));
|
|
325
|
+
currentRes = get(currentRes, part);
|
|
211
326
|
}
|
|
212
|
-
set(res, key, mergeValue);
|
|
327
|
+
set(res, key, isObjectLike(mergeValue) ? applyDefaults(baseValue, mergeValue) : mergeValue);
|
|
213
328
|
}
|
|
214
329
|
return res;
|
|
215
330
|
}
|
|
331
|
+
function applyProjectDefaults(config) {
|
|
332
|
+
return applyDefaults(projectConfigDefaults, config);
|
|
333
|
+
}
|
|
334
|
+
function applyBranchDefaults(config) {
|
|
335
|
+
return applyDefaults(
|
|
336
|
+
branchConfigDefaults,
|
|
337
|
+
applyDefaults(
|
|
338
|
+
projectConfigDefaults,
|
|
339
|
+
config
|
|
340
|
+
)
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
function applyEnvironmentDefaults(config) {
|
|
344
|
+
return applyDefaults(
|
|
345
|
+
environmentConfigDefaults,
|
|
346
|
+
applyDefaults(
|
|
347
|
+
branchConfigDefaults,
|
|
348
|
+
applyDefaults(
|
|
349
|
+
projectConfigDefaults,
|
|
350
|
+
config
|
|
351
|
+
)
|
|
352
|
+
)
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
function applyOrganizationDefaults(config) {
|
|
356
|
+
return applyDefaults(
|
|
357
|
+
organizationConfigDefaults,
|
|
358
|
+
applyDefaults(
|
|
359
|
+
environmentConfigDefaults,
|
|
360
|
+
applyDefaults(
|
|
361
|
+
branchConfigDefaults,
|
|
362
|
+
applyDefaults(
|
|
363
|
+
projectConfigDefaults,
|
|
364
|
+
config
|
|
365
|
+
)
|
|
366
|
+
)
|
|
367
|
+
)
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
async function sanitizeProjectConfig(config) {
|
|
371
|
+
assertNormalized(config);
|
|
372
|
+
const oldSourceOfTruth = config.sourceOfTruth;
|
|
373
|
+
const sourceOfTruth = oldSourceOfTruth.type === "neon" && typeof oldSourceOfTruth.connectionStrings === "object" ? {
|
|
374
|
+
type: "neon",
|
|
375
|
+
connectionStrings: { ...filterUndefined(oldSourceOfTruth.connectionStrings) }
|
|
376
|
+
} : oldSourceOfTruth.type === "postgres" && typeof oldSourceOfTruth.connectionString === "string" ? {
|
|
377
|
+
type: "postgres",
|
|
378
|
+
connectionString: oldSourceOfTruth.connectionString
|
|
379
|
+
} : {
|
|
380
|
+
type: "hosted"
|
|
381
|
+
};
|
|
382
|
+
return {
|
|
383
|
+
...config,
|
|
384
|
+
sourceOfTruth
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
async function sanitizeBranchConfig(config) {
|
|
388
|
+
assertNormalized(config);
|
|
389
|
+
const prepared = await sanitizeProjectConfig(config);
|
|
390
|
+
return {
|
|
391
|
+
...prepared
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
async function sanitizeEnvironmentConfig(config) {
|
|
395
|
+
assertNormalized(config);
|
|
396
|
+
const prepared = await sanitizeBranchConfig(config);
|
|
397
|
+
return {
|
|
398
|
+
...prepared
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
async function sanitizeOrganizationConfig(config) {
|
|
402
|
+
assertNormalized(config);
|
|
403
|
+
const prepared = await sanitizeEnvironmentConfig(config);
|
|
404
|
+
const themes = {
|
|
405
|
+
...DEFAULT_EMAIL_THEMES,
|
|
406
|
+
...prepared.emails.themes
|
|
407
|
+
};
|
|
408
|
+
const templates = {
|
|
409
|
+
...DEFAULT_EMAIL_TEMPLATES,
|
|
410
|
+
...prepared.emails.templates
|
|
411
|
+
};
|
|
412
|
+
return {
|
|
413
|
+
...prepared,
|
|
414
|
+
emails: {
|
|
415
|
+
...prepared.emails,
|
|
416
|
+
selectedThemeId: has(themes, prepared.emails.selectedThemeId) ? prepared.emails.selectedThemeId : DEFAULT_EMAIL_THEME_ID,
|
|
417
|
+
themes,
|
|
418
|
+
templates
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
async function getConfigOverrideErrors(schema, configOverride, options = {}) {
|
|
423
|
+
if (typeof configOverride !== "object" || configOverride === null) {
|
|
424
|
+
return Result.error("Config override must be a non-null object.");
|
|
425
|
+
}
|
|
426
|
+
if (Object.getPrototypeOf(configOverride) !== Object.getPrototypeOf({})) {
|
|
427
|
+
return Result.error("Config override must be plain old JavaScript object.");
|
|
428
|
+
}
|
|
429
|
+
const reason = getInvalidConfigReason(configOverride, { configName: "override" });
|
|
430
|
+
if (reason) return Result.error("Invalid config format: " + reason);
|
|
431
|
+
const getSubSchema = (schema2, key) => {
|
|
432
|
+
const keyParts = key.split(".");
|
|
433
|
+
if (!schema2.hasNested(keyParts[0])) {
|
|
434
|
+
return void 0;
|
|
435
|
+
}
|
|
436
|
+
const nestedSchema = schema2.getNested(keyParts[0]);
|
|
437
|
+
if (nestedSchema.meta()?.stackConfigCanNoLongerBeOverridden && !options.allowPropertiesThatCanNoLongerBeOverridden) {
|
|
438
|
+
return void 0;
|
|
439
|
+
}
|
|
440
|
+
if (keyParts.length === 1) {
|
|
441
|
+
return nestedSchema;
|
|
442
|
+
} else {
|
|
443
|
+
return getSubSchema(nestedSchema, keyParts.slice(1).join("."));
|
|
444
|
+
}
|
|
445
|
+
};
|
|
446
|
+
const getRestrictedSchemaBase = (path, schema2) => {
|
|
447
|
+
const schemaInfo = schema2.meta()?.stackSchemaInfo;
|
|
448
|
+
switch (schemaInfo?.type) {
|
|
449
|
+
case "string": {
|
|
450
|
+
const stringSchema = schema2;
|
|
451
|
+
const description = stringSchema.describe();
|
|
452
|
+
let res = yupString();
|
|
453
|
+
if (description.tests.some((t) => t.name === "uuid")) {
|
|
454
|
+
res = res.uuid();
|
|
455
|
+
}
|
|
456
|
+
return res;
|
|
457
|
+
}
|
|
458
|
+
case "number": {
|
|
459
|
+
return yupNumber();
|
|
460
|
+
}
|
|
461
|
+
case "boolean": {
|
|
462
|
+
return yupBoolean();
|
|
463
|
+
}
|
|
464
|
+
case "date": {
|
|
465
|
+
return yupDate();
|
|
466
|
+
}
|
|
467
|
+
case "mixed": {
|
|
468
|
+
return yupMixed();
|
|
469
|
+
}
|
|
470
|
+
case "array": {
|
|
471
|
+
throw new StackAssertionError(`Arrays are not supported in config JSON files (besides tuples). Use a record instead.`, { schemaInfo, schema: schema2 });
|
|
472
|
+
}
|
|
473
|
+
case "tuple": {
|
|
474
|
+
return yupTuple(schemaInfo.items.map((s, index) => getRestrictedSchema(path + `[${index}]`, s)));
|
|
475
|
+
}
|
|
476
|
+
case "union": {
|
|
477
|
+
const schemas = schemaInfo.items;
|
|
478
|
+
const nonObjectSchemas = [...schemas.entries()].filter(([index, s]) => s.meta()?.stackSchemaInfo?.type !== "object");
|
|
479
|
+
const objectSchemas = schemas.filter((s) => s.meta()?.stackSchemaInfo?.type === "object");
|
|
480
|
+
const allObjectSchemaKeys = [...new Set(objectSchemas.flatMap((s) => Object.keys(s.fields)))];
|
|
481
|
+
const mergedObjectSchema = yupObject(
|
|
482
|
+
Object.fromEntries(
|
|
483
|
+
allObjectSchemaKeys.map((key) => [key, yupUnion(
|
|
484
|
+
...objectSchemas.flatMap((s, index) => s.hasNested(key) ? [s.getNested(key)] : [])
|
|
485
|
+
)])
|
|
486
|
+
)
|
|
487
|
+
);
|
|
488
|
+
return yupUnion(
|
|
489
|
+
...nonObjectSchemas.map(([index, s]) => getRestrictedSchema(path + `|variant-${index}|`, s)),
|
|
490
|
+
...objectSchemas.length > 0 ? [getRestrictedSchema(path + (nonObjectSchemas.length > 0 ? `|variant|` : ""), mergedObjectSchema)] : []
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
case "record": {
|
|
494
|
+
return yupRecord(getRestrictedSchema(path + ".key", schemaInfo.keySchema), getRestrictedSchema(path + ".value", schemaInfo.valueSchema));
|
|
495
|
+
}
|
|
496
|
+
case "object": {
|
|
497
|
+
const objectSchema = schema2;
|
|
498
|
+
return yupObject(
|
|
499
|
+
Object.fromEntries(
|
|
500
|
+
Object.entries(objectSchema.fields).map(([key, value]) => [key, getRestrictedSchema(path + "." + key, value)])
|
|
501
|
+
)
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
case "never": {
|
|
505
|
+
return yupNever();
|
|
506
|
+
}
|
|
507
|
+
default: {
|
|
508
|
+
throw new StackAssertionError(`Unknown schema info at path ${path}: ${JSON.stringify(schemaInfo)}`, { schemaInfo, schema: schema2 });
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
const getRestrictedSchema = (path, schema2) => {
|
|
513
|
+
let restricted = getRestrictedSchemaBase(path, schema2);
|
|
514
|
+
restricted = restricted.nullable();
|
|
515
|
+
const description = schema2.describe();
|
|
516
|
+
if (description.oneOf.length > 0) {
|
|
517
|
+
restricted = restricted.oneOf(description.oneOf);
|
|
518
|
+
}
|
|
519
|
+
if (description.notOneOf.length > 0) {
|
|
520
|
+
restricted = restricted.notOneOf(description.notOneOf);
|
|
521
|
+
}
|
|
522
|
+
return restricted;
|
|
523
|
+
};
|
|
524
|
+
for (const [key, value] of Object.entries(configOverride)) {
|
|
525
|
+
if (value === void 0) continue;
|
|
526
|
+
const subSchema = getSubSchema(schema, key);
|
|
527
|
+
if (!subSchema) {
|
|
528
|
+
return Result.error(`The key ${JSON.stringify(key)} is not valid for the schema.`);
|
|
529
|
+
}
|
|
530
|
+
let restrictedSchema = getRestrictedSchema(key, subSchema);
|
|
531
|
+
try {
|
|
532
|
+
await restrictedSchema.validate(value, {
|
|
533
|
+
strict: true,
|
|
534
|
+
...{
|
|
535
|
+
// Although `path` is not part of the yup types, it is actually recognized and does the correct thing
|
|
536
|
+
path: key
|
|
537
|
+
},
|
|
538
|
+
context: {
|
|
539
|
+
noUnknownPathPrefixes: [""]
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
} catch (error) {
|
|
543
|
+
if (error instanceof yup.ValidationError) {
|
|
544
|
+
return Result.error(error.message);
|
|
545
|
+
}
|
|
546
|
+
throw error;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
return Result.ok(null);
|
|
550
|
+
}
|
|
551
|
+
async function assertNoConfigOverrideErrors(schema, config, options = {}) {
|
|
552
|
+
const res = await getConfigOverrideErrors(schema, config, options);
|
|
553
|
+
if (res.status === "error") throw new StackAssertionError(`Config override is invalid \u2014 at a place where it should have already been validated! ${res.error}`, { options, config, schema });
|
|
554
|
+
}
|
|
555
|
+
typeAssertIs()();
|
|
556
|
+
typeAssertExtends()();
|
|
557
|
+
typeAssertExtends()();
|
|
558
|
+
async function getIncompleteConfigWarnings(schema, incompleteConfig) {
|
|
559
|
+
await assertNoConfigOverrideErrors(schema, incompleteConfig, { allowPropertiesThatCanNoLongerBeOverridden: true });
|
|
560
|
+
let normalized;
|
|
561
|
+
try {
|
|
562
|
+
normalized = normalize(incompleteConfig, { onDotIntoNull: "empty-object" });
|
|
563
|
+
} catch (error) {
|
|
564
|
+
if (error instanceof NormalizationError) {
|
|
565
|
+
return Result.error(`Config is not normalizable. ` + error.message);
|
|
566
|
+
}
|
|
567
|
+
throw error;
|
|
568
|
+
}
|
|
569
|
+
try {
|
|
570
|
+
await schema.validate(normalized, {
|
|
571
|
+
strict: true,
|
|
572
|
+
context: {
|
|
573
|
+
noUnknownPathPrefixes: [""]
|
|
574
|
+
}
|
|
575
|
+
});
|
|
576
|
+
return Result.ok(null);
|
|
577
|
+
} catch (error) {
|
|
578
|
+
if (error instanceof yup.ValidationError) {
|
|
579
|
+
return Result.error(error.message);
|
|
580
|
+
}
|
|
581
|
+
throw error;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
typeAssertExtends()();
|
|
585
|
+
typeAssertExtends()();
|
|
586
|
+
typeAssertExtends()();
|
|
587
|
+
typeAssertExtends()();
|
|
588
|
+
typeAssert()();
|
|
589
|
+
typeAssert()();
|
|
590
|
+
typeAssertExtends()();
|
|
216
591
|
export {
|
|
217
|
-
|
|
218
|
-
|
|
592
|
+
applyBranchDefaults,
|
|
593
|
+
applyEnvironmentDefaults,
|
|
594
|
+
applyOrganizationDefaults,
|
|
595
|
+
applyProjectDefaults,
|
|
596
|
+
assertNoConfigOverrideErrors,
|
|
219
597
|
branchConfigSchema,
|
|
220
598
|
configLevels,
|
|
221
|
-
environmentConfigDefaults,
|
|
222
599
|
environmentConfigSchema,
|
|
223
|
-
|
|
600
|
+
getConfigOverrideErrors,
|
|
601
|
+
getIncompleteConfigWarnings,
|
|
602
|
+
migrateConfigOverride,
|
|
224
603
|
organizationConfigSchema,
|
|
225
|
-
|
|
226
|
-
|
|
604
|
+
projectConfigSchema,
|
|
605
|
+
sanitizeBranchConfig,
|
|
606
|
+
sanitizeEnvironmentConfig,
|
|
607
|
+
sanitizeOrganizationConfig,
|
|
608
|
+
sanitizeProjectConfig
|
|
227
609
|
};
|
|
228
610
|
//# sourceMappingURL=schema.js.map
|