@lukoweb/apitogo 0.1.53 → 0.1.54
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/dist/cli/cli.js +96 -11
- package/dist/declarations/config/apitogo-config-core.d.ts +14 -4
- package/dist/declarations/config/local-manifest.d.ts +15 -1
- package/dist/declarations/config/validators/ZudokuConfig.d.ts +34 -2
- package/dist/declarations/lib/authentication/providers/dev-portal-auth-pages.d.ts +15 -0
- package/dist/declarations/lib/authentication/providers/dev-portal-constants.d.ts +19 -1
- package/dist/declarations/lib/authentication/providers/dev-portal-utils.d.ts +5 -1
- package/dist/declarations/lib/authentication/providers/dev-portal.d.ts +5 -0
- package/dist/flat-config.d.ts +17 -1
- package/package.json +1 -1
- package/src/config/apitogo-config-core.ts +127 -11
- package/src/config/apitogo-config-loader.node.ts +28 -8
- package/src/config/local-manifest.ts +32 -1
- package/src/config/validators/ZudokuConfig.ts +25 -1
- package/src/lib/authentication/providers/dev-portal-auth-pages.tsx +439 -0
- package/src/lib/authentication/providers/dev-portal-constants.ts +15 -1
- package/src/lib/authentication/providers/dev-portal-utils.ts +117 -2
- package/src/lib/authentication/providers/dev-portal.tsx +41 -6
package/dist/cli/cli.js
CHANGED
|
@@ -393,6 +393,7 @@ function normalizeApitogoConfig(config2) {
|
|
|
393
393
|
delete normalized.projectName;
|
|
394
394
|
migratePlanCatalog(normalized);
|
|
395
395
|
syncBillingEnabled(normalized);
|
|
396
|
+
syncAuthentication(normalized);
|
|
396
397
|
return normalized;
|
|
397
398
|
}
|
|
398
399
|
function isBillingEnabled(config2) {
|
|
@@ -402,6 +403,63 @@ function isBillingEnabled(config2) {
|
|
|
402
403
|
);
|
|
403
404
|
return plans?.enabled === true;
|
|
404
405
|
}
|
|
406
|
+
function isUserPanelEnabled(normalized) {
|
|
407
|
+
const modules = asRecord(normalized.modules);
|
|
408
|
+
const userPanel = asRecord(modules?.userPanel);
|
|
409
|
+
if (userPanel?.enabled === true) {
|
|
410
|
+
return true;
|
|
411
|
+
}
|
|
412
|
+
const dashboard = asRecord(userPanel?.dashboard);
|
|
413
|
+
const userManagement = asRecord(userPanel?.userManagement);
|
|
414
|
+
const apiKeys = asRecord(userPanel?.apiKeys);
|
|
415
|
+
const plans = asRecord(userPanel?.plans);
|
|
416
|
+
return dashboard?.enabled === true || userManagement?.enabled === true || apiKeys?.enabled === true || plans?.enabled === true;
|
|
417
|
+
}
|
|
418
|
+
function syncAuthentication(normalized) {
|
|
419
|
+
const userPanelEnabled = isUserPanelEnabled(normalized);
|
|
420
|
+
const authentication = asRecord(normalized.authentication);
|
|
421
|
+
if (!userPanelEnabled && !authentication) {
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
const auth = authentication ?? {};
|
|
425
|
+
auth.enabled = userPanelEnabled;
|
|
426
|
+
auth.type = "dev-portal";
|
|
427
|
+
if (userPanelEnabled) {
|
|
428
|
+
const native = asRecord(auth.native) ?? {};
|
|
429
|
+
if (native.enabled === void 0) {
|
|
430
|
+
native.enabled = true;
|
|
431
|
+
}
|
|
432
|
+
auth.native = native;
|
|
433
|
+
if (!Array.isArray(auth.providers)) {
|
|
434
|
+
auth.providers = [];
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
normalized.authentication = auth;
|
|
438
|
+
}
|
|
439
|
+
function stripAuthenticationSecrets(authentication) {
|
|
440
|
+
const {
|
|
441
|
+
gateway: _gateway,
|
|
442
|
+
oidc: _oidc,
|
|
443
|
+
stripe: _stripe,
|
|
444
|
+
type: _type,
|
|
445
|
+
email,
|
|
446
|
+
providers,
|
|
447
|
+
...authPublic
|
|
448
|
+
} = authentication;
|
|
449
|
+
const emailRecord = asRecord(email);
|
|
450
|
+
if (emailRecord) {
|
|
451
|
+
const { connectionString: _connectionString, ...emailPublic } = emailRecord;
|
|
452
|
+
authPublic.email = emailPublic;
|
|
453
|
+
}
|
|
454
|
+
if (Array.isArray(providers)) {
|
|
455
|
+
authPublic.providers = providers.map((entry) => {
|
|
456
|
+
const provider = asRecord(entry) ?? {};
|
|
457
|
+
const { clientSecret: _clientSecret, ...providerPublic } = provider;
|
|
458
|
+
return providerPublic;
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
return authPublic;
|
|
462
|
+
}
|
|
405
463
|
function syncBillingEnabled(normalized) {
|
|
406
464
|
const legacyPricing = asRecord(normalized.pricing);
|
|
407
465
|
const modules = ensureModules(normalized);
|
|
@@ -430,13 +488,7 @@ function deriveManifestFields(config2) {
|
|
|
430
488
|
if (key === "authentication") {
|
|
431
489
|
const authentication2 = asRecord(normalized.authentication);
|
|
432
490
|
if (authentication2) {
|
|
433
|
-
|
|
434
|
-
gateway: _gateway,
|
|
435
|
-
oidc: _oidc,
|
|
436
|
-
stripe: _stripe,
|
|
437
|
-
...authPublic
|
|
438
|
-
} = authentication2;
|
|
439
|
-
manifest.authentication = authPublic;
|
|
491
|
+
manifest.authentication = stripAuthenticationSecrets(authentication2);
|
|
440
492
|
}
|
|
441
493
|
continue;
|
|
442
494
|
}
|
|
@@ -640,8 +692,23 @@ var init_local_manifest = __esm({
|
|
|
640
692
|
}).optional(),
|
|
641
693
|
authentication: z3.object({
|
|
642
694
|
enabled: z3.boolean().optional(),
|
|
643
|
-
|
|
644
|
-
|
|
695
|
+
apiBaseUrl: z3.string().optional(),
|
|
696
|
+
native: z3.object({
|
|
697
|
+
enabled: z3.boolean().optional()
|
|
698
|
+
}).optional(),
|
|
699
|
+
email: z3.object({
|
|
700
|
+
provider: z3.string().optional(),
|
|
701
|
+
from: z3.string().optional()
|
|
702
|
+
}).optional(),
|
|
703
|
+
providers: z3.array(
|
|
704
|
+
z3.object({
|
|
705
|
+
id: z3.string().min(1),
|
|
706
|
+
displayName: z3.string().optional(),
|
|
707
|
+
authority: z3.string().optional(),
|
|
708
|
+
clientId: z3.string().optional(),
|
|
709
|
+
scopes: z3.string().optional()
|
|
710
|
+
})
|
|
711
|
+
).optional()
|
|
645
712
|
}).optional(),
|
|
646
713
|
plans: z3.array(ManifestPlanInputSchema).optional(),
|
|
647
714
|
backend: z3.object({
|
|
@@ -4094,8 +4161,26 @@ var init_ZudokuConfig = __esm({
|
|
|
4094
4161
|
redirectToAfterSignOut: z9.string().optional()
|
|
4095
4162
|
}),
|
|
4096
4163
|
z9.object({
|
|
4097
|
-
type: z9.literal("dev-portal"),
|
|
4164
|
+
type: z9.literal("dev-portal").optional().default("dev-portal"),
|
|
4098
4165
|
apiBaseUrl: z9.string().optional(),
|
|
4166
|
+
native: z9.object({
|
|
4167
|
+
enabled: z9.boolean().optional()
|
|
4168
|
+
}).optional(),
|
|
4169
|
+
email: z9.object({
|
|
4170
|
+
provider: z9.string().optional(),
|
|
4171
|
+
from: z9.string().optional(),
|
|
4172
|
+
connectionString: z9.string().optional()
|
|
4173
|
+
}).optional(),
|
|
4174
|
+
providers: z9.array(
|
|
4175
|
+
z9.object({
|
|
4176
|
+
id: z9.string().min(1),
|
|
4177
|
+
displayName: z9.string().optional(),
|
|
4178
|
+
authority: z9.string().optional(),
|
|
4179
|
+
clientId: z9.string().optional(),
|
|
4180
|
+
clientSecret: z9.string().optional(),
|
|
4181
|
+
scopes: z9.string().optional()
|
|
4182
|
+
})
|
|
4183
|
+
).optional(),
|
|
4099
4184
|
redirectToAfterSignUp: z9.string().optional(),
|
|
4100
4185
|
redirectToAfterSignIn: z9.string().optional(),
|
|
4101
4186
|
redirectToAfterSignOut: z9.string().optional()
|
|
@@ -4716,7 +4801,7 @@ import {
|
|
|
4716
4801
|
// package.json
|
|
4717
4802
|
var package_default = {
|
|
4718
4803
|
name: "@lukoweb/apitogo",
|
|
4719
|
-
version: "0.1.
|
|
4804
|
+
version: "0.1.54",
|
|
4720
4805
|
type: "module",
|
|
4721
4806
|
sideEffects: [
|
|
4722
4807
|
"**/*.css",
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
export declare const APITOGO_CONFIG_FILENAME = "apitogo.config.json";
|
|
2
2
|
export type ApitogoJsonConfig = Record<string, unknown>;
|
|
3
|
+
export type AuthProviderPublicConfig = {
|
|
4
|
+
id: string;
|
|
5
|
+
displayName?: string;
|
|
6
|
+
authority?: string;
|
|
7
|
+
clientId?: string;
|
|
8
|
+
scopes?: string;
|
|
9
|
+
};
|
|
3
10
|
export type AuthenticationSecrets = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
clientId?: string;
|
|
7
|
-
clientSecret?: string;
|
|
11
|
+
email?: {
|
|
12
|
+
connectionString?: string;
|
|
8
13
|
};
|
|
14
|
+
providers?: Record<string, {
|
|
15
|
+
clientSecret?: string;
|
|
16
|
+
}>;
|
|
9
17
|
stripe?: {
|
|
10
18
|
secretKey?: string;
|
|
11
19
|
webhookSecret?: string;
|
|
@@ -18,6 +26,8 @@ type PlanCatalogItem = Record<string, unknown> & {
|
|
|
18
26
|
export declare function readPlanCatalogItems(config: ApitogoJsonConfig): PlanCatalogItem[];
|
|
19
27
|
export declare function normalizeApitogoConfig(config: ApitogoJsonConfig): ApitogoJsonConfig;
|
|
20
28
|
export declare function isBillingEnabled(config: ApitogoJsonConfig): boolean;
|
|
29
|
+
export declare function readAuthProviders(config: ApitogoJsonConfig): AuthProviderPublicConfig[];
|
|
30
|
+
export declare function isNativeAuthEnabled(config: ApitogoJsonConfig): boolean;
|
|
21
31
|
export declare function deriveManifestFields(config: ApitogoJsonConfig): ApitogoJsonConfig;
|
|
22
32
|
export declare function extractManifest(config: ApitogoJsonConfig | null | undefined): ApitogoJsonConfig | null;
|
|
23
33
|
export declare function extractSiteConfig(config: ApitogoJsonConfig | null | undefined): ApitogoJsonConfig;
|
|
@@ -35,8 +35,21 @@ export declare const DevPortalLocalManifestSchema: z.ZodObject<{
|
|
|
35
35
|
}, z.core.$strip>>;
|
|
36
36
|
authentication: z.ZodOptional<z.ZodObject<{
|
|
37
37
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
38
|
-
type: z.ZodOptional<z.ZodString>;
|
|
39
38
|
apiBaseUrl: z.ZodOptional<z.ZodString>;
|
|
39
|
+
native: z.ZodOptional<z.ZodObject<{
|
|
40
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
41
|
+
}, z.core.$strip>>;
|
|
42
|
+
email: z.ZodOptional<z.ZodObject<{
|
|
43
|
+
provider: z.ZodOptional<z.ZodString>;
|
|
44
|
+
from: z.ZodOptional<z.ZodString>;
|
|
45
|
+
}, z.core.$strip>>;
|
|
46
|
+
providers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
47
|
+
id: z.ZodString;
|
|
48
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
49
|
+
authority: z.ZodOptional<z.ZodString>;
|
|
50
|
+
clientId: z.ZodOptional<z.ZodString>;
|
|
51
|
+
scopes: z.ZodOptional<z.ZodString>;
|
|
52
|
+
}, z.core.$strip>>>;
|
|
40
53
|
}, z.core.$strip>>;
|
|
41
54
|
plans: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
42
55
|
sku: z.ZodString;
|
|
@@ -91,6 +104,7 @@ export type DevPortalPreviewPlanCatalog = {
|
|
|
91
104
|
};
|
|
92
105
|
export declare function isPricingEnabled(manifest: DevPortalLocalManifest | null | undefined): boolean;
|
|
93
106
|
export declare function isAuthenticationEnabled(manifest: DevPortalLocalManifest | null | undefined): boolean;
|
|
107
|
+
export declare function isNativeAuthEnabledInManifest(manifest: DevPortalLocalManifest | null | undefined): boolean;
|
|
94
108
|
export declare function manifestToPreviewCatalog(manifest: DevPortalLocalManifest | null | undefined): DevPortalPreviewPlanCatalog;
|
|
95
109
|
export declare function normalizeBillingPeriod(period?: string): string;
|
|
96
110
|
export declare function plansToPreviewCatalog(plans: ManifestPlanInput[] | undefined): Pick<DevPortalPreviewPlanCatalog, "plans">;
|
|
@@ -367,8 +367,24 @@ declare const AuthenticationSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
367
367
|
redirectToAfterSignIn: z.ZodOptional<z.ZodString>;
|
|
368
368
|
redirectToAfterSignOut: z.ZodOptional<z.ZodString>;
|
|
369
369
|
}, z.core.$strip>, z.ZodObject<{
|
|
370
|
-
type: z.ZodLiteral<"dev-portal"
|
|
370
|
+
type: z.ZodDefault<z.ZodOptional<z.ZodLiteral<"dev-portal">>>;
|
|
371
371
|
apiBaseUrl: z.ZodOptional<z.ZodString>;
|
|
372
|
+
native: z.ZodOptional<z.ZodObject<{
|
|
373
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
374
|
+
}, z.core.$strip>>;
|
|
375
|
+
email: z.ZodOptional<z.ZodObject<{
|
|
376
|
+
provider: z.ZodOptional<z.ZodString>;
|
|
377
|
+
from: z.ZodOptional<z.ZodString>;
|
|
378
|
+
connectionString: z.ZodOptional<z.ZodString>;
|
|
379
|
+
}, z.core.$strip>>;
|
|
380
|
+
providers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
381
|
+
id: z.ZodString;
|
|
382
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
383
|
+
authority: z.ZodOptional<z.ZodString>;
|
|
384
|
+
clientId: z.ZodOptional<z.ZodString>;
|
|
385
|
+
clientSecret: z.ZodOptional<z.ZodString>;
|
|
386
|
+
scopes: z.ZodOptional<z.ZodString>;
|
|
387
|
+
}, z.core.$strip>>>;
|
|
372
388
|
redirectToAfterSignUp: z.ZodOptional<z.ZodString>;
|
|
373
389
|
redirectToAfterSignIn: z.ZodOptional<z.ZodString>;
|
|
374
390
|
redirectToAfterSignOut: z.ZodOptional<z.ZodString>;
|
|
@@ -6771,8 +6787,24 @@ export declare const ZudokuConfig: z.ZodObject<{
|
|
|
6771
6787
|
redirectToAfterSignIn: z.ZodOptional<z.ZodString>;
|
|
6772
6788
|
redirectToAfterSignOut: z.ZodOptional<z.ZodString>;
|
|
6773
6789
|
}, z.core.$strip>, z.ZodObject<{
|
|
6774
|
-
type: z.ZodLiteral<"dev-portal"
|
|
6790
|
+
type: z.ZodDefault<z.ZodOptional<z.ZodLiteral<"dev-portal">>>;
|
|
6775
6791
|
apiBaseUrl: z.ZodOptional<z.ZodString>;
|
|
6792
|
+
native: z.ZodOptional<z.ZodObject<{
|
|
6793
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
6794
|
+
}, z.core.$strip>>;
|
|
6795
|
+
email: z.ZodOptional<z.ZodObject<{
|
|
6796
|
+
provider: z.ZodOptional<z.ZodString>;
|
|
6797
|
+
from: z.ZodOptional<z.ZodString>;
|
|
6798
|
+
connectionString: z.ZodOptional<z.ZodString>;
|
|
6799
|
+
}, z.core.$strip>>;
|
|
6800
|
+
providers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
6801
|
+
id: z.ZodString;
|
|
6802
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
6803
|
+
authority: z.ZodOptional<z.ZodString>;
|
|
6804
|
+
clientId: z.ZodOptional<z.ZodString>;
|
|
6805
|
+
clientSecret: z.ZodOptional<z.ZodString>;
|
|
6806
|
+
scopes: z.ZodOptional<z.ZodString>;
|
|
6807
|
+
}, z.core.$strip>>>;
|
|
6776
6808
|
redirectToAfterSignUp: z.ZodOptional<z.ZodString>;
|
|
6777
6809
|
redirectToAfterSignIn: z.ZodOptional<z.ZodString>;
|
|
6778
6810
|
redirectToAfterSignOut: z.ZodOptional<z.ZodString>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare function DevPortalLoginPage({ apiBaseUrl, }: {
|
|
2
|
+
apiBaseUrl?: string;
|
|
3
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
export declare function DevPortalRegisterPage({ apiBaseUrl, }: {
|
|
5
|
+
apiBaseUrl?: string;
|
|
6
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare function DevPortalVerifyEmailPage({ apiBaseUrl }: {
|
|
8
|
+
apiBaseUrl?: string;
|
|
9
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare function DevPortalForgotPasswordPage({ apiBaseUrl }: {
|
|
11
|
+
apiBaseUrl?: string;
|
|
12
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare function DevPortalResetPasswordPage({ apiBaseUrl }: {
|
|
14
|
+
apiBaseUrl?: string;
|
|
15
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -14,5 +14,23 @@ export type EndUserMeResponse = {
|
|
|
14
14
|
};
|
|
15
15
|
export type DevPortalAuthStatusResponse = {
|
|
16
16
|
available: boolean;
|
|
17
|
-
|
|
17
|
+
nativeEnabled?: boolean;
|
|
18
|
+
oidcConfigured?: boolean;
|
|
19
|
+
providerCount?: number;
|
|
20
|
+
};
|
|
21
|
+
export type DevPortalAuthConfigResponse = {
|
|
22
|
+
native: {
|
|
23
|
+
enabled: boolean;
|
|
24
|
+
};
|
|
25
|
+
email?: {
|
|
26
|
+
provider: string;
|
|
27
|
+
from: string;
|
|
28
|
+
} | null;
|
|
29
|
+
providers: Array<{
|
|
30
|
+
id: string;
|
|
31
|
+
displayName: string;
|
|
32
|
+
authority: string;
|
|
33
|
+
clientId: string;
|
|
34
|
+
scopes: string[];
|
|
35
|
+
}>;
|
|
18
36
|
};
|
|
@@ -3,7 +3,11 @@ import { type EndUserMeResponse } from "./dev-portal-constants.js";
|
|
|
3
3
|
export declare function resolveDevPortalApiBaseUrl(config: Pick<DevPortalAuthenticationConfig, "apiBaseUrl">): string | undefined;
|
|
4
4
|
export declare function isPlaceholderDevPortalApiUrl(apiBaseUrl: string | undefined): boolean;
|
|
5
5
|
export declare function toAbsoluteReturnUrl(pathOrUrl: string): string;
|
|
6
|
-
export declare function
|
|
6
|
+
export declare function buildDevPortalOidcChallengeUrl(apiBaseUrl: string, providerId: string, returnUrl: string): string;
|
|
7
7
|
export declare function buildDevPortalLogoutUrl(apiBaseUrl: string, returnUrl: string): string;
|
|
8
|
+
export declare function normalizeDevPortalAuthConfig(raw: unknown): import("./dev-portal-constants.js").DevPortalAuthConfigResponse;
|
|
9
|
+
export declare function isNativeAuthEnabled(config: import("./dev-portal-constants.js").DevPortalAuthConfigResponse | null | undefined): boolean;
|
|
10
|
+
export declare function fetchDevPortalAuthConfig(apiBaseUrl: string, fetchImpl?: typeof fetch): Promise<import("./dev-portal-constants.js").DevPortalAuthConfigResponse>;
|
|
11
|
+
export declare function postDevPortalAuth<T>(apiBaseUrl: string, path: string, body: unknown, fetchImpl?: typeof fetch): Promise<T>;
|
|
8
12
|
export declare function probeDevPortalBackend(apiBaseUrl: string, fetchImpl?: typeof fetch): Promise<boolean>;
|
|
9
13
|
export declare function mapEndUserMeToProfile(me: EndUserMeResponse): import("../state.js").UserProfile;
|
|
@@ -21,7 +21,12 @@ export declare class DevPortalAuthenticationProvider extends CoreAuthenticationP
|
|
|
21
21
|
private backendAvailable;
|
|
22
22
|
private refreshGeneration;
|
|
23
23
|
private refreshInFlight;
|
|
24
|
+
private authConfigNativeEnabled;
|
|
24
25
|
constructor({ apiBaseUrl, redirectToAfterSignIn, redirectToAfterSignUp, redirectToAfterSignOut, }: DevPortalAuthenticationConfig);
|
|
26
|
+
getRoutes(): {
|
|
27
|
+
path: string;
|
|
28
|
+
element: import("react/jsx-runtime").JSX.Element;
|
|
29
|
+
}[];
|
|
25
30
|
initialize(_context: ZudokuContext): Promise<void>;
|
|
26
31
|
onPageLoad: () => Promise<void>;
|
|
27
32
|
private syncBackendAvailability;
|
package/dist/flat-config.d.ts
CHANGED
|
@@ -319,8 +319,24 @@ export interface FlatZudokuConfig {
|
|
|
319
319
|
redirectToAfterSignIn?: string
|
|
320
320
|
redirectToAfterSignOut?: string
|
|
321
321
|
} | {
|
|
322
|
-
type
|
|
322
|
+
type?: "dev-portal"
|
|
323
323
|
apiBaseUrl?: string
|
|
324
|
+
native?: {
|
|
325
|
+
enabled?: boolean
|
|
326
|
+
}
|
|
327
|
+
email?: {
|
|
328
|
+
provider?: string
|
|
329
|
+
from?: string
|
|
330
|
+
connectionString?: string
|
|
331
|
+
}
|
|
332
|
+
providers?: {
|
|
333
|
+
id: string
|
|
334
|
+
displayName?: string
|
|
335
|
+
authority?: string
|
|
336
|
+
clientId?: string
|
|
337
|
+
clientSecret?: string
|
|
338
|
+
scopes?: string
|
|
339
|
+
}[]
|
|
324
340
|
redirectToAfterSignUp?: string
|
|
325
341
|
redirectToAfterSignIn?: string
|
|
326
342
|
redirectToAfterSignOut?: string
|
package/package.json
CHANGED
|
@@ -34,12 +34,20 @@ const SITE_CONFIG_KEYS = [
|
|
|
34
34
|
|
|
35
35
|
export type ApitogoJsonConfig = Record<string, unknown>;
|
|
36
36
|
|
|
37
|
+
export type AuthProviderPublicConfig = {
|
|
38
|
+
id: string;
|
|
39
|
+
displayName?: string;
|
|
40
|
+
authority?: string;
|
|
41
|
+
clientId?: string;
|
|
42
|
+
scopes?: string;
|
|
43
|
+
};
|
|
44
|
+
|
|
37
45
|
export type AuthenticationSecrets = {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
clientId?: string;
|
|
41
|
-
clientSecret?: string;
|
|
46
|
+
email?: {
|
|
47
|
+
connectionString?: string;
|
|
42
48
|
};
|
|
49
|
+
/** Provider secrets keyed by provider `id` (from env: `authentication__providers__{id}__clientSecret`). */
|
|
50
|
+
providers?: Record<string, { clientSecret?: string }>;
|
|
43
51
|
stripe?: {
|
|
44
52
|
secretKey?: string;
|
|
45
53
|
webhookSecret?: string;
|
|
@@ -351,6 +359,7 @@ export function normalizeApitogoConfig(
|
|
|
351
359
|
|
|
352
360
|
migratePlanCatalog(normalized);
|
|
353
361
|
syncBillingEnabled(normalized);
|
|
362
|
+
syncAuthentication(normalized);
|
|
354
363
|
|
|
355
364
|
return normalized;
|
|
356
365
|
}
|
|
@@ -364,6 +373,119 @@ export function isBillingEnabled(config: ApitogoJsonConfig): boolean {
|
|
|
364
373
|
return plans?.enabled === true;
|
|
365
374
|
}
|
|
366
375
|
|
|
376
|
+
function isUserPanelEnabled(normalized: ApitogoJsonConfig): boolean {
|
|
377
|
+
const modules = asRecord(normalized.modules);
|
|
378
|
+
const userPanel = asRecord(modules?.userPanel);
|
|
379
|
+
if (userPanel?.enabled === true) {
|
|
380
|
+
return true;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const dashboard = asRecord(userPanel?.dashboard);
|
|
384
|
+
const userManagement = asRecord(userPanel?.userManagement);
|
|
385
|
+
const apiKeys = asRecord(userPanel?.apiKeys);
|
|
386
|
+
const plans = asRecord(userPanel?.plans);
|
|
387
|
+
|
|
388
|
+
return (
|
|
389
|
+
dashboard?.enabled === true ||
|
|
390
|
+
userManagement?.enabled === true ||
|
|
391
|
+
apiKeys?.enabled === true ||
|
|
392
|
+
plans?.enabled === true
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/** Read public OIDC provider entries from `authentication.providers` array. */
|
|
397
|
+
export function readAuthProviders(
|
|
398
|
+
config: ApitogoJsonConfig,
|
|
399
|
+
): AuthProviderPublicConfig[] {
|
|
400
|
+
const normalized = normalizeApitogoConfig(config);
|
|
401
|
+
const authentication = asRecord(normalized.authentication);
|
|
402
|
+
const providers = authentication?.providers;
|
|
403
|
+
if (!Array.isArray(providers)) {
|
|
404
|
+
return [];
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return providers
|
|
408
|
+
.map((entry) => asRecord(entry))
|
|
409
|
+
.filter((entry): entry is Record<string, unknown> => entry !== undefined)
|
|
410
|
+
.filter((entry) => typeof entry.id === "string" && entry.id.trim())
|
|
411
|
+
.map((entry) => ({
|
|
412
|
+
id: String(entry.id).trim(),
|
|
413
|
+
displayName:
|
|
414
|
+
typeof entry.displayName === "string" ? entry.displayName : undefined,
|
|
415
|
+
authority:
|
|
416
|
+
typeof entry.authority === "string" ? entry.authority : undefined,
|
|
417
|
+
clientId: typeof entry.clientId === "string" ? entry.clientId : undefined,
|
|
418
|
+
scopes: typeof entry.scopes === "string" ? entry.scopes : undefined,
|
|
419
|
+
}));
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
export function isNativeAuthEnabled(config: ApitogoJsonConfig): boolean {
|
|
423
|
+
const normalized = normalizeApitogoConfig(config);
|
|
424
|
+
if (!isUserPanelEnabled(normalized)) {
|
|
425
|
+
return false;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const native = asRecord(asRecord(normalized.authentication)?.native);
|
|
429
|
+
return native?.enabled !== false;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function syncAuthentication(normalized: ApitogoJsonConfig): void {
|
|
433
|
+
const userPanelEnabled = isUserPanelEnabled(normalized);
|
|
434
|
+
const authentication = asRecord(normalized.authentication);
|
|
435
|
+
|
|
436
|
+
if (!userPanelEnabled && !authentication) {
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const auth = authentication ?? {};
|
|
441
|
+
auth.enabled = userPanelEnabled;
|
|
442
|
+
auth.type = "dev-portal";
|
|
443
|
+
|
|
444
|
+
if (userPanelEnabled) {
|
|
445
|
+
const native = asRecord(auth.native) ?? {};
|
|
446
|
+
if (native.enabled === undefined) {
|
|
447
|
+
native.enabled = true;
|
|
448
|
+
}
|
|
449
|
+
auth.native = native;
|
|
450
|
+
|
|
451
|
+
if (!Array.isArray(auth.providers)) {
|
|
452
|
+
auth.providers = [];
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
normalized.authentication = auth;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function stripAuthenticationSecrets(
|
|
460
|
+
authentication: Record<string, unknown>,
|
|
461
|
+
): Record<string, unknown> {
|
|
462
|
+
const {
|
|
463
|
+
gateway: _gateway,
|
|
464
|
+
oidc: _oidc,
|
|
465
|
+
stripe: _stripe,
|
|
466
|
+
type: _type,
|
|
467
|
+
email,
|
|
468
|
+
providers,
|
|
469
|
+
...authPublic
|
|
470
|
+
} = authentication;
|
|
471
|
+
|
|
472
|
+
const emailRecord = asRecord(email);
|
|
473
|
+
if (emailRecord) {
|
|
474
|
+
const { connectionString: _connectionString, ...emailPublic } = emailRecord;
|
|
475
|
+
authPublic.email = emailPublic;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (Array.isArray(providers)) {
|
|
479
|
+
authPublic.providers = providers.map((entry) => {
|
|
480
|
+
const provider = asRecord(entry) ?? {};
|
|
481
|
+
const { clientSecret: _clientSecret, ...providerPublic } = provider;
|
|
482
|
+
return providerPublic;
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
return authPublic;
|
|
487
|
+
}
|
|
488
|
+
|
|
367
489
|
function syncBillingEnabled(normalized: ApitogoJsonConfig): void {
|
|
368
490
|
const legacyPricing = asRecord(normalized.pricing);
|
|
369
491
|
const modules = ensureModules(normalized);
|
|
@@ -400,13 +522,7 @@ export function deriveManifestFields(
|
|
|
400
522
|
if (key === "authentication") {
|
|
401
523
|
const authentication = asRecord(normalized.authentication);
|
|
402
524
|
if (authentication) {
|
|
403
|
-
|
|
404
|
-
gateway: _gateway,
|
|
405
|
-
oidc: _oidc,
|
|
406
|
-
stripe: _stripe,
|
|
407
|
-
...authPublic
|
|
408
|
-
} = authentication;
|
|
409
|
-
manifest.authentication = authPublic;
|
|
525
|
+
manifest.authentication = stripAuthenticationSecrets(authentication);
|
|
410
526
|
}
|
|
411
527
|
continue;
|
|
412
528
|
}
|
|
@@ -36,19 +36,39 @@ export function readAuthenticationSecrets(
|
|
|
36
36
|
): AuthenticationSecrets {
|
|
37
37
|
const overrides = applyEnvOverrides({}, env);
|
|
38
38
|
const authentication = asRecord(overrides.authentication);
|
|
39
|
-
const
|
|
39
|
+
const email = asRecord(authentication?.email);
|
|
40
|
+
const providers = asRecord(authentication?.providers);
|
|
40
41
|
const stripe = asRecord(authentication?.stripe);
|
|
41
42
|
|
|
42
43
|
const secrets: AuthenticationSecrets = {};
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
|
|
45
|
+
if (email?.connectionString) {
|
|
46
|
+
secrets.email = {
|
|
47
|
+
connectionString:
|
|
48
|
+
typeof email.connectionString === "string"
|
|
49
|
+
? email.connectionString
|
|
50
|
+
: undefined,
|
|
50
51
|
};
|
|
51
52
|
}
|
|
53
|
+
|
|
54
|
+
if (providers) {
|
|
55
|
+
const providerSecrets: Record<string, { clientSecret?: string }> = {};
|
|
56
|
+
for (const [id, value] of Object.entries(providers)) {
|
|
57
|
+
const provider = asRecord(value);
|
|
58
|
+
if (provider?.clientSecret) {
|
|
59
|
+
providerSecrets[id] = {
|
|
60
|
+
clientSecret:
|
|
61
|
+
typeof provider.clientSecret === "string"
|
|
62
|
+
? provider.clientSecret
|
|
63
|
+
: undefined,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (Object.keys(providerSecrets).length > 0) {
|
|
68
|
+
secrets.providers = providerSecrets;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
52
72
|
if (stripe) {
|
|
53
73
|
secrets.stripe = {
|
|
54
74
|
secretKey:
|
|
@@ -55,8 +55,29 @@ export const DevPortalLocalManifestSchema = z.object({
|
|
|
55
55
|
authentication: z
|
|
56
56
|
.object({
|
|
57
57
|
enabled: z.boolean().optional(),
|
|
58
|
-
type: z.string().optional(),
|
|
59
58
|
apiBaseUrl: z.string().optional(),
|
|
59
|
+
native: z
|
|
60
|
+
.object({
|
|
61
|
+
enabled: z.boolean().optional(),
|
|
62
|
+
})
|
|
63
|
+
.optional(),
|
|
64
|
+
email: z
|
|
65
|
+
.object({
|
|
66
|
+
provider: z.string().optional(),
|
|
67
|
+
from: z.string().optional(),
|
|
68
|
+
})
|
|
69
|
+
.optional(),
|
|
70
|
+
providers: z
|
|
71
|
+
.array(
|
|
72
|
+
z.object({
|
|
73
|
+
id: z.string().min(1),
|
|
74
|
+
displayName: z.string().optional(),
|
|
75
|
+
authority: z.string().optional(),
|
|
76
|
+
clientId: z.string().optional(),
|
|
77
|
+
scopes: z.string().optional(),
|
|
78
|
+
}),
|
|
79
|
+
)
|
|
80
|
+
.optional(),
|
|
60
81
|
})
|
|
61
82
|
.optional(),
|
|
62
83
|
plans: z.array(ManifestPlanInputSchema).optional(),
|
|
@@ -116,6 +137,16 @@ export function isAuthenticationEnabled(
|
|
|
116
137
|
return manifest?.authentication?.enabled === true;
|
|
117
138
|
}
|
|
118
139
|
|
|
140
|
+
export function isNativeAuthEnabledInManifest(
|
|
141
|
+
manifest: DevPortalLocalManifest | null | undefined,
|
|
142
|
+
): boolean {
|
|
143
|
+
if (!isAuthenticationEnabled(manifest)) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return manifest?.authentication?.native?.enabled !== false;
|
|
148
|
+
}
|
|
149
|
+
|
|
119
150
|
export function manifestToPreviewCatalog(
|
|
120
151
|
manifest: DevPortalLocalManifest | null | undefined,
|
|
121
152
|
): DevPortalPreviewPlanCatalog {
|
|
@@ -492,8 +492,32 @@ const AuthenticationSchema = z.discriminatedUnion("type", [
|
|
|
492
492
|
redirectToAfterSignOut: z.string().optional(),
|
|
493
493
|
}),
|
|
494
494
|
z.object({
|
|
495
|
-
type: z.literal("dev-portal"),
|
|
495
|
+
type: z.literal("dev-portal").optional().default("dev-portal"),
|
|
496
496
|
apiBaseUrl: z.string().optional(),
|
|
497
|
+
native: z
|
|
498
|
+
.object({
|
|
499
|
+
enabled: z.boolean().optional(),
|
|
500
|
+
})
|
|
501
|
+
.optional(),
|
|
502
|
+
email: z
|
|
503
|
+
.object({
|
|
504
|
+
provider: z.string().optional(),
|
|
505
|
+
from: z.string().optional(),
|
|
506
|
+
connectionString: z.string().optional(),
|
|
507
|
+
})
|
|
508
|
+
.optional(),
|
|
509
|
+
providers: z
|
|
510
|
+
.array(
|
|
511
|
+
z.object({
|
|
512
|
+
id: z.string().min(1),
|
|
513
|
+
displayName: z.string().optional(),
|
|
514
|
+
authority: z.string().optional(),
|
|
515
|
+
clientId: z.string().optional(),
|
|
516
|
+
clientSecret: z.string().optional(),
|
|
517
|
+
scopes: z.string().optional(),
|
|
518
|
+
}),
|
|
519
|
+
)
|
|
520
|
+
.optional(),
|
|
497
521
|
redirectToAfterSignUp: z.string().optional(),
|
|
498
522
|
redirectToAfterSignIn: z.string().optional(),
|
|
499
523
|
redirectToAfterSignOut: z.string().optional(),
|