@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.cjs CHANGED
@@ -2307,6 +2307,12 @@ var init_chunker = __esm({
2307
2307
  });
2308
2308
 
2309
2309
  // src/services/rag/embedding.service.ts
2310
+ function hasEmbeddingApiKey(config) {
2311
+ const ai = config?.ai;
2312
+ return Boolean(
2313
+ ai?.apiKey || process.env.OPENROUTER_API_KEY || process.env.OPENAI_API_KEY || process.env.GEMINI_API_KEY || process.env.GOOGLE_GENERATIVE_AI_API_KEY
2314
+ );
2315
+ }
2310
2316
  function getEmbeddingModel(config) {
2311
2317
  const ai = config?.ai;
2312
2318
  const provider = ai?.provider;
@@ -2649,6 +2655,9 @@ var init_rag_service = __esm({
2649
2655
  if (!col || !this.isCollectionRAGEnabled(config, col)) {
2650
2656
  return { indexed: 0, skipped: 0 };
2651
2657
  }
2658
+ if (!hasEmbeddingApiKey(config)) {
2659
+ return { indexed: 0, skipped: 0 };
2660
+ }
2652
2661
  const docId = String(doc.id || doc._id || "");
2653
2662
  if (!docId) return { indexed: 0, skipped: 0 };
2654
2663
  const ragConfig = col.ai?.rag;
@@ -3948,8 +3957,12 @@ var server_exports = {};
3948
3957
  __export(server_exports, {
3949
3958
  AIAgent: () => AIAgent,
3950
3959
  AIController: () => AIController,
3960
+ AUTH_SESSIONS_COLLECTION: () => AUTH_SESSIONS_COLLECTION,
3951
3961
  AuthController: () => AuthController,
3952
3962
  CollectionController: () => CollectionController,
3963
+ DEFAULT_LOCK_TIME_MS: () => DEFAULT_LOCK_TIME_MS,
3964
+ DEFAULT_MAX_LOGIN_ATTEMPTS: () => DEFAULT_MAX_LOGIN_ATTEMPTS,
3965
+ DEFAULT_SESSION_EXPIRY: () => DEFAULT_SESSION_EXPIRY,
3953
3966
  EmbeddingService: () => EmbeddingService,
3954
3967
  GlobalController: () => GlobalController,
3955
3968
  InMemoryRateLimitStore: () => InMemoryRateLimitStore,
@@ -3960,7 +3973,11 @@ __export(server_exports, {
3960
3973
  attachRequestMetrics: () => attachRequestMetrics,
3961
3974
  bindObservabilityRuntime: () => bindObservabilityRuntime,
3962
3975
  buildDyrectedSystemPrompt: () => buildDyrectedSystemPrompt,
3976
+ buildInviteEmail: () => buildInviteEmail,
3977
+ buildPasswordChangedEmail: () => buildPasswordChangedEmail,
3963
3978
  buildRequestLogger: () => buildRequestLogger,
3979
+ buildResetPasswordEmail: () => buildResetPasswordEmail,
3980
+ buildWelcomeEmail: () => buildWelcomeEmail,
3964
3981
  captureRequestBody: () => captureRequestBody,
3965
3982
  chunkText: () => chunkText,
3966
3983
  cosineSimilarity: () => cosineSimilarity,
@@ -3968,26 +3985,42 @@ __export(server_exports, {
3968
3985
  createDyrectedApp: () => createDyrectedApp,
3969
3986
  createObservabilityRuntime: () => createObservabilityRuntime,
3970
3987
  createRequestSpan: () => createRequestSpan,
3988
+ decodeCollectionToken: () => decodeCollectionToken,
3971
3989
  endRequestSpan: () => endRequestSpan,
3972
3990
  estimateTokens: () => estimateTokens,
3973
3991
  extractTextFromDoc: () => extractTextFromDoc,
3974
3992
  formatAIErrorMessage: () => formatAIErrorMessage,
3975
3993
  getAIModel: () => getAIModel,
3994
+ getAuthSession: () => getAuthSession,
3976
3995
  getConfigLogger: () => getConfigLogger,
3977
3996
  getEmbeddingModel: () => getEmbeddingModel,
3997
+ getLockedUntilMs: () => getLockedUntilMs,
3978
3998
  getObservabilityRuntime: () => getObservabilityRuntime,
3979
3999
  getRequestLogger: () => getRequestLogger,
4000
+ hasEmbeddingApiKey: () => hasEmbeddingApiKey,
3980
4001
  hashContent: () => hashContent,
4002
+ hashPassword: () => hashPassword,
4003
+ isAuthSessionActive: () => isAuthSessionActive,
4004
+ issueAuthSessionToken: () => issueAuthSessionToken,
3981
4005
  normalizeFieldValue: () => normalizeFieldValue,
3982
4006
  redactBody: () => redactBody,
3983
4007
  redactHeaders: () => redactHeaders,
3984
4008
  registerRoutes: () => registerRoutes,
3985
4009
  renderPrometheusMetrics: () => renderPrometheusMetrics,
4010
+ resolveAuthLockoutConfig: () => resolveAuthLockoutConfig,
3986
4011
  resolveObservabilityConfig: () => resolveObservabilityConfig,
4012
+ resolveSessionTokenExpiry: () => resolveSessionTokenExpiry,
4013
+ revokeAllAuthSessions: () => revokeAllAuthSessions,
4014
+ revokeAuthSession: () => revokeAuthSession,
4015
+ sendEmail: () => sendEmail,
3987
4016
  serializeDetailForApi: () => serializeDetailForApi,
3988
4017
  serializeViewForApi: () => serializeViewForApi,
3989
4018
  shouldSampleRequest: () => shouldSampleRequest,
3990
- validatePayloadAgainstFields: () => validatePayloadAgainstFields
4019
+ signCollectionToken: () => signCollectionToken,
4020
+ touchAuthSession: () => touchAuthSession,
4021
+ validatePayloadAgainstFields: () => validatePayloadAgainstFields,
4022
+ verifyCollectionToken: () => verifyCollectionToken,
4023
+ verifyPassword: () => verifyPassword
3991
4024
  });
3992
4025
  module.exports = __toCommonJS(server_exports);
3993
4026
 
@@ -4829,6 +4862,14 @@ function getSecret() {
4829
4862
  return new TextEncoder().encode(secret);
4830
4863
  }
4831
4864
  var DEFAULT_EXPIRY = "7d";
4865
+ var DEFAULT_SESSION_EXPIRY = DEFAULT_EXPIRY;
4866
+ function resolveSessionTokenExpiry(collection) {
4867
+ const auth = collection.auth;
4868
+ if (auth && typeof auth === "object" && typeof auth.tokenExpiration === "string" && auth.tokenExpiration.length > 0) {
4869
+ return auth.tokenExpiration;
4870
+ }
4871
+ return DEFAULT_SESSION_EXPIRY;
4872
+ }
4832
4873
  async function signCollectionToken(payload, expiresIn = DEFAULT_EXPIRY) {
4833
4874
  return new import_jose.SignJWT({ ...payload }).setProtectedHeader({ alg: "HS256" }).setIssuedAt().setExpirationTime(expiresIn).sign(getSecret());
4834
4875
  }
@@ -7783,13 +7824,13 @@ var CollectionController = class {
7783
7824
  const config = c.get("config");
7784
7825
  const db = config.db;
7785
7826
  if (!db) return c.json({ message: "Database not configured" }, 500);
7786
- if (!this.collection.views?.length) {
7787
- return c.json({ error: true, message: `Collection ${this.collection.slug} has no views` }, 404);
7827
+ if (!this.collection.views?.length && !this.collection.actions?.length) {
7828
+ return c.json({ error: true, message: `Collection ${this.collection.slug} has no views or actions` }, 404);
7788
7829
  }
7789
7830
  const actionName = c.req.param("action");
7790
7831
  const viewSlugParam = c.req.param("viewSlug");
7791
7832
  let action;
7792
- for (const view2 of this.collection.views) {
7833
+ for (const view2 of this.collection.views ?? []) {
7793
7834
  if (viewSlugParam && view2.slug !== viewSlugParam) continue;
7794
7835
  const match = view2.actions?.find((candidate) => candidate.name === actionName);
7795
7836
  if (match) {
@@ -7797,6 +7838,9 @@ var CollectionController = class {
7797
7838
  break;
7798
7839
  }
7799
7840
  }
7841
+ if (!action && !viewSlugParam) {
7842
+ action = this.collection.actions?.find((candidate) => candidate.name === actionName);
7843
+ }
7800
7844
  if (!action) {
7801
7845
  return c.json(
7802
7846
  { error: true, message: `Action "${actionName}" was not found${viewSlugParam ? ` in view "${viewSlugParam}"` : ""}` },
@@ -7814,7 +7858,7 @@ var CollectionController = class {
7814
7858
  const input = body?.input ?? {};
7815
7859
  const user = c.get("user");
7816
7860
  const accessArgs = { user, req: this.toHookRequestContext(c) };
7817
- const view = viewSlugParam ? this.collection.views.find((candidate) => candidate.slug === viewSlugParam) : void 0;
7861
+ const view = viewSlugParam ? this.collection.views?.find((candidate) => candidate.slug === viewSlugParam) : void 0;
7818
7862
  if (view?.access) {
7819
7863
  const allowed = await resolveBooleanAccess(config, view.access.update ?? view.access.read ?? true, {
7820
7864
  ...accessArgs,
@@ -7852,7 +7896,8 @@ var CollectionController = class {
7852
7896
  });
7853
7897
  resolvedData = handlerResult ?? {};
7854
7898
  } catch (error) {
7855
- results.push({ id, ok: false, status: 500, error: error instanceof Error ? error.message : String(error) });
7899
+ const status = typeof error.statusCode === "number" ? error.statusCode : 500;
7900
+ results.push({ id, ok: false, status, error: error instanceof Error ? error.message : String(error) });
7856
7901
  continue;
7857
7902
  }
7858
7903
  } else {
@@ -7875,7 +7920,8 @@ var CollectionController = class {
7875
7920
  if (requestedIds.length === 1) {
7876
7921
  const single = results[0];
7877
7922
  if (!single.ok) {
7878
- return c.json(single.error ?? { error: true, message: "Action failed" }, single.status ?? 500);
7923
+ const body2 = typeof single.error === "string" ? { error: true, message: single.error } : single.error ?? { error: true, message: "Action failed" };
7924
+ return c.json(body2, single.status ?? 500);
7879
7925
  }
7880
7926
  return c.json(single.doc);
7881
7927
  }
@@ -9680,6 +9726,7 @@ var AuthController = class {
9680
9726
  userId: user.id,
9681
9727
  email: user.email,
9682
9728
  collection: this.collection.slug,
9729
+ expiresIn: resolveSessionTokenExpiry(this.collection),
9683
9730
  ip: c.get("clientIp"),
9684
9731
  authSource: "local"
9685
9732
  });
@@ -9771,6 +9818,7 @@ var AuthController = class {
9771
9818
  userId: user.id,
9772
9819
  email: user.email,
9773
9820
  collection: this.collection.slug,
9821
+ expiresIn: resolveSessionTokenExpiry(this.collection),
9774
9822
  ip: c.get("clientIp"),
9775
9823
  authSource: "local"
9776
9824
  });
@@ -9861,12 +9909,15 @@ var AuthController = class {
9861
9909
  }
9862
9910
  const tokenPayload = c.get("authTokenPayload");
9863
9911
  if (tokenPayload?.sid) {
9864
- const token2 = await signCollectionToken({
9865
- sub: requestUser.sub,
9866
- email: requestUser.email,
9867
- collection: this.collection.slug,
9868
- sid: tokenPayload.sid
9869
- });
9912
+ const token2 = await signCollectionToken(
9913
+ {
9914
+ sub: requestUser.sub,
9915
+ email: requestUser.email,
9916
+ collection: this.collection.slug,
9917
+ sid: tokenPayload.sid
9918
+ },
9919
+ resolveSessionTokenExpiry(this.collection)
9920
+ );
9870
9921
  return c.json({ token: token2 });
9871
9922
  }
9872
9923
  const token = await issueAuthSessionToken({
@@ -10128,6 +10179,7 @@ var AuthController = class {
10128
10179
  userId: user.id,
10129
10180
  email: inviteeEmail,
10130
10181
  collection: this.collection.slug,
10182
+ expiresIn: resolveSessionTokenExpiry(this.collection),
10131
10183
  ip: c.get("clientIp"),
10132
10184
  authSource: "local"
10133
10185
  });
@@ -10380,6 +10432,7 @@ var AdminAuthController = class {
10380
10432
  userId: user.id,
10381
10433
  email: user.email,
10382
10434
  collection: adminCollection.slug,
10435
+ expiresIn: resolveSessionTokenExpiry(adminCollection),
10383
10436
  providerId: provider.id,
10384
10437
  authSource: "external",
10385
10438
  ip: c.get("clientIp")
@@ -14313,6 +14366,8 @@ function registerRoutes(app, config) {
14313
14366
  app.post(`${path}/aggregate`, (c) => controller.aggregate(c));
14314
14367
  if (collection.views?.length) {
14315
14368
  app.post(`${path}/views/:viewSlug/actions/:action`, optionalAuth(config), (c) => controller.runViewAction(c));
14369
+ }
14370
+ if (collection.views?.length || collection.actions?.length) {
14316
14371
  app.post(`${path}/actions/:action`, optionalAuth(config), (c) => controller.runViewAction(c));
14317
14372
  }
14318
14373
  if (collection.audit) {
@@ -15090,6 +15145,8 @@ async function createDyrectedApp(rawConfig) {
15090
15145
  if (err instanceof import_http_exception6.HTTPException) {
15091
15146
  return c.json({ error: true, message: err.message }, err.status);
15092
15147
  }
15148
+ const statusCode = err.statusCode;
15149
+ const status = typeof statusCode === "number" && Number.isInteger(statusCode) && statusCode >= 400 && statusCode <= 599 ? statusCode : 500;
15093
15150
  const logger = getRequestLogger(c, "core");
15094
15151
  logger.error({
15095
15152
  err,
@@ -15102,9 +15159,10 @@ async function createDyrectedApp(rawConfig) {
15102
15159
  method: c.req.method
15103
15160
  });
15104
15161
  return c.json({
15162
+ error: true,
15105
15163
  message: err.message || "Internal Server Error",
15106
15164
  stack: process.env.NODE_ENV === "development" ? err.stack : void 0
15107
- }, 500);
15165
+ }, status);
15108
15166
  });
15109
15167
  registerRoutes(app, config);
15110
15168
  return app;
@@ -15120,8 +15178,12 @@ init_embedding_service();
15120
15178
  0 && (module.exports = {
15121
15179
  AIAgent,
15122
15180
  AIController,
15181
+ AUTH_SESSIONS_COLLECTION,
15123
15182
  AuthController,
15124
15183
  CollectionController,
15184
+ DEFAULT_LOCK_TIME_MS,
15185
+ DEFAULT_MAX_LOGIN_ATTEMPTS,
15186
+ DEFAULT_SESSION_EXPIRY,
15125
15187
  EmbeddingService,
15126
15188
  GlobalController,
15127
15189
  InMemoryRateLimitStore,
@@ -15132,7 +15194,11 @@ init_embedding_service();
15132
15194
  attachRequestMetrics,
15133
15195
  bindObservabilityRuntime,
15134
15196
  buildDyrectedSystemPrompt,
15197
+ buildInviteEmail,
15198
+ buildPasswordChangedEmail,
15135
15199
  buildRequestLogger,
15200
+ buildResetPasswordEmail,
15201
+ buildWelcomeEmail,
15136
15202
  captureRequestBody,
15137
15203
  chunkText,
15138
15204
  cosineSimilarity,
@@ -15140,24 +15206,40 @@ init_embedding_service();
15140
15206
  createDyrectedApp,
15141
15207
  createObservabilityRuntime,
15142
15208
  createRequestSpan,
15209
+ decodeCollectionToken,
15143
15210
  endRequestSpan,
15144
15211
  estimateTokens,
15145
15212
  extractTextFromDoc,
15146
15213
  formatAIErrorMessage,
15147
15214
  getAIModel,
15215
+ getAuthSession,
15148
15216
  getConfigLogger,
15149
15217
  getEmbeddingModel,
15218
+ getLockedUntilMs,
15150
15219
  getObservabilityRuntime,
15151
15220
  getRequestLogger,
15221
+ hasEmbeddingApiKey,
15152
15222
  hashContent,
15223
+ hashPassword,
15224
+ isAuthSessionActive,
15225
+ issueAuthSessionToken,
15153
15226
  normalizeFieldValue,
15154
15227
  redactBody,
15155
15228
  redactHeaders,
15156
15229
  registerRoutes,
15157
15230
  renderPrometheusMetrics,
15231
+ resolveAuthLockoutConfig,
15158
15232
  resolveObservabilityConfig,
15233
+ resolveSessionTokenExpiry,
15234
+ revokeAllAuthSessions,
15235
+ revokeAuthSession,
15236
+ sendEmail,
15159
15237
  serializeDetailForApi,
15160
15238
  serializeViewForApi,
15161
15239
  shouldSampleRequest,
15162
- validatePayloadAgainstFields
15240
+ signCollectionToken,
15241
+ touchAuthSession,
15242
+ validatePayloadAgainstFields,
15243
+ verifyCollectionToken,
15244
+ verifyPassword
15163
15245
  });
package/dist/server.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { J as DyrectedContext, D as DyrectedConfig, C as CollectionConfig, G as GlobalConfig, bj as DatabaseAdapter, b as AuthenticatedUser, bE as DyrectedAIContext, al as AIThread, ah as AIMessage, cu as RAGSearchResult, ak as AIRateLimitStore, aj as AIRateLimitResult } from './app-phLVsEOM.cjs';
2
- export { d8 as DyrectedObservabilityRuntime, d9 as RequestBodyCapture, da as RequestTraceContext, db as ResolvedObservabilityConfig, dc as attachRequestMetrics, dd as bindObservabilityRuntime, de as buildRequestLogger, df as captureRequestBody, dg as createDyrectedApp, dh as createObservabilityRuntime, di as createRequestSpan, dj as endRequestSpan, dk as getConfigLogger, dl as getObservabilityRuntime, dm as getRequestLogger, dn as redactBody, dp as redactHeaders, dq as renderPrometheusMetrics, dr as resolveObservabilityConfig, ds as shouldSampleRequest } from './app-phLVsEOM.cjs';
1
+ import { M as DyrectedContext, D as DyrectedConfig, C as CollectionConfig, G as GlobalConfig, bl as DatabaseAdapter, b as AuthenticatedUser, bG as DyrectedAIContext, an as AIThread, aj as AIMessage, cw as RAGSearchResult, am as AIRateLimitStore, al as AIRateLimitResult } from './app-Cmp5lFLJ.cjs';
2
+ export { da as CollectionTokenPayload, db as DEFAULT_SESSION_EXPIRY, dc as DyrectedObservabilityRuntime, dd as RequestBodyCapture, de as RequestTraceContext, df as ResolvedObservabilityConfig, dg as attachRequestMetrics, dh as bindObservabilityRuntime, di as buildRequestLogger, dj as captureRequestBody, dk as createDyrectedApp, dl as createObservabilityRuntime, dm as createRequestSpan, dn as decodeCollectionToken, dp as endRequestSpan, dq as getConfigLogger, dr as getObservabilityRuntime, ds as getRequestLogger, dt as redactBody, du as redactHeaders, dv as renderPrometheusMetrics, dw as resolveObservabilityConfig, dx as resolveSessionTokenExpiry, dy as shouldSampleRequest, dz as signCollectionToken, dA as verifyCollectionToken } from './app-Cmp5lFLJ.cjs';
3
3
  import * as hono from 'hono';
4
4
  import { Hono, Context, Next } from 'hono';
5
5
  import * as hono_utils_http_status from 'hono/utils/http-status';
@@ -434,6 +434,96 @@ declare class AIController {
434
434
  }, hono_utils_http_status.ContentfulStatusCode, "json">>;
435
435
  }
436
436
 
437
+ declare const AUTH_SESSIONS_COLLECTION = "__auth_sessions";
438
+ interface AuthSessionRecord {
439
+ id: string;
440
+ userId: string;
441
+ email: string;
442
+ collection: string;
443
+ authSource?: 'local' | 'external';
444
+ providerId?: string;
445
+ lastIp?: string;
446
+ createdAt?: string;
447
+ updatedAt?: string;
448
+ lastSeenAt?: string;
449
+ expiresAt?: string | null;
450
+ revokedAt?: string | null;
451
+ }
452
+ interface IssueAuthSessionArgs {
453
+ config: DyrectedConfig;
454
+ userId: string;
455
+ email: string;
456
+ collection: string;
457
+ expiresIn?: string;
458
+ authSource?: 'local' | 'external';
459
+ providerId?: string;
460
+ ip?: string;
461
+ }
462
+ declare function issueAuthSessionToken(args: IssueAuthSessionArgs): Promise<string>;
463
+ declare function getAuthSession(config: DyrectedConfig, sessionId: string): Promise<AuthSessionRecord | null>;
464
+ declare function isAuthSessionActive(session: AuthSessionRecord | null | undefined): session is AuthSessionRecord;
465
+ declare function touchAuthSession(config: DyrectedConfig, sessionId: string, args: {
466
+ ip?: string;
467
+ }): Promise<void>;
468
+ declare function revokeAuthSession(config: DyrectedConfig, sessionId: string): Promise<void>;
469
+ declare function revokeAllAuthSessions(config: DyrectedConfig, args: {
470
+ userId: string;
471
+ collection: string;
472
+ }): Promise<number>;
473
+
474
+ /**
475
+ * Hash a plain-text password using scrypt.
476
+ * Returns a `salt:hash` string safe to store in the database.
477
+ */
478
+ declare function hashPassword(plain: string): Promise<string>;
479
+ /**
480
+ * Verify a plain-text password against a stored `salt:hash` string.
481
+ */
482
+ declare function verifyPassword(plain: string, stored: string): Promise<boolean>;
483
+
484
+ declare const DEFAULT_MAX_LOGIN_ATTEMPTS = 5;
485
+ declare const DEFAULT_LOCK_TIME_MS: number;
486
+ type ResolvedAuthLockoutConfig = {
487
+ enabled: boolean;
488
+ maxLoginAttempts: number;
489
+ lockTime: number;
490
+ };
491
+ declare function resolveAuthLockoutConfig(collection: CollectionConfig): ResolvedAuthLockoutConfig;
492
+ declare function getLockedUntilMs(value: unknown): number | null;
493
+
494
+ declare function sendEmail(config: DyrectedConfig, payload: {
495
+ to: string;
496
+ subject: string;
497
+ html: string;
498
+ }): Promise<void>;
499
+ declare function buildWelcomeEmail(config: DyrectedConfig, args: {
500
+ email: string;
501
+ }): {
502
+ subject: string;
503
+ html: string;
504
+ };
505
+ declare function buildInviteEmail(config: DyrectedConfig, args: {
506
+ token: string;
507
+ invitedByEmail?: string;
508
+ url?: string;
509
+ }): {
510
+ subject: string;
511
+ html: string;
512
+ };
513
+ declare function buildResetPasswordEmail(config: DyrectedConfig, args: {
514
+ token: string;
515
+ url?: string;
516
+ }): {
517
+ subject: string;
518
+ html: string;
519
+ };
520
+ declare function buildPasswordChangedEmail(config: DyrectedConfig, args: {
521
+ email: string;
522
+ }): {
523
+ subject: string;
524
+ html: string;
525
+ };
526
+
437
527
  declare function getAIModel(config?: DyrectedConfig): LanguageModel;
438
528
  declare function formatAIErrorMessage(error: any): string;
439
529
  declare function buildDyrectedSystemPrompt(context: DyrectedAIContext): string;
@@ -626,6 +716,13 @@ declare function estimateTokens(text: string): number;
626
716
  */
627
717
  declare function chunkText(text: string, options?: ChunkOptions): ChunkResult[];
628
718
 
719
+ /**
720
+ * Whether any embedding API key is resolvable for this config. Mirrors the
721
+ * key sources consulted by `getEmbeddingModel` without constructing a
722
+ * provider. When this returns false, RAG indexing can never succeed, so
723
+ * callers should skip silently instead of throwing and logging noise.
724
+ */
725
+ declare function hasEmbeddingApiKey(config?: DyrectedConfig): boolean;
629
726
  declare function getEmbeddingModel(config?: DyrectedConfig): EmbeddingModel;
630
727
  declare class EmbeddingService {
631
728
  private config?;
@@ -648,4 +745,4 @@ declare class InMemoryRateLimitStore implements AIRateLimitStore {
648
745
  }
649
746
  declare function aiRateLimit(config?: DyrectedConfig): (c: Context<DyrectedContext>, next: Next) => Promise<void>;
650
747
 
651
- export { AIAgent, type AIAgentOptions, AIController, AuthController, type ChunkOptions, type ChunkResult, CollectionController, type DeleteDocumentChunksOptions, DyrectedContext, EmbeddingService, GlobalController, InMemoryRateLimitStore, type IndexDocumentOptions, MediaController, PreviewController, type RAGSearchOptions, RAGService, type ReindexAllOptions, type ReindexCollectionOptions, aiRateLimit, buildDyrectedSystemPrompt, chunkText, cosineSimilarity, createDyrectedAITools, estimateTokens, extractTextFromDoc, formatAIErrorMessage, getAIModel, getEmbeddingModel, hashContent, normalizeFieldValue, registerRoutes, serializeDetailForApi, serializeViewForApi, validatePayloadAgainstFields };
748
+ export { AIAgent, type AIAgentOptions, AIController, AUTH_SESSIONS_COLLECTION, AuthController, type AuthSessionRecord, type ChunkOptions, type ChunkResult, CollectionController, DEFAULT_LOCK_TIME_MS, DEFAULT_MAX_LOGIN_ATTEMPTS, type DeleteDocumentChunksOptions, DyrectedContext, EmbeddingService, GlobalController, InMemoryRateLimitStore, type IndexDocumentOptions, MediaController, PreviewController, type RAGSearchOptions, RAGService, type ReindexAllOptions, type ReindexCollectionOptions, type ResolvedAuthLockoutConfig, aiRateLimit, buildDyrectedSystemPrompt, buildInviteEmail, buildPasswordChangedEmail, buildResetPasswordEmail, buildWelcomeEmail, chunkText, cosineSimilarity, createDyrectedAITools, estimateTokens, extractTextFromDoc, formatAIErrorMessage, getAIModel, getAuthSession, getEmbeddingModel, getLockedUntilMs, hasEmbeddingApiKey, hashContent, hashPassword, isAuthSessionActive, issueAuthSessionToken, normalizeFieldValue, registerRoutes, resolveAuthLockoutConfig, revokeAllAuthSessions, revokeAuthSession, sendEmail, serializeDetailForApi, serializeViewForApi, touchAuthSession, validatePayloadAgainstFields, verifyPassword };
package/dist/server.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { J as DyrectedContext, D as DyrectedConfig, C as CollectionConfig, G as GlobalConfig, bj as DatabaseAdapter, b as AuthenticatedUser, bE as DyrectedAIContext, al as AIThread, ah as AIMessage, cu as RAGSearchResult, ak as AIRateLimitStore, aj as AIRateLimitResult } from './app-phLVsEOM.js';
2
- export { d8 as DyrectedObservabilityRuntime, d9 as RequestBodyCapture, da as RequestTraceContext, db as ResolvedObservabilityConfig, dc as attachRequestMetrics, dd as bindObservabilityRuntime, de as buildRequestLogger, df as captureRequestBody, dg as createDyrectedApp, dh as createObservabilityRuntime, di as createRequestSpan, dj as endRequestSpan, dk as getConfigLogger, dl as getObservabilityRuntime, dm as getRequestLogger, dn as redactBody, dp as redactHeaders, dq as renderPrometheusMetrics, dr as resolveObservabilityConfig, ds as shouldSampleRequest } from './app-phLVsEOM.js';
1
+ import { M as DyrectedContext, D as DyrectedConfig, C as CollectionConfig, G as GlobalConfig, bl as DatabaseAdapter, b as AuthenticatedUser, bG as DyrectedAIContext, an as AIThread, aj as AIMessage, cw as RAGSearchResult, am as AIRateLimitStore, al as AIRateLimitResult } from './app-Cmp5lFLJ.js';
2
+ export { da as CollectionTokenPayload, db as DEFAULT_SESSION_EXPIRY, dc as DyrectedObservabilityRuntime, dd as RequestBodyCapture, de as RequestTraceContext, df as ResolvedObservabilityConfig, dg as attachRequestMetrics, dh as bindObservabilityRuntime, di as buildRequestLogger, dj as captureRequestBody, dk as createDyrectedApp, dl as createObservabilityRuntime, dm as createRequestSpan, dn as decodeCollectionToken, dp as endRequestSpan, dq as getConfigLogger, dr as getObservabilityRuntime, ds as getRequestLogger, dt as redactBody, du as redactHeaders, dv as renderPrometheusMetrics, dw as resolveObservabilityConfig, dx as resolveSessionTokenExpiry, dy as shouldSampleRequest, dz as signCollectionToken, dA as verifyCollectionToken } from './app-Cmp5lFLJ.js';
3
3
  import * as hono from 'hono';
4
4
  import { Hono, Context, Next } from 'hono';
5
5
  import * as hono_utils_http_status from 'hono/utils/http-status';
@@ -434,6 +434,96 @@ declare class AIController {
434
434
  }, hono_utils_http_status.ContentfulStatusCode, "json">>;
435
435
  }
436
436
 
437
+ declare const AUTH_SESSIONS_COLLECTION = "__auth_sessions";
438
+ interface AuthSessionRecord {
439
+ id: string;
440
+ userId: string;
441
+ email: string;
442
+ collection: string;
443
+ authSource?: 'local' | 'external';
444
+ providerId?: string;
445
+ lastIp?: string;
446
+ createdAt?: string;
447
+ updatedAt?: string;
448
+ lastSeenAt?: string;
449
+ expiresAt?: string | null;
450
+ revokedAt?: string | null;
451
+ }
452
+ interface IssueAuthSessionArgs {
453
+ config: DyrectedConfig;
454
+ userId: string;
455
+ email: string;
456
+ collection: string;
457
+ expiresIn?: string;
458
+ authSource?: 'local' | 'external';
459
+ providerId?: string;
460
+ ip?: string;
461
+ }
462
+ declare function issueAuthSessionToken(args: IssueAuthSessionArgs): Promise<string>;
463
+ declare function getAuthSession(config: DyrectedConfig, sessionId: string): Promise<AuthSessionRecord | null>;
464
+ declare function isAuthSessionActive(session: AuthSessionRecord | null | undefined): session is AuthSessionRecord;
465
+ declare function touchAuthSession(config: DyrectedConfig, sessionId: string, args: {
466
+ ip?: string;
467
+ }): Promise<void>;
468
+ declare function revokeAuthSession(config: DyrectedConfig, sessionId: string): Promise<void>;
469
+ declare function revokeAllAuthSessions(config: DyrectedConfig, args: {
470
+ userId: string;
471
+ collection: string;
472
+ }): Promise<number>;
473
+
474
+ /**
475
+ * Hash a plain-text password using scrypt.
476
+ * Returns a `salt:hash` string safe to store in the database.
477
+ */
478
+ declare function hashPassword(plain: string): Promise<string>;
479
+ /**
480
+ * Verify a plain-text password against a stored `salt:hash` string.
481
+ */
482
+ declare function verifyPassword(plain: string, stored: string): Promise<boolean>;
483
+
484
+ declare const DEFAULT_MAX_LOGIN_ATTEMPTS = 5;
485
+ declare const DEFAULT_LOCK_TIME_MS: number;
486
+ type ResolvedAuthLockoutConfig = {
487
+ enabled: boolean;
488
+ maxLoginAttempts: number;
489
+ lockTime: number;
490
+ };
491
+ declare function resolveAuthLockoutConfig(collection: CollectionConfig): ResolvedAuthLockoutConfig;
492
+ declare function getLockedUntilMs(value: unknown): number | null;
493
+
494
+ declare function sendEmail(config: DyrectedConfig, payload: {
495
+ to: string;
496
+ subject: string;
497
+ html: string;
498
+ }): Promise<void>;
499
+ declare function buildWelcomeEmail(config: DyrectedConfig, args: {
500
+ email: string;
501
+ }): {
502
+ subject: string;
503
+ html: string;
504
+ };
505
+ declare function buildInviteEmail(config: DyrectedConfig, args: {
506
+ token: string;
507
+ invitedByEmail?: string;
508
+ url?: string;
509
+ }): {
510
+ subject: string;
511
+ html: string;
512
+ };
513
+ declare function buildResetPasswordEmail(config: DyrectedConfig, args: {
514
+ token: string;
515
+ url?: string;
516
+ }): {
517
+ subject: string;
518
+ html: string;
519
+ };
520
+ declare function buildPasswordChangedEmail(config: DyrectedConfig, args: {
521
+ email: string;
522
+ }): {
523
+ subject: string;
524
+ html: string;
525
+ };
526
+
437
527
  declare function getAIModel(config?: DyrectedConfig): LanguageModel;
438
528
  declare function formatAIErrorMessage(error: any): string;
439
529
  declare function buildDyrectedSystemPrompt(context: DyrectedAIContext): string;
@@ -626,6 +716,13 @@ declare function estimateTokens(text: string): number;
626
716
  */
627
717
  declare function chunkText(text: string, options?: ChunkOptions): ChunkResult[];
628
718
 
719
+ /**
720
+ * Whether any embedding API key is resolvable for this config. Mirrors the
721
+ * key sources consulted by `getEmbeddingModel` without constructing a
722
+ * provider. When this returns false, RAG indexing can never succeed, so
723
+ * callers should skip silently instead of throwing and logging noise.
724
+ */
725
+ declare function hasEmbeddingApiKey(config?: DyrectedConfig): boolean;
629
726
  declare function getEmbeddingModel(config?: DyrectedConfig): EmbeddingModel;
630
727
  declare class EmbeddingService {
631
728
  private config?;
@@ -648,4 +745,4 @@ declare class InMemoryRateLimitStore implements AIRateLimitStore {
648
745
  }
649
746
  declare function aiRateLimit(config?: DyrectedConfig): (c: Context<DyrectedContext>, next: Next) => Promise<void>;
650
747
 
651
- export { AIAgent, type AIAgentOptions, AIController, AuthController, type ChunkOptions, type ChunkResult, CollectionController, type DeleteDocumentChunksOptions, DyrectedContext, EmbeddingService, GlobalController, InMemoryRateLimitStore, type IndexDocumentOptions, MediaController, PreviewController, type RAGSearchOptions, RAGService, type ReindexAllOptions, type ReindexCollectionOptions, aiRateLimit, buildDyrectedSystemPrompt, chunkText, cosineSimilarity, createDyrectedAITools, estimateTokens, extractTextFromDoc, formatAIErrorMessage, getAIModel, getEmbeddingModel, hashContent, normalizeFieldValue, registerRoutes, serializeDetailForApi, serializeViewForApi, validatePayloadAgainstFields };
748
+ export { AIAgent, type AIAgentOptions, AIController, AUTH_SESSIONS_COLLECTION, AuthController, type AuthSessionRecord, type ChunkOptions, type ChunkResult, CollectionController, DEFAULT_LOCK_TIME_MS, DEFAULT_MAX_LOGIN_ATTEMPTS, type DeleteDocumentChunksOptions, DyrectedContext, EmbeddingService, GlobalController, InMemoryRateLimitStore, type IndexDocumentOptions, MediaController, PreviewController, type RAGSearchOptions, RAGService, type ReindexAllOptions, type ReindexCollectionOptions, type ResolvedAuthLockoutConfig, aiRateLimit, buildDyrectedSystemPrompt, buildInviteEmail, buildPasswordChangedEmail, buildResetPasswordEmail, buildWelcomeEmail, chunkText, cosineSimilarity, createDyrectedAITools, estimateTokens, extractTextFromDoc, formatAIErrorMessage, getAIModel, getAuthSession, getEmbeddingModel, getLockedUntilMs, hasEmbeddingApiKey, hashContent, hashPassword, isAuthSessionActive, issueAuthSessionToken, normalizeFieldValue, registerRoutes, resolveAuthLockoutConfig, revokeAllAuthSessions, revokeAuthSession, sendEmail, serializeDetailForApi, serializeViewForApi, touchAuthSession, validatePayloadAgainstFields, verifyPassword };