@dyrected/core 2.13.6 → 2.15.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/dist/server.js CHANGED
@@ -2308,6 +2308,12 @@ var init_chunker = __esm({
2308
2308
  import { createGoogleGenerativeAI } from "@ai-sdk/google";
2309
2309
  import { createOpenAI } from "@ai-sdk/openai";
2310
2310
  import { embed, embedMany } from "ai";
2311
+ function hasEmbeddingApiKey(config) {
2312
+ const ai = config?.ai;
2313
+ return Boolean(
2314
+ ai?.apiKey || process.env.OPENROUTER_API_KEY || process.env.OPENAI_API_KEY || process.env.GEMINI_API_KEY || process.env.GOOGLE_GENERATIVE_AI_API_KEY
2315
+ );
2316
+ }
2311
2317
  function getEmbeddingModel(config) {
2312
2318
  const ai = config?.ai;
2313
2319
  const provider = ai?.provider;
@@ -2647,6 +2653,9 @@ var init_rag_service = __esm({
2647
2653
  if (!col || !this.isCollectionRAGEnabled(config, col)) {
2648
2654
  return { indexed: 0, skipped: 0 };
2649
2655
  }
2656
+ if (!hasEmbeddingApiKey(config)) {
2657
+ return { indexed: 0, skipped: 0 };
2658
+ }
2650
2659
  const docId = String(doc.id || doc._id || "");
2651
2660
  if (!docId) return { indexed: 0, skipped: 0 };
2652
2661
  const ragConfig = col.ai?.rag;
@@ -4793,6 +4802,14 @@ function getSecret() {
4793
4802
  return new TextEncoder().encode(secret);
4794
4803
  }
4795
4804
  var DEFAULT_EXPIRY = "7d";
4805
+ var DEFAULT_SESSION_EXPIRY = DEFAULT_EXPIRY;
4806
+ function resolveSessionTokenExpiry(collection) {
4807
+ const auth = collection.auth;
4808
+ if (auth && typeof auth === "object" && typeof auth.tokenExpiration === "string" && auth.tokenExpiration.length > 0) {
4809
+ return auth.tokenExpiration;
4810
+ }
4811
+ return DEFAULT_SESSION_EXPIRY;
4812
+ }
4796
4813
  async function signCollectionToken(payload, expiresIn = DEFAULT_EXPIRY) {
4797
4814
  return new SignJWT({ ...payload }).setProtectedHeader({ alg: "HS256" }).setIssuedAt().setExpirationTime(expiresIn).sign(getSecret());
4798
4815
  }
@@ -7747,13 +7764,13 @@ var CollectionController = class {
7747
7764
  const config = c.get("config");
7748
7765
  const db = config.db;
7749
7766
  if (!db) return c.json({ message: "Database not configured" }, 500);
7750
- if (!this.collection.views?.length) {
7751
- return c.json({ error: true, message: `Collection ${this.collection.slug} has no views` }, 404);
7767
+ if (!this.collection.views?.length && !this.collection.actions?.length) {
7768
+ return c.json({ error: true, message: `Collection ${this.collection.slug} has no views or actions` }, 404);
7752
7769
  }
7753
7770
  const actionName = c.req.param("action");
7754
7771
  const viewSlugParam = c.req.param("viewSlug");
7755
7772
  let action;
7756
- for (const view2 of this.collection.views) {
7773
+ for (const view2 of this.collection.views ?? []) {
7757
7774
  if (viewSlugParam && view2.slug !== viewSlugParam) continue;
7758
7775
  const match = view2.actions?.find((candidate) => candidate.name === actionName);
7759
7776
  if (match) {
@@ -7761,6 +7778,9 @@ var CollectionController = class {
7761
7778
  break;
7762
7779
  }
7763
7780
  }
7781
+ if (!action && !viewSlugParam) {
7782
+ action = this.collection.actions?.find((candidate) => candidate.name === actionName);
7783
+ }
7764
7784
  if (!action) {
7765
7785
  return c.json(
7766
7786
  { error: true, message: `Action "${actionName}" was not found${viewSlugParam ? ` in view "${viewSlugParam}"` : ""}` },
@@ -7778,7 +7798,7 @@ var CollectionController = class {
7778
7798
  const input = body?.input ?? {};
7779
7799
  const user = c.get("user");
7780
7800
  const accessArgs = { user, req: this.toHookRequestContext(c) };
7781
- const view = viewSlugParam ? this.collection.views.find((candidate) => candidate.slug === viewSlugParam) : void 0;
7801
+ const view = viewSlugParam ? this.collection.views?.find((candidate) => candidate.slug === viewSlugParam) : void 0;
7782
7802
  if (view?.access) {
7783
7803
  const allowed = await resolveBooleanAccess(config, view.access.update ?? view.access.read ?? true, {
7784
7804
  ...accessArgs,
@@ -7816,7 +7836,8 @@ var CollectionController = class {
7816
7836
  });
7817
7837
  resolvedData = handlerResult ?? {};
7818
7838
  } catch (error) {
7819
- results.push({ id, ok: false, status: 500, error: error instanceof Error ? error.message : String(error) });
7839
+ const status = typeof error.statusCode === "number" ? error.statusCode : 500;
7840
+ results.push({ id, ok: false, status, error: error instanceof Error ? error.message : String(error) });
7820
7841
  continue;
7821
7842
  }
7822
7843
  } else {
@@ -7839,7 +7860,8 @@ var CollectionController = class {
7839
7860
  if (requestedIds.length === 1) {
7840
7861
  const single = results[0];
7841
7862
  if (!single.ok) {
7842
- return c.json(single.error ?? { error: true, message: "Action failed" }, single.status ?? 500);
7863
+ const body2 = typeof single.error === "string" ? { error: true, message: single.error } : single.error ?? { error: true, message: "Action failed" };
7864
+ return c.json(body2, single.status ?? 500);
7843
7865
  }
7844
7866
  return c.json(single.doc);
7845
7867
  }
@@ -9644,6 +9666,7 @@ var AuthController = class {
9644
9666
  userId: user.id,
9645
9667
  email: user.email,
9646
9668
  collection: this.collection.slug,
9669
+ expiresIn: resolveSessionTokenExpiry(this.collection),
9647
9670
  ip: c.get("clientIp"),
9648
9671
  authSource: "local"
9649
9672
  });
@@ -9735,6 +9758,7 @@ var AuthController = class {
9735
9758
  userId: user.id,
9736
9759
  email: user.email,
9737
9760
  collection: this.collection.slug,
9761
+ expiresIn: resolveSessionTokenExpiry(this.collection),
9738
9762
  ip: c.get("clientIp"),
9739
9763
  authSource: "local"
9740
9764
  });
@@ -9825,12 +9849,15 @@ var AuthController = class {
9825
9849
  }
9826
9850
  const tokenPayload = c.get("authTokenPayload");
9827
9851
  if (tokenPayload?.sid) {
9828
- const token2 = await signCollectionToken({
9829
- sub: requestUser.sub,
9830
- email: requestUser.email,
9831
- collection: this.collection.slug,
9832
- sid: tokenPayload.sid
9833
- });
9852
+ const token2 = await signCollectionToken(
9853
+ {
9854
+ sub: requestUser.sub,
9855
+ email: requestUser.email,
9856
+ collection: this.collection.slug,
9857
+ sid: tokenPayload.sid
9858
+ },
9859
+ resolveSessionTokenExpiry(this.collection)
9860
+ );
9834
9861
  return c.json({ token: token2 });
9835
9862
  }
9836
9863
  const token = await issueAuthSessionToken({
@@ -10092,6 +10119,7 @@ var AuthController = class {
10092
10119
  userId: user.id,
10093
10120
  email: inviteeEmail,
10094
10121
  collection: this.collection.slug,
10122
+ expiresIn: resolveSessionTokenExpiry(this.collection),
10095
10123
  ip: c.get("clientIp"),
10096
10124
  authSource: "local"
10097
10125
  });
@@ -10349,6 +10377,7 @@ var AdminAuthController = class {
10349
10377
  userId: user.id,
10350
10378
  email: user.email,
10351
10379
  collection: adminCollection.slug,
10380
+ expiresIn: resolveSessionTokenExpiry(adminCollection),
10352
10381
  providerId: provider.id,
10353
10382
  authSource: "external",
10354
10383
  ip: c.get("clientIp")
@@ -14282,6 +14311,8 @@ function registerRoutes(app, config) {
14282
14311
  app.post(`${path}/aggregate`, (c) => controller.aggregate(c));
14283
14312
  if (collection.views?.length) {
14284
14313
  app.post(`${path}/views/:viewSlug/actions/:action`, optionalAuth(config), (c) => controller.runViewAction(c));
14314
+ }
14315
+ if (collection.views?.length || collection.actions?.length) {
14285
14316
  app.post(`${path}/actions/:action`, optionalAuth(config), (c) => controller.runViewAction(c));
14286
14317
  }
14287
14318
  if (collection.audit) {
@@ -15059,6 +15090,8 @@ async function createDyrectedApp(rawConfig) {
15059
15090
  if (err instanceof HTTPException6) {
15060
15091
  return c.json({ error: true, message: err.message }, err.status);
15061
15092
  }
15093
+ const statusCode = err.statusCode;
15094
+ const status = typeof statusCode === "number" && Number.isInteger(statusCode) && statusCode >= 400 && statusCode <= 599 ? statusCode : 500;
15062
15095
  const logger = getRequestLogger(c, "core");
15063
15096
  logger.error({
15064
15097
  err,
@@ -15071,9 +15104,10 @@ async function createDyrectedApp(rawConfig) {
15071
15104
  method: c.req.method
15072
15105
  });
15073
15106
  return c.json({
15107
+ error: true,
15074
15108
  message: err.message || "Internal Server Error",
15075
15109
  stack: process.env.NODE_ENV === "development" ? err.stack : void 0
15076
- }, 500);
15110
+ }, status);
15077
15111
  });
15078
15112
  registerRoutes(app, config);
15079
15113
  return app;
@@ -15088,8 +15122,12 @@ init_embedding_service();
15088
15122
  export {
15089
15123
  AIAgent,
15090
15124
  AIController,
15125
+ AUTH_SESSIONS_COLLECTION,
15091
15126
  AuthController,
15092
15127
  CollectionController,
15128
+ DEFAULT_LOCK_TIME_MS,
15129
+ DEFAULT_MAX_LOGIN_ATTEMPTS,
15130
+ DEFAULT_SESSION_EXPIRY,
15093
15131
  EmbeddingService,
15094
15132
  GlobalController,
15095
15133
  InMemoryRateLimitStore,
@@ -15100,7 +15138,11 @@ export {
15100
15138
  attachRequestMetrics,
15101
15139
  bindObservabilityRuntime,
15102
15140
  buildDyrectedSystemPrompt,
15141
+ buildInviteEmail,
15142
+ buildPasswordChangedEmail,
15103
15143
  buildRequestLogger,
15144
+ buildResetPasswordEmail,
15145
+ buildWelcomeEmail,
15104
15146
  captureRequestBody,
15105
15147
  chunkText,
15106
15148
  cosineSimilarity,
@@ -15108,24 +15150,40 @@ export {
15108
15150
  createDyrectedApp,
15109
15151
  createObservabilityRuntime,
15110
15152
  createRequestSpan,
15153
+ decodeCollectionToken,
15111
15154
  endRequestSpan,
15112
15155
  estimateTokens,
15113
15156
  extractTextFromDoc,
15114
15157
  formatAIErrorMessage,
15115
15158
  getAIModel,
15159
+ getAuthSession,
15116
15160
  getConfigLogger,
15117
15161
  getEmbeddingModel,
15162
+ getLockedUntilMs,
15118
15163
  getObservabilityRuntime,
15119
15164
  getRequestLogger,
15165
+ hasEmbeddingApiKey,
15120
15166
  hashContent,
15167
+ hashPassword,
15168
+ isAuthSessionActive,
15169
+ issueAuthSessionToken,
15121
15170
  normalizeFieldValue,
15122
15171
  redactBody,
15123
15172
  redactHeaders,
15124
15173
  registerRoutes,
15125
15174
  renderPrometheusMetrics,
15175
+ resolveAuthLockoutConfig,
15126
15176
  resolveObservabilityConfig,
15177
+ resolveSessionTokenExpiry,
15178
+ revokeAllAuthSessions,
15179
+ revokeAuthSession,
15180
+ sendEmail,
15127
15181
  serializeDetailForApi,
15128
15182
  serializeViewForApi,
15129
15183
  shouldSampleRequest,
15130
- validatePayloadAgainstFields
15184
+ signCollectionToken,
15185
+ touchAuthSession,
15186
+ validatePayloadAgainstFields,
15187
+ verifyCollectionToken,
15188
+ verifyPassword
15131
15189
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dyrected/core",
3
- "version": "2.13.6",
3
+ "version": "2.15.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",