@dyrected/core 2.5.41 → 2.5.43

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/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { F as Field, B as Block, D as DyrectedConfig, C as CollectionConfig, A as AdminAuthConfig, P as PublicAdminAuthConfig, W as WorkflowConfig, a as AuthenticatedUser, b as WorkflowTransition, L as LifecycleEventName, c as LifecycleEvent, d as BaseDocument, H as HookRequestContext, G as GlobalConfig } from './index-DfkPT4NR.cjs';
2
- export { e as AccessFunction, f as AdminAuthAccessResolution, g as AdminAuthClaimMapping, h as AdminAuthProvider, i as AdminAuthProvisioningMode, j as AdminAuthResolveAccessArgs, k as AdminAuthResolvedIdentity, l as AdminConfig, m as AdminDashboardComponentSlots, n as AdminIconName, o as ArrayField, p as BaseAdminAuthProvider, q as BlocksField, r as BooleanField, s as CharacterLimitFieldConfig, t as CollectionAfterChangeHook, u as CollectionAfterDeleteHook, v as CollectionAfterReadHook, w as CollectionAfterTransitionHook, x as CollectionBeforeChangeHook, y as CollectionBeforeDeleteHook, z as CollectionBeforeReadHook, E as CollectionBeforeTransitionHook, I as CollectionListComponentSlots, J as CustomAdminAuthProvider, K as DatabaseAdapter, M as DateField, N as DateTimeField, O as DynamicOptionItem, Q as DynamicOptionsConfig, R as DynamicOptionsResolver, S as DynamicOptionsResolverArgs, T as EmailField, U as FieldAdminOnChangeHook, V as FieldAdminOnChangeHookArgs, X as FieldAdminOptionsHook, Y as FieldAdminOptionsHookArgs, Z as FieldAdminOptionsHookResult, _ as FieldAfterReadHook, $ as FieldAfterReadHookArgs, a0 as FieldBeforeChangeHook, a1 as FieldBeforeChangeHookArgs, a2 as FieldHook, a3 as FieldType, a4 as FileData, a5 as GlobalAfterChangeHook, a6 as GlobalAfterReadHook, a7 as GlobalBeforeChangeHook, a8 as GlobalBeforeReadHook, a9 as HookFunction, aa as IconField, ab as ImageField, ac as ImageService, ad as JoinField, ae as JsonField, af as LIFECYCLE_EVENT_NAMES, ag as LifecycleEventHandler, ah as MultiSelectField, ai as NumberField, aj as OIDCAdminAuthProvider, ak as ObjectField, al as PaginatedResult, am as PublicAdminAuthProvider, an as RadioField, ao as ReadonlyDatabaseAdapter, ap as RelationshipField, aq as RichTextField, ar as RowField, as as SelectField, at as StorageAdapter, au as TextField, av as TextareaField, aw as TimeField, ax as UploadConfig, ay as UrlField, az as WordLimitFieldConfig, aA as WorkflowMetadata, aB as WorkflowRole, aC as WorkflowState, aD as WorkflowTransitionContext } from './index-DfkPT4NR.cjs';
1
+ import { F as Field, B as Block, D as DyrectedConfig, C as CollectionConfig, A as AdminAuthConfig, P as PublicAdminAuthConfig, W as WorkflowConfig, a as AuthenticatedUser, b as WorkflowTransition, L as LifecycleEventName, c as LifecycleEvent, d as BaseDocument, H as HookRequestContext, G as GlobalConfig } from './app-config-2vF6W56z.cjs';
2
+ export { e as AccessFunction, f as AdminAuthAccessResolution, g as AdminAuthClaimMapping, h as AdminAuthProvider, i as AdminAuthProvisioningMode, j as AdminAuthResolveAccessArgs, k as AdminAuthResolvedIdentity, l as AdminConfig, m as AdminDashboardComponentSlots, n as AdminIconName, o as ArrayField, p as BaseAdminAuthProvider, q as BlocksField, r as BooleanField, s as CharacterLimitFieldConfig, t as CollectionAfterChangeHook, u as CollectionAfterDeleteHook, v as CollectionAfterReadHook, w as CollectionAfterTransitionHook, x as CollectionBeforeChangeHook, y as CollectionBeforeDeleteHook, z as CollectionBeforeReadHook, E as CollectionBeforeTransitionHook, I as CollectionListComponentSlots, J as CustomAdminAuthProvider, K as DatabaseAdapter, M as DateField, N as DateTimeField, O as DynamicOptionItem, Q as DynamicOptionsConfig, R as DynamicOptionsResolver, S as DynamicOptionsResolverArgs, T as EmailField, U as FieldAdminOnChangeHook, V as FieldAdminOnChangeHookArgs, X as FieldAdminOptionsHook, Y as FieldAdminOptionsHookArgs, Z as FieldAdminOptionsHookResult, _ as FieldAfterReadHook, $ as FieldAfterReadHookArgs, a0 as FieldBeforeChangeHook, a1 as FieldBeforeChangeHookArgs, a2 as FieldHook, a3 as FieldType, a4 as FileData, a5 as GlobalAfterChangeHook, a6 as GlobalAfterReadHook, a7 as GlobalBeforeChangeHook, a8 as GlobalBeforeReadHook, a9 as HookFunction, aa as IconField, ab as ImageField, ac as ImageService, ad as JoinField, ae as JsonField, af as LIFECYCLE_EVENT_NAMES, ag as LifecycleEventHandler, ah as MultiSelectField, ai as NumberField, aj as OIDCAdminAuthProvider, ak as ObjectField, al as PaginatedResult, am as PublicAdminAuthProvider, an as RadioField, ao as ReadonlyDatabaseAdapter, ap as RelationshipField, aq as RichTextField, ar as RowField, as as SelectField, at as StorageAdapter, au as TextField, av as TextareaField, aw as TimeField, ax as UploadConfig, ay as UrlField, az as WordLimitFieldConfig, aA as WorkflowMetadata, aB as WorkflowRole, aC as WorkflowState, aD as WorkflowTransitionContext } from './app-config-2vF6W56z.cjs';
3
3
  import 'lucide-react';
4
4
 
5
5
  type Prettify<T> = {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { F as Field, B as Block, D as DyrectedConfig, C as CollectionConfig, A as AdminAuthConfig, P as PublicAdminAuthConfig, W as WorkflowConfig, a as AuthenticatedUser, b as WorkflowTransition, L as LifecycleEventName, c as LifecycleEvent, d as BaseDocument, H as HookRequestContext, G as GlobalConfig } from './index-DfkPT4NR.js';
2
- export { e as AccessFunction, f as AdminAuthAccessResolution, g as AdminAuthClaimMapping, h as AdminAuthProvider, i as AdminAuthProvisioningMode, j as AdminAuthResolveAccessArgs, k as AdminAuthResolvedIdentity, l as AdminConfig, m as AdminDashboardComponentSlots, n as AdminIconName, o as ArrayField, p as BaseAdminAuthProvider, q as BlocksField, r as BooleanField, s as CharacterLimitFieldConfig, t as CollectionAfterChangeHook, u as CollectionAfterDeleteHook, v as CollectionAfterReadHook, w as CollectionAfterTransitionHook, x as CollectionBeforeChangeHook, y as CollectionBeforeDeleteHook, z as CollectionBeforeReadHook, E as CollectionBeforeTransitionHook, I as CollectionListComponentSlots, J as CustomAdminAuthProvider, K as DatabaseAdapter, M as DateField, N as DateTimeField, O as DynamicOptionItem, Q as DynamicOptionsConfig, R as DynamicOptionsResolver, S as DynamicOptionsResolverArgs, T as EmailField, U as FieldAdminOnChangeHook, V as FieldAdminOnChangeHookArgs, X as FieldAdminOptionsHook, Y as FieldAdminOptionsHookArgs, Z as FieldAdminOptionsHookResult, _ as FieldAfterReadHook, $ as FieldAfterReadHookArgs, a0 as FieldBeforeChangeHook, a1 as FieldBeforeChangeHookArgs, a2 as FieldHook, a3 as FieldType, a4 as FileData, a5 as GlobalAfterChangeHook, a6 as GlobalAfterReadHook, a7 as GlobalBeforeChangeHook, a8 as GlobalBeforeReadHook, a9 as HookFunction, aa as IconField, ab as ImageField, ac as ImageService, ad as JoinField, ae as JsonField, af as LIFECYCLE_EVENT_NAMES, ag as LifecycleEventHandler, ah as MultiSelectField, ai as NumberField, aj as OIDCAdminAuthProvider, ak as ObjectField, al as PaginatedResult, am as PublicAdminAuthProvider, an as RadioField, ao as ReadonlyDatabaseAdapter, ap as RelationshipField, aq as RichTextField, ar as RowField, as as SelectField, at as StorageAdapter, au as TextField, av as TextareaField, aw as TimeField, ax as UploadConfig, ay as UrlField, az as WordLimitFieldConfig, aA as WorkflowMetadata, aB as WorkflowRole, aC as WorkflowState, aD as WorkflowTransitionContext } from './index-DfkPT4NR.js';
1
+ import { F as Field, B as Block, D as DyrectedConfig, C as CollectionConfig, A as AdminAuthConfig, P as PublicAdminAuthConfig, W as WorkflowConfig, a as AuthenticatedUser, b as WorkflowTransition, L as LifecycleEventName, c as LifecycleEvent, d as BaseDocument, H as HookRequestContext, G as GlobalConfig } from './app-config-2vF6W56z.js';
2
+ export { e as AccessFunction, f as AdminAuthAccessResolution, g as AdminAuthClaimMapping, h as AdminAuthProvider, i as AdminAuthProvisioningMode, j as AdminAuthResolveAccessArgs, k as AdminAuthResolvedIdentity, l as AdminConfig, m as AdminDashboardComponentSlots, n as AdminIconName, o as ArrayField, p as BaseAdminAuthProvider, q as BlocksField, r as BooleanField, s as CharacterLimitFieldConfig, t as CollectionAfterChangeHook, u as CollectionAfterDeleteHook, v as CollectionAfterReadHook, w as CollectionAfterTransitionHook, x as CollectionBeforeChangeHook, y as CollectionBeforeDeleteHook, z as CollectionBeforeReadHook, E as CollectionBeforeTransitionHook, I as CollectionListComponentSlots, J as CustomAdminAuthProvider, K as DatabaseAdapter, M as DateField, N as DateTimeField, O as DynamicOptionItem, Q as DynamicOptionsConfig, R as DynamicOptionsResolver, S as DynamicOptionsResolverArgs, T as EmailField, U as FieldAdminOnChangeHook, V as FieldAdminOnChangeHookArgs, X as FieldAdminOptionsHook, Y as FieldAdminOptionsHookArgs, Z as FieldAdminOptionsHookResult, _ as FieldAfterReadHook, $ as FieldAfterReadHookArgs, a0 as FieldBeforeChangeHook, a1 as FieldBeforeChangeHookArgs, a2 as FieldHook, a3 as FieldType, a4 as FileData, a5 as GlobalAfterChangeHook, a6 as GlobalAfterReadHook, a7 as GlobalBeforeChangeHook, a8 as GlobalBeforeReadHook, a9 as HookFunction, aa as IconField, ab as ImageField, ac as ImageService, ad as JoinField, ae as JsonField, af as LIFECYCLE_EVENT_NAMES, ag as LifecycleEventHandler, ah as MultiSelectField, ai as NumberField, aj as OIDCAdminAuthProvider, ak as ObjectField, al as PaginatedResult, am as PublicAdminAuthProvider, an as RadioField, ao as ReadonlyDatabaseAdapter, ap as RelationshipField, aq as RichTextField, ar as RowField, as as SelectField, at as StorageAdapter, au as TextField, av as TextareaField, aw as TimeField, ax as UploadConfig, ay as UrlField, az as WordLimitFieldConfig, aA as WorkflowMetadata, aB as WorkflowRole, aC as WorkflowState, aD as WorkflowTransitionContext } from './app-config-2vF6W56z.js';
3
3
  import 'lucide-react';
4
4
 
5
5
  type Prettify<T> = {
package/dist/server.cjs CHANGED
@@ -2137,11 +2137,12 @@ var AdminAuthController = class {
2137
2137
  return c.json(getPublicAdminAuthConfig(this.config.adminAuth));
2138
2138
  }
2139
2139
  async start(c) {
2140
- const provider = this.getProvider(c.req.param("provider"));
2140
+ const requestConfig = await this.getRequestConfig(c);
2141
+ const provider = this.getProvider(requestConfig, c.req.param("provider"));
2141
2142
  if (!provider) {
2142
2143
  return c.json({ error: true, message: "Admin auth provider not found." }, 404);
2143
2144
  }
2144
- const siteId = c.req.header("X-Site-Id") || c.get("siteId");
2145
+ const siteId = this.getSiteId(c);
2145
2146
  const returnTo = this.normalizeReturnTo(c.req.query("returnTo"), c);
2146
2147
  if (provider.type === "oidc") {
2147
2148
  const redirectUrl = await this.buildOidcStartUrl(
@@ -2155,19 +2156,29 @@ var AdminAuthController = class {
2155
2156
  if (!provider.startUrl) {
2156
2157
  return c.json({ error: true, message: "This provider does not expose a start URL." }, 400);
2157
2158
  }
2158
- const url = new URL(provider.startUrl);
2159
+ const url = this.buildCustomProviderStartUrl(provider.startUrl, new URL(c.req.url).origin);
2160
+ if (!url) {
2161
+ return c.json(
2162
+ {
2163
+ error: true,
2164
+ message: `Admin auth provider "${provider.id}" has an invalid start URL.`
2165
+ },
2166
+ 500
2167
+ );
2168
+ }
2159
2169
  url.searchParams.set("returnTo", returnTo);
2160
2170
  if (siteId) url.searchParams.set("siteId", siteId);
2161
2171
  url.searchParams.set("provider", provider.id);
2162
2172
  return c.redirect(url.toString(), 302);
2163
2173
  }
2164
2174
  async callback(c) {
2165
- const provider = this.getProvider(c.req.param("provider"));
2175
+ const requestConfig = await this.getRequestConfig(c);
2176
+ const provider = this.getProvider(requestConfig, c.req.param("provider"));
2166
2177
  if (!provider) {
2167
2178
  return c.json({ error: true, message: "Admin auth provider not found." }, 404);
2168
2179
  }
2169
2180
  try {
2170
- const exchange = await this.completeProviderAuth(provider, c);
2181
+ const exchange = await this.completeProviderAuth(requestConfig, provider, c);
2171
2182
  const redirectUrl = new URL(exchange.returnTo);
2172
2183
  redirectUrl.searchParams.set("dyrectedExternalToken", exchange.token);
2173
2184
  redirectUrl.searchParams.set("dyrectedAdminCollection", exchange.collectionSlug);
@@ -2181,12 +2192,13 @@ var AdminAuthController = class {
2181
2192
  }
2182
2193
  }
2183
2194
  async exchange(c) {
2184
- const provider = this.getProvider(c.req.param("provider"));
2195
+ const requestConfig = await this.getRequestConfig(c);
2196
+ const provider = this.getProvider(requestConfig, c.req.param("provider"));
2185
2197
  if (!provider) {
2186
2198
  return c.json({ error: true, message: "Admin auth provider not found." }, 404);
2187
2199
  }
2188
2200
  try {
2189
- const exchange = await this.completeProviderAuth(provider, c);
2201
+ const exchange = await this.completeProviderAuth(requestConfig, provider, c);
2190
2202
  return c.json({
2191
2203
  token: exchange.token,
2192
2204
  collectionSlug: exchange.collectionSlug,
@@ -2201,15 +2213,15 @@ var AdminAuthController = class {
2201
2213
  async logout(c) {
2202
2214
  return c.json({ success: true, message: "Logged out. Discard your token." });
2203
2215
  }
2204
- getProvider(id) {
2205
- if (this.config.adminAuth?.mode !== "external") return void 0;
2206
- return this.config.adminAuth.providers.find((provider) => provider.id === id);
2216
+ getProvider(config, id) {
2217
+ if (config.adminAuth?.mode !== "external") return void 0;
2218
+ return config.adminAuth.providers.find((provider) => provider.id === id);
2207
2219
  }
2208
- async completeProviderAuth(provider, c) {
2220
+ async completeProviderAuth(requestConfig, provider, c) {
2209
2221
  const resolved = provider.type === "oidc" ? await this.resolveOidcIdentity(provider, c) : await this.resolveCustomIdentity(provider, c);
2210
2222
  const identity = resolved.identity;
2211
- const siteId = c.req.header("X-Site-Id") || c.get("siteId");
2212
- const adminCollection = getAdminAuthCollection(this.config);
2223
+ const siteId = this.getSiteId(c);
2224
+ const adminCollection = getAdminAuthCollection(requestConfig);
2213
2225
  if (!adminCollection?.auth) {
2214
2226
  throw new Error("Admin auth collection is not configured.");
2215
2227
  }
@@ -2220,12 +2232,12 @@ var AdminAuthController = class {
2220
2232
  where: { email: identity.email },
2221
2233
  limit: 1
2222
2234
  })).docs[0] : null);
2223
- const provisioningMode = this.config.adminAuth?.provisioningMode ?? "jit_plus_membership_management";
2235
+ const provisioningMode = requestConfig.adminAuth?.provisioningMode ?? "jit_plus_membership_management";
2224
2236
  const allowJitProvisioning = provisioningMode !== "preprovisioned_only" && provider.allowJitProvisioning !== false;
2225
2237
  if (!user && !allowJitProvisioning) {
2226
2238
  throw new Error("This account has not been provisioned for admin access.");
2227
2239
  }
2228
- const access = await this.resolveAccess(identity, provider.id, siteId, c, user);
2240
+ const access = await this.resolveAccess(requestConfig, identity, provider.id, siteId, c, user);
2229
2241
  if (!access.allowed) {
2230
2242
  throw new Error("Access denied for this site.");
2231
2243
  }
@@ -2260,8 +2272,8 @@ var AdminAuthController = class {
2260
2272
  returnTo: resolved.returnTo
2261
2273
  };
2262
2274
  }
2263
- async resolveAccess(identity, providerId, siteId, c, user) {
2264
- const resolved = await this.config.adminAuth?.resolveAccess?.({
2275
+ async resolveAccess(requestConfig, identity, providerId, siteId, c, user) {
2276
+ const resolved = await requestConfig.adminAuth?.resolveAccess?.({
2265
2277
  identity,
2266
2278
  providerId,
2267
2279
  siteId,
@@ -2300,6 +2312,21 @@ var AdminAuthController = class {
2300
2312
  });
2301
2313
  return result.docs[0] ?? null;
2302
2314
  }
2315
+ getSiteId(c) {
2316
+ return c.req.header("X-Site-Id") || c.get("siteId");
2317
+ }
2318
+ async getRequestConfig(c) {
2319
+ const siteId = this.getSiteId(c);
2320
+ if (!siteId || !this.config.onSchemaFetch) return this.config;
2321
+ const dynamic = await this.config.onSchemaFetch(siteId);
2322
+ return {
2323
+ ...this.config,
2324
+ ...dynamic.admin ? { admin: { ...this.config.admin, ...dynamic.admin } } : {},
2325
+ ...dynamic.adminAuth ? { adminAuth: { ...this.config.adminAuth, ...dynamic.adminAuth } } : {},
2326
+ collections: dynamic.collections ? [...this.config.collections, ...dynamic.collections] : this.config.collections,
2327
+ globals: dynamic.globals ? [...this.config.globals, ...dynamic.globals] : this.config.globals
2328
+ };
2329
+ }
2303
2330
  async buildOidcStartUrl(provider, returnTo, siteId, origin) {
2304
2331
  const discovery = await this.getOidcDiscovery(provider);
2305
2332
  const nonce = (0, import_node_crypto2.randomBytes)(16).toString("hex");
@@ -2452,6 +2479,17 @@ var AdminAuthController = class {
2452
2479
  defaultCallbackPath(providerId, origin = "") {
2453
2480
  return `${origin}/api/admin/auth/${providerId}/callback`;
2454
2481
  }
2482
+ buildCustomProviderStartUrl(startUrl, origin) {
2483
+ const value = startUrl.trim();
2484
+ if (!value || /^(undefined|null)(\/|$)/i.test(value)) return null;
2485
+ try {
2486
+ const url = new URL(value, origin);
2487
+ if (url.protocol !== "http:" && url.protocol !== "https:") return null;
2488
+ return url;
2489
+ } catch {
2490
+ return null;
2491
+ }
2492
+ }
2455
2493
  async signState(payload) {
2456
2494
  return new import_jose2.SignJWT(payload).setProtectedHeader({ alg: "HS256" }).setIssuedAt().setExpirationTime("15m").sign(this.getStateSecret());
2457
2495
  }
package/dist/server.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as hono_types from 'hono/types';
2
2
  import * as hono from 'hono';
3
3
  import { Hono, Context } from 'hono';
4
- import { D as DyrectedConfig, C as CollectionConfig, G as GlobalConfig } from './index-DfkPT4NR.cjs';
4
+ import { D as DyrectedConfig, C as CollectionConfig, G as GlobalConfig } from './app-config-2vF6W56z.cjs';
5
5
  import * as hono_utils_http_status from 'hono/utils/http-status';
6
6
  import * as hono_utils_types from 'hono/utils/types';
7
7
  import 'lucide-react';
package/dist/server.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as hono_types from 'hono/types';
2
2
  import * as hono from 'hono';
3
3
  import { Hono, Context } from 'hono';
4
- import { D as DyrectedConfig, C as CollectionConfig, G as GlobalConfig } from './index-DfkPT4NR.js';
4
+ import { D as DyrectedConfig, C as CollectionConfig, G as GlobalConfig } from './app-config-2vF6W56z.js';
5
5
  import * as hono_utils_http_status from 'hono/utils/http-status';
6
6
  import * as hono_utils_types from 'hono/utils/types';
7
7
  import 'lucide-react';
package/dist/server.js CHANGED
@@ -1636,11 +1636,12 @@ var AdminAuthController = class {
1636
1636
  return c.json(getPublicAdminAuthConfig(this.config.adminAuth));
1637
1637
  }
1638
1638
  async start(c) {
1639
- const provider = this.getProvider(c.req.param("provider"));
1639
+ const requestConfig = await this.getRequestConfig(c);
1640
+ const provider = this.getProvider(requestConfig, c.req.param("provider"));
1640
1641
  if (!provider) {
1641
1642
  return c.json({ error: true, message: "Admin auth provider not found." }, 404);
1642
1643
  }
1643
- const siteId = c.req.header("X-Site-Id") || c.get("siteId");
1644
+ const siteId = this.getSiteId(c);
1644
1645
  const returnTo = this.normalizeReturnTo(c.req.query("returnTo"), c);
1645
1646
  if (provider.type === "oidc") {
1646
1647
  const redirectUrl = await this.buildOidcStartUrl(
@@ -1654,19 +1655,29 @@ var AdminAuthController = class {
1654
1655
  if (!provider.startUrl) {
1655
1656
  return c.json({ error: true, message: "This provider does not expose a start URL." }, 400);
1656
1657
  }
1657
- const url = new URL(provider.startUrl);
1658
+ const url = this.buildCustomProviderStartUrl(provider.startUrl, new URL(c.req.url).origin);
1659
+ if (!url) {
1660
+ return c.json(
1661
+ {
1662
+ error: true,
1663
+ message: `Admin auth provider "${provider.id}" has an invalid start URL.`
1664
+ },
1665
+ 500
1666
+ );
1667
+ }
1658
1668
  url.searchParams.set("returnTo", returnTo);
1659
1669
  if (siteId) url.searchParams.set("siteId", siteId);
1660
1670
  url.searchParams.set("provider", provider.id);
1661
1671
  return c.redirect(url.toString(), 302);
1662
1672
  }
1663
1673
  async callback(c) {
1664
- const provider = this.getProvider(c.req.param("provider"));
1674
+ const requestConfig = await this.getRequestConfig(c);
1675
+ const provider = this.getProvider(requestConfig, c.req.param("provider"));
1665
1676
  if (!provider) {
1666
1677
  return c.json({ error: true, message: "Admin auth provider not found." }, 404);
1667
1678
  }
1668
1679
  try {
1669
- const exchange = await this.completeProviderAuth(provider, c);
1680
+ const exchange = await this.completeProviderAuth(requestConfig, provider, c);
1670
1681
  const redirectUrl = new URL(exchange.returnTo);
1671
1682
  redirectUrl.searchParams.set("dyrectedExternalToken", exchange.token);
1672
1683
  redirectUrl.searchParams.set("dyrectedAdminCollection", exchange.collectionSlug);
@@ -1680,12 +1691,13 @@ var AdminAuthController = class {
1680
1691
  }
1681
1692
  }
1682
1693
  async exchange(c) {
1683
- const provider = this.getProvider(c.req.param("provider"));
1694
+ const requestConfig = await this.getRequestConfig(c);
1695
+ const provider = this.getProvider(requestConfig, c.req.param("provider"));
1684
1696
  if (!provider) {
1685
1697
  return c.json({ error: true, message: "Admin auth provider not found." }, 404);
1686
1698
  }
1687
1699
  try {
1688
- const exchange = await this.completeProviderAuth(provider, c);
1700
+ const exchange = await this.completeProviderAuth(requestConfig, provider, c);
1689
1701
  return c.json({
1690
1702
  token: exchange.token,
1691
1703
  collectionSlug: exchange.collectionSlug,
@@ -1700,15 +1712,15 @@ var AdminAuthController = class {
1700
1712
  async logout(c) {
1701
1713
  return c.json({ success: true, message: "Logged out. Discard your token." });
1702
1714
  }
1703
- getProvider(id) {
1704
- if (this.config.adminAuth?.mode !== "external") return void 0;
1705
- return this.config.adminAuth.providers.find((provider) => provider.id === id);
1715
+ getProvider(config, id) {
1716
+ if (config.adminAuth?.mode !== "external") return void 0;
1717
+ return config.adminAuth.providers.find((provider) => provider.id === id);
1706
1718
  }
1707
- async completeProviderAuth(provider, c) {
1719
+ async completeProviderAuth(requestConfig, provider, c) {
1708
1720
  const resolved = provider.type === "oidc" ? await this.resolveOidcIdentity(provider, c) : await this.resolveCustomIdentity(provider, c);
1709
1721
  const identity = resolved.identity;
1710
- const siteId = c.req.header("X-Site-Id") || c.get("siteId");
1711
- const adminCollection = getAdminAuthCollection(this.config);
1722
+ const siteId = this.getSiteId(c);
1723
+ const adminCollection = getAdminAuthCollection(requestConfig);
1712
1724
  if (!adminCollection?.auth) {
1713
1725
  throw new Error("Admin auth collection is not configured.");
1714
1726
  }
@@ -1719,12 +1731,12 @@ var AdminAuthController = class {
1719
1731
  where: { email: identity.email },
1720
1732
  limit: 1
1721
1733
  })).docs[0] : null);
1722
- const provisioningMode = this.config.adminAuth?.provisioningMode ?? "jit_plus_membership_management";
1734
+ const provisioningMode = requestConfig.adminAuth?.provisioningMode ?? "jit_plus_membership_management";
1723
1735
  const allowJitProvisioning = provisioningMode !== "preprovisioned_only" && provider.allowJitProvisioning !== false;
1724
1736
  if (!user && !allowJitProvisioning) {
1725
1737
  throw new Error("This account has not been provisioned for admin access.");
1726
1738
  }
1727
- const access = await this.resolveAccess(identity, provider.id, siteId, c, user);
1739
+ const access = await this.resolveAccess(requestConfig, identity, provider.id, siteId, c, user);
1728
1740
  if (!access.allowed) {
1729
1741
  throw new Error("Access denied for this site.");
1730
1742
  }
@@ -1759,8 +1771,8 @@ var AdminAuthController = class {
1759
1771
  returnTo: resolved.returnTo
1760
1772
  };
1761
1773
  }
1762
- async resolveAccess(identity, providerId, siteId, c, user) {
1763
- const resolved = await this.config.adminAuth?.resolveAccess?.({
1774
+ async resolveAccess(requestConfig, identity, providerId, siteId, c, user) {
1775
+ const resolved = await requestConfig.adminAuth?.resolveAccess?.({
1764
1776
  identity,
1765
1777
  providerId,
1766
1778
  siteId,
@@ -1799,6 +1811,21 @@ var AdminAuthController = class {
1799
1811
  });
1800
1812
  return result.docs[0] ?? null;
1801
1813
  }
1814
+ getSiteId(c) {
1815
+ return c.req.header("X-Site-Id") || c.get("siteId");
1816
+ }
1817
+ async getRequestConfig(c) {
1818
+ const siteId = this.getSiteId(c);
1819
+ if (!siteId || !this.config.onSchemaFetch) return this.config;
1820
+ const dynamic = await this.config.onSchemaFetch(siteId);
1821
+ return {
1822
+ ...this.config,
1823
+ ...dynamic.admin ? { admin: { ...this.config.admin, ...dynamic.admin } } : {},
1824
+ ...dynamic.adminAuth ? { adminAuth: { ...this.config.adminAuth, ...dynamic.adminAuth } } : {},
1825
+ collections: dynamic.collections ? [...this.config.collections, ...dynamic.collections] : this.config.collections,
1826
+ globals: dynamic.globals ? [...this.config.globals, ...dynamic.globals] : this.config.globals
1827
+ };
1828
+ }
1802
1829
  async buildOidcStartUrl(provider, returnTo, siteId, origin) {
1803
1830
  const discovery = await this.getOidcDiscovery(provider);
1804
1831
  const nonce = randomBytes2(16).toString("hex");
@@ -1951,6 +1978,17 @@ var AdminAuthController = class {
1951
1978
  defaultCallbackPath(providerId, origin = "") {
1952
1979
  return `${origin}/api/admin/auth/${providerId}/callback`;
1953
1980
  }
1981
+ buildCustomProviderStartUrl(startUrl, origin) {
1982
+ const value = startUrl.trim();
1983
+ if (!value || /^(undefined|null)(\/|$)/i.test(value)) return null;
1984
+ try {
1985
+ const url = new URL(value, origin);
1986
+ if (url.protocol !== "http:" && url.protocol !== "https:") return null;
1987
+ return url;
1988
+ } catch {
1989
+ return null;
1990
+ }
1991
+ }
1954
1992
  async signState(payload) {
1955
1993
  return new SignJWT2(payload).setProtectedHeader({ alg: "HS256" }).setIssuedAt().setExpirationTime("15m").sign(this.getStateSecret());
1956
1994
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dyrected/core",
3
- "version": "2.5.41",
3
+ "version": "2.5.43",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",