@ima-jin/config 0.7.0 → 0.8.13

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.
@@ -1,7 +1,168 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ALLOWED_FRAME_ORIGINS: () => ALLOWED_FRAME_ORIGINS,
24
+ APP_DISPLAY_NAME: () => APP_DISPLAY_NAME,
25
+ HANDLE_ALLOWED_CHARS: () => HANDLE_ALLOWED_CHARS,
26
+ HANDLE_ERROR: () => HANDLE_ERROR,
27
+ HANDLE_INPUT_PATTERN: () => HANDLE_INPUT_PATTERN,
28
+ HANDLE_PATTERN: () => HANDLE_PATTERN,
29
+ RESERVED_HANDLES: () => RESERVED_HANDLES,
30
+ SERVICES: () => SERVICES,
31
+ SERVICE_NAMES: () => SERVICE_NAMES,
32
+ SESSION_COOKIE_NAME: () => SESSION_COOKIE_NAME,
33
+ apiFetch: () => apiFetch,
34
+ apiUrl: () => apiUrl,
35
+ articleAuthorPath: () => articleAuthorPath,
36
+ articlePath: () => articlePath,
37
+ articlesPath: () => articlesPath,
38
+ authAgentsPath: () => authAgentsPath,
39
+ authAppsPath: () => authAppsPath,
40
+ authAttestationsPath: () => authAttestationsPath,
41
+ authAuthorizePath: () => authAuthorizePath,
42
+ authDeveloperAppPath: () => authDeveloperAppPath,
43
+ authDeveloperAppsPath: () => authDeveloperAppsPath,
44
+ authGroupSettingsPath: () => authGroupSettingsPath,
45
+ authGroupsPath: () => authGroupsPath,
46
+ authLoginPath: () => authLoginPath,
47
+ authMembersPath: () => authMembersPath,
48
+ authNewGroupPath: () => authNewGroupPath,
49
+ authNewStubPath: () => authNewStubPath,
50
+ authNotificationsPath: () => authNotificationsPath,
51
+ authOnboardPath: () => authOnboardPath,
52
+ authRegisterPath: () => authRegisterPath,
53
+ authSecurityPath: () => authSecurityPath,
54
+ authSettingsPath: () => authSettingsPath,
55
+ authStubsPath: () => authStubsPath,
56
+ bugsAdminPath: () => bugsAdminPath,
57
+ bugsPath: () => bugsPath,
58
+ buildPath: () => buildPath,
59
+ buildPublicUrl: () => buildPublicUrl,
60
+ buildPublicUrlAbsolute: () => buildPublicUrlAbsolute,
61
+ buildServiceUrlMap: () => buildServiceUrlMap,
62
+ bumpPath: () => bumpPath,
63
+ chatConversationPath: () => chatConversationPath,
64
+ chatConversationsPath: () => chatConversationsPath,
65
+ chatPath: () => chatPath,
66
+ coffeeDashboardPath: () => coffeeDashboardPath,
67
+ coffeeEditPath: () => coffeeEditPath,
68
+ coffeeHandlePath: () => coffeeHandlePath,
69
+ coffeeSuccessPath: () => coffeeSuccessPath,
70
+ connectionsInvitePath: () => connectionsInvitePath,
71
+ connectionsPath: () => connectionsPath,
72
+ connectionsPodPath: () => connectionsPodPath,
73
+ corsHeaders: () => corsHeaders,
74
+ corsOptions: () => corsOptions,
75
+ developerGuidePath: () => developerGuidePath,
76
+ docsPath: () => docsPath,
77
+ dykilCreatePath: () => dykilCreatePath,
78
+ dykilDashboardPath: () => dykilDashboardPath,
79
+ dykilEmbedPath: () => dykilEmbedPath,
80
+ dykilHandlePath: () => dykilHandlePath,
81
+ dykilResultsPath: () => dykilResultsPath,
82
+ dykilSurveyPath: () => dykilSurveyPath,
83
+ eventAdminPath: () => eventAdminPath,
84
+ eventCheckoutSuccessPath: () => eventCheckoutSuccessPath,
85
+ eventEditPath: () => eventEditPath,
86
+ eventEditUrl: () => eventEditUrl,
87
+ eventMyTicketsPath: () => eventMyTicketsPath,
88
+ eventMyTicketsUrl: () => eventMyTicketsUrl,
89
+ eventPath: () => eventPath,
90
+ eventRegisterPath: () => eventRegisterPath,
91
+ eventRegisterUrl: () => eventRegisterUrl,
92
+ eventUrl: () => eventUrl,
93
+ eventsAdminListPath: () => eventsAdminListPath,
94
+ eventsCheckoutSuccessPath: () => eventsCheckoutSuccessPath,
95
+ eventsCreatePath: () => eventsCreatePath,
96
+ eventsDashboardPath: () => eventsDashboardPath,
97
+ getClientIP: () => getClientIP,
98
+ getForestScopeConfig: () => getForestScopeConfig,
99
+ getNodeSelf: () => getNodeSelf,
100
+ getPort: () => getPort,
101
+ getPublicUrl: () => getPublicUrl,
102
+ getService: () => getService,
103
+ getServiceUrl: () => getServiceUrl,
104
+ getSessionCookieName: () => getSessionCookieName,
105
+ getSessionCookieOptions: () => getSessionCookieOptions,
106
+ hasRegistryServiceUrl: () => hasRegistryServiceUrl,
107
+ healthPath: () => healthPath,
108
+ isAllowedOrigin: () => isAllowedOrigin,
109
+ isReservedHandle: () => isReservedHandle,
110
+ isValidHandle: () => isValidHandle,
111
+ learnCourseDashboardPath: () => learnCourseDashboardPath,
112
+ learnCourseLessonPath: () => learnCourseLessonPath,
113
+ learnCoursePath: () => learnCoursePath,
114
+ learnCoursePresentPath: () => learnCoursePresentPath,
115
+ learnCourseStudentsPath: () => learnCourseStudentsPath,
116
+ learnDashboardPath: () => learnDashboardPath,
117
+ learnHandlePath: () => learnHandlePath,
118
+ linksDashboardPath: () => linksDashboardPath,
119
+ linksEditPath: () => linksEditPath,
120
+ linksHandlePath: () => linksHandlePath,
121
+ marketCheckoutSuccessPath: () => marketCheckoutSuccessPath,
122
+ marketDashboardPath: () => marketDashboardPath,
123
+ marketListingEditPath: () => marketListingEditPath,
124
+ marketListingPath: () => marketListingPath,
125
+ marketNewListingPath: () => marketNewListingPath,
126
+ marketSellerPath: () => marketSellerPath,
127
+ marketSettingsPath: () => marketSettingsPath,
128
+ mediaPath: () => mediaPath,
129
+ normalizeHandleInput: () => normalizeHandleInput,
130
+ notifyPath: () => notifyPath,
131
+ notifySettingsPath: () => notifySettingsPath,
132
+ payHistoryPath: () => payHistoryPath,
133
+ payPath: () => payPath,
134
+ payPayoutsPath: () => payPayoutsPath,
135
+ payTopupPath: () => payTopupPath,
136
+ payTopupSuccessPath: () => payTopupSuccessPath,
137
+ privacyPath: () => privacyPath,
138
+ profileEditPath: () => profileEditPath,
139
+ profileLoginPath: () => profileLoginPath,
140
+ profilePath: () => profilePath,
141
+ profileRegisterPath: () => profileRegisterPath,
142
+ profileUrl: () => profileUrl,
143
+ projectPath: () => projectPath,
144
+ rateLimit: () => rateLimit,
145
+ registryDocsPath: () => registryDocsPath,
146
+ registryPath: () => registryPath,
147
+ registryServiceUrl: () => registryServiceUrl,
148
+ servicesByTier: () => servicesByTier,
149
+ servicesByVisibility: () => servicesByVisibility,
150
+ standaloneDashboardMiddleware: () => standaloneDashboardMiddleware,
151
+ subscribePath: () => subscribePath,
152
+ tier1Headers: () => tier1Headers,
153
+ tier2Headers: () => tier2Headers,
154
+ tier3Headers: () => tier3Headers,
155
+ validateOrigin: () => validateOrigin,
156
+ whitepaperPath: () => whitepaperPath,
157
+ withCors: () => withCors
158
+ });
159
+ module.exports = __toCommonJS(index_exports);
160
+
1
161
  // src/cors.ts
2
- import { NextResponse } from "next/server";
162
+ var import_server = require("next/server");
3
163
  var ORIGIN_PATTERN = /^https:\/\/(dev-)?[a-z-]+\.imajin\.ai$/;
4
164
  var LOCAL_PATTERN = /^http:\/\/localhost:\d+$/;
165
+ var ALLOWED_FRAME_ORIGINS = "https://*.imajin.ai https://imajin.ai";
5
166
  function isAllowedOrigin(origin) {
6
167
  if (!origin) return false;
7
168
  if (ORIGIN_PATTERN.test(origin)) return true;
@@ -15,12 +176,12 @@ function corsHeaders(request) {
15
176
  "Access-Control-Allow-Origin": allowed ? origin : "",
16
177
  "Access-Control-Allow-Credentials": "true",
17
178
  "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
18
- "Access-Control-Allow-Headers": "Content-Type, Authorization, X-Caller-DID",
179
+ "Access-Control-Allow-Headers": "Content-Type, Authorization, X-Caller-DID, X-App-DID, X-App-Authorization",
19
180
  "Vary": "Origin"
20
181
  };
21
182
  }
22
183
  function corsOptions(request) {
23
- return new NextResponse(null, { status: 204, headers: corsHeaders(request) });
184
+ return new import_server.NextResponse(null, { status: 204, headers: corsHeaders(request) });
24
185
  }
25
186
  function withCors(response, request) {
26
187
  const headers = corsHeaders(request);
@@ -35,6 +196,9 @@ function validateOrigin(request) {
35
196
  return isAllowedOrigin(origin);
36
197
  }
37
198
 
199
+ // src/dashboard-redirect-middleware.ts
200
+ var import_server2 = require("next/server");
201
+
38
202
  // src/services.ts
39
203
  var SERVICES = [
40
204
  // Kernel services — individually visible, all run on the kernel process (port 3000/7000)
@@ -47,6 +211,11 @@ var SERVICES = [
47
211
  { name: "media", label: "Media", icon: "\u{1F4C1}", description: "Files, images, and .fair attribution", devPort: 3e3, prodPort: 7e3, schema: "media", tier: "core", visibility: "authenticated", category: "kernel" },
48
212
  { name: "registry", label: "Registry", icon: "\u{1F4E1}", description: "Service registry and DFOS relay", devPort: 3e3, prodPort: 7e3, schema: "registry", tier: "core", visibility: "public", category: "kernel" },
49
213
  { name: "notify", label: "Notify", icon: "\u{1F514}", description: "Notifications and preferences", devPort: 3e3, prodPort: 7e3, schema: "notify", tier: "core", visibility: "internal", category: "kernel" },
214
+ { name: "usage", label: "Usage", icon: "\u{1F4CA}", description: "Inference cost ledger \u2014 incurred, billed, drift, signed rollup", devPort: 3e3, prodPort: 7e3, schema: "usage", tier: "core", visibility: "authenticated", category: "kernel" },
215
+ { name: "calendar", label: "Calendar", icon: "\u{1F4C5}", description: "Temporal entries \u2014 availability, meetings, events, and reminders", devPort: 3e3, prodPort: 7e3, schema: null, tier: "core", visibility: "authenticated", category: "kernel" },
216
+ { name: "jin", label: "Jin", icon: "\u{1F9ED}", description: "Operator dashboard \u2014 signed approvals, proposals, and usage feed", devPort: 3e3, prodPort: 7e3, schema: "operator", tier: "core", visibility: "internal", category: "kernel" },
217
+ { name: "google", label: "Google Workspace", icon: "\u{1F4E8}", description: "Gmail/Calendar/Drive/Meet connector \u2014 OAuth2 auth-code, sealed refresh token", devPort: 3e3, prodPort: 7e3, schema: null, tier: "core", visibility: "authenticated", category: "kernel" },
218
+ { name: "vault", label: "Vault", icon: "\u{1F510}", description: "Sealed secrets, delegation grants, and vault-minted service credentials", devPort: 3e3, prodPort: 7e3, schema: null, tier: "core", visibility: "internal", category: "kernel" },
50
219
  // Core apps — separate processes
51
220
  { name: "events", label: "Events", icon: "\u{1F3AB}", description: "Event creation, ticketing, and management", devPort: 3006, prodPort: 7006, schema: "events", tier: "core", visibility: "public", category: "core" },
52
221
  // Imajin apps
@@ -58,7 +227,10 @@ var SERVICES = [
58
227
  // Meta — project info and external resources surfaced in the launcher
59
228
  { name: "project", label: "Project", icon: "\u{1F4D6}", description: "Thesis, whitepaper, essays, RFCs", devPort: 3e3, prodPort: 7e3, schema: "public", tier: "core", visibility: "public", category: "meta", wwwPath: "/project" },
60
229
  { name: "github", label: "GitHub", icon: "\u{1F419}", description: "Source code", devPort: 3e3, prodPort: 7e3, schema: "public", tier: "core", visibility: "public", category: "meta", externalUrl: "https://github.com/ima-jin/imajin-ai" },
61
- { name: "docs", label: "Docs", icon: "\u{1F4C4}", description: "API documentation", devPort: 3e3, prodPort: 7e3, schema: "public", tier: "core", visibility: "public", category: "meta", wwwPath: "/developer-guide" }
230
+ { name: "docs", label: "Docs", icon: "\u{1F4C4}", description: "API documentation", devPort: 3e3, prodPort: 7e3, schema: "public", tier: "core", visibility: "public", category: "meta", wwwPath: "/developer-guide" },
231
+ // Daemon processes — not web apps, no HTTP port exposed
232
+ { name: "broker-agent", label: "Broker Agent", icon: "\u{1F916}", description: "Telegram broker agent \u2014 conversational surface for social coordination (#1101)", devPort: 0, prodPort: 0, schema: null, tier: "core", visibility: "internal", category: "infrastructure" },
233
+ { name: "corpus", label: "Corpus", icon: "\u{1F50E}", description: "Per-DID corpus indexing and BM25 search service (#1737)", devPort: 8013, prodPort: 8013, schema: null, tier: "core", visibility: "internal", category: "infrastructure" }
62
234
  // Connected apps (separate repos) will use the plugin architecture (#249).
63
235
  // Not included here — they authenticate via delegated sessions, not the monorepo manifest.
64
236
  ];
@@ -67,7 +239,8 @@ function getService(name) {
67
239
  }
68
240
  function getPort(name, env = "dev") {
69
241
  const svc = getService(name);
70
- return svc ? env === "prod" ? svc.prodPort : svc.devPort : void 0;
242
+ if (!svc) return void 0;
243
+ return env === "prod" ? svc.prodPort : svc.devPort;
71
244
  }
72
245
  function getServiceUrl(name, env = "dev") {
73
246
  const port = getPort(name, env);
@@ -75,18 +248,18 @@ function getServiceUrl(name, env = "dev") {
75
248
  }
76
249
  function getPublicUrl(name, options) {
77
250
  const svc = SERVICES.find((s) => s.name === name);
78
- if (svc == null ? void 0 : svc.externalUrl) return svc.externalUrl;
79
- const domain = (options == null ? void 0 : options.domain) || "imajin.ai";
80
- const prefix = options == null ? void 0 : options.prefix;
81
- if (svc == null ? void 0 : svc.wwwPath) {
251
+ if (svc?.externalUrl) return svc.externalUrl;
252
+ const domain = options?.domain || "imajin.ai";
253
+ const prefix = options?.prefix;
254
+ if (svc?.wwwPath) {
82
255
  const wwwUrl = getPublicUrl("www", options);
83
256
  return `${wwwUrl}${svc.wwwPath}`;
84
257
  }
85
- if (domain.includes("localhost") || (prefix == null ? void 0 : prefix.includes("localhost"))) {
258
+ if (domain.includes("localhost") || prefix?.includes("localhost")) {
86
259
  const port = getPort(name, "dev");
87
260
  return port ? `http://localhost:${port}` : `http://localhost:3000`;
88
261
  }
89
- if (prefix && prefix.includes(".")) {
262
+ if (prefix?.includes(".")) {
90
263
  const base = prefix.endsWith("/") ? prefix.slice(0, -1) : prefix;
91
264
  if (name === "www" || name === "kernel") return `https://${base}`;
92
265
  return `https://${base}/${name}`;
@@ -100,8 +273,8 @@ function buildPublicUrl(name, servicePrefix, domain) {
100
273
  const explicit = process.env[envKey];
101
274
  if (explicit) return explicit;
102
275
  }
103
- const p = servicePrefix ?? (typeof process !== "undefined" ? process.env.NEXT_PUBLIC_SERVICE_PREFIX : void 0) ?? "https://";
104
- const d = domain ?? (typeof process !== "undefined" ? process.env.NEXT_PUBLIC_DOMAIN : void 0) ?? "imajin.ai";
276
+ const p = servicePrefix ?? (typeof process === "undefined" ? void 0 : process.env.NEXT_PUBLIC_SERVICE_PREFIX) ?? "https://";
277
+ const d = domain ?? (typeof process === "undefined" ? void 0 : process.env.NEXT_PUBLIC_DOMAIN) ?? "imajin.ai";
105
278
  if (p.includes("localhost") || d.includes("localhost")) {
106
279
  const port = getPort(name, "dev");
107
280
  return port ? `http://localhost:${port}` : `http://localhost:3000`;
@@ -112,6 +285,20 @@ function buildPublicUrl(name, servicePrefix, domain) {
112
285
  const match = p.replace(/^https?:\/\//, "").replace(/-$/, "") || void 0;
113
286
  return getPublicUrl(name, { prefix: match, domain: d });
114
287
  }
288
+ function buildPublicUrlAbsolute(name) {
289
+ if (typeof process !== "undefined") {
290
+ const explicit = process.env[`NEXT_PUBLIC_${name.toUpperCase()}_URL`];
291
+ if (explicit && /^https?:\/\//.test(explicit)) return explicit;
292
+ }
293
+ const prefix = (typeof process === "undefined" ? void 0 : process.env.NEXT_PUBLIC_SERVICE_PREFIX) ?? "https://";
294
+ const domain = (typeof process === "undefined" ? void 0 : process.env.NEXT_PUBLIC_DOMAIN) ?? "imajin.ai";
295
+ if (prefix.includes("localhost") || domain.includes("localhost")) {
296
+ const port = getPort(name, "dev");
297
+ return port ? `http://localhost:${port}` : "http://localhost:3000";
298
+ }
299
+ const match = prefix.replace(/^https?:\/\//, "").replace(/-$/, "") || void 0;
300
+ return getPublicUrl(name, { prefix: match, domain });
301
+ }
115
302
  var SERVICE_NAMES = SERVICES.map((s) => s.name);
116
303
  function servicesByTier(tier) {
117
304
  return SERVICES.filter((s) => s.tier === tier);
@@ -129,6 +316,46 @@ function buildServiceUrlMap(env, mode = "dev") {
129
316
  return map;
130
317
  }
131
318
 
319
+ // src/dashboard-redirect-middleware.ts
320
+ function standaloneDashboardMiddleware(request, { service, cors = true }) {
321
+ if (request.nextUrl.pathname === "/dashboard") {
322
+ const hubUrl = new URL(`${buildPublicUrlAbsolute("kernel")}/auth/${service}`);
323
+ hubUrl.search = request.nextUrl.search;
324
+ return import_server2.NextResponse.redirect(hubUrl, 308);
325
+ }
326
+ if (!cors) {
327
+ return import_server2.NextResponse.next();
328
+ }
329
+ if (request.method === "OPTIONS") {
330
+ return new import_server2.NextResponse(null, { status: 204, headers: corsHeaders(request) });
331
+ }
332
+ return withCors(import_server2.NextResponse.next(), request);
333
+ }
334
+
335
+ // src/security-headers.ts
336
+ function buildFrameAncestors() {
337
+ const local = process.env.NODE_ENV !== "production" ? " http://localhost:*" : "";
338
+ return `frame-ancestors 'self' ${ALLOWED_FRAME_ORIGINS}${local}`;
339
+ }
340
+ function tier1Headers() {
341
+ return [
342
+ { key: "Content-Security-Policy", value: "frame-ancestors 'none'" },
343
+ { key: "X-Frame-Options", value: "DENY" }
344
+ ];
345
+ }
346
+ function tier2Headers() {
347
+ return [{ key: "Content-Security-Policy", value: buildFrameAncestors() }];
348
+ }
349
+ function tier3Headers() {
350
+ return [
351
+ { key: "X-Content-Type-Options", value: "nosniff" },
352
+ { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" }
353
+ ];
354
+ }
355
+
356
+ // src/brand.ts
357
+ var APP_DISPLAY_NAME = "imajin (\u03B1)";
358
+
132
359
  // src/session.ts
133
360
  function getSessionCookieName(env) {
134
361
  const resolved = env ?? (typeof process !== "undefined" && (process.env.IMAJIN_ENV === "dev" || process.env.NODE_ENV === "development") ? "dev" : "prod");
@@ -140,8 +367,13 @@ function isLocalhost() {
140
367
  const prefix = process.env.NEXT_PUBLIC_SERVICE_PREFIX ?? "";
141
368
  return prefix.includes("localhost");
142
369
  }
370
+ function isHostScoped() {
371
+ if (typeof process === "undefined") return false;
372
+ return process.env.SESSION_COOKIE_SCOPE === "host";
373
+ }
143
374
  function getSessionCookieOptions(env) {
144
375
  const local = isLocalhost();
376
+ const omitDomain = local || isHostScoped();
145
377
  return {
146
378
  name: getSessionCookieName(env),
147
379
  options: {
@@ -149,7 +381,7 @@ function getSessionCookieOptions(env) {
149
381
  secure: !local,
150
382
  sameSite: local ? "lax" : "none",
151
383
  path: "/",
152
- ...local ? {} : { domain: ".imajin.ai" },
384
+ ...omitDomain ? {} : { domain: ".imajin.ai" },
153
385
  maxAge: 60 * 60 * 24
154
386
  // 24 hours
155
387
  }
@@ -173,11 +405,102 @@ function apiFetch(path, init) {
173
405
  return fetch(apiUrl(path), init);
174
406
  }
175
407
 
408
+ // src/rate-limit.ts
409
+ var store = /* @__PURE__ */ new Map();
410
+ var lastGlobalCleanup = Date.now();
411
+ function pruneStore(now) {
412
+ if (now - lastGlobalCleanup < 6e4) return;
413
+ store.forEach((entry, key) => {
414
+ if (now - entry.lastSeen > 12e4) {
415
+ store.delete(key);
416
+ }
417
+ });
418
+ lastGlobalCleanup = now;
419
+ }
420
+ function rateLimit(key, limit, windowMs) {
421
+ const now = Date.now();
422
+ pruneStore(now);
423
+ const windowStart = now - windowMs;
424
+ const entry = store.get(key) ?? { timestamps: [], lastSeen: now };
425
+ entry.timestamps = entry.timestamps.filter((t) => t > windowStart);
426
+ entry.lastSeen = now;
427
+ if (entry.timestamps.length >= limit) {
428
+ const oldest = entry.timestamps[0];
429
+ const retryAfter = Math.ceil((oldest + windowMs - now) / 1e3);
430
+ store.set(key, entry);
431
+ return { limited: true, retryAfter: Math.max(1, retryAfter) };
432
+ }
433
+ entry.timestamps.push(now);
434
+ store.set(key, entry);
435
+ return { limited: false, retryAfter: 0 };
436
+ }
437
+ function getClientIP(request) {
438
+ const forwarded = request.headers.get("x-forwarded-for");
439
+ if (forwarded) return forwarded.split(",")[0].trim();
440
+ return "127.0.0.1";
441
+ }
442
+
443
+ // src/registry-service-url.ts
444
+ var warnedAboutLegacyRegistryUrl = false;
445
+ function registryServiceUrl() {
446
+ if (process.env.REGISTRY_SERVICE_URL) return process.env.REGISTRY_SERVICE_URL;
447
+ if (process.env.REGISTRY_URL) {
448
+ if (!warnedAboutLegacyRegistryUrl) {
449
+ console.warn("REGISTRY_URL is deprecated \u2014 set REGISTRY_SERVICE_URL");
450
+ warnedAboutLegacyRegistryUrl = true;
451
+ }
452
+ return process.env.REGISTRY_URL;
453
+ }
454
+ return `http://localhost:${process.env.PORT || 3e3}/registry`;
455
+ }
456
+ function hasRegistryServiceUrl() {
457
+ return Boolean(process.env.REGISTRY_SERVICE_URL || process.env.REGISTRY_URL);
458
+ }
459
+
460
+ // src/node-self.ts
461
+ async function getNodeSelf() {
462
+ const url = `${registryServiceUrl()}/api/node/self`;
463
+ try {
464
+ const res = await fetch(url);
465
+ if (!res.ok) {
466
+ console.warn(`[config] getNodeSelf: registry returned ${res.status} for ${url} \u2014 check REGISTRY_SERVICE_URL`);
467
+ return null;
468
+ }
469
+ return await res.json();
470
+ } catch (err) {
471
+ console.warn(`[config] getNodeSelf: fetch failed for ${url} \u2014 ${err instanceof Error ? err.message : String(err)}`);
472
+ return null;
473
+ }
474
+ }
475
+
476
+ // src/forest-config.ts
477
+ function profileBaseUrl() {
478
+ if (process.env.PROFILE_SERVICE_URL) return process.env.PROFILE_SERVICE_URL;
479
+ const mode = process.env.NODE_ENV === "production" ? "prod" : "dev";
480
+ const base = getServiceUrl("profile", mode) ?? "http://localhost:3000";
481
+ return `${base}/profile`;
482
+ }
483
+ async function getForestScopeConfig(groupDid) {
484
+ const url = `${profileBaseUrl()}/api/forest/${encodeURIComponent(groupDid)}/config/public`;
485
+ try {
486
+ const res = await fetch(url);
487
+ if (!res.ok) {
488
+ console.warn(`[config] getForestScopeConfig: profile service returned ${res.status} for ${url}`);
489
+ return null;
490
+ }
491
+ const data = await res.json();
492
+ return { scopeFeeBps: typeof data?.scopeFeeBps === "number" ? data.scopeFeeBps : null };
493
+ } catch (err) {
494
+ console.warn(`[config] getForestScopeConfig: fetch failed for ${url} \u2014 ${err instanceof Error ? err.message : String(err)}`);
495
+ return null;
496
+ }
497
+ }
498
+
176
499
  // src/handles.ts
177
500
  var HANDLE_PATTERN = /^[a-z0-9._-]{3,30}$/;
178
- var HANDLE_EDGE = /^[.\-]|[.\-]$/;
179
- var HANDLE_CONSECUTIVE = /[.\-]{2}/;
180
- var HANDLE_INPUT_PATTERN = "[a-z0-9._\\-]{3,30}";
501
+ var HANDLE_EDGE = /^[.-]|[.-]$/;
502
+ var HANDLE_CONSECUTIVE = /[.-]{2}/;
503
+ var HANDLE_INPUT_PATTERN = String.raw`[a-z0-9._\-]{3,30}`;
181
504
  var HANDLE_ALLOWED_CHARS = /[^a-z0-9._-]/g;
182
505
  var RESERVED_HANDLES = /* @__PURE__ */ new Set([
183
506
  "admin",
@@ -320,7 +643,10 @@ var docsPath = () => `/docs`;
320
643
  var projectPath = () => `/project`;
321
644
  var notifyPath = () => `/notify`;
322
645
  var notifySettingsPath = () => `/notify/settings`;
323
- export {
646
+ // Annotate the CommonJS export names for ESM import in node:
647
+ 0 && (module.exports = {
648
+ ALLOWED_FRAME_ORIGINS,
649
+ APP_DISPLAY_NAME,
324
650
  HANDLE_ALLOWED_CHARS,
325
651
  HANDLE_ERROR,
326
652
  HANDLE_INPUT_PATTERN,
@@ -356,6 +682,7 @@ export {
356
682
  bugsPath,
357
683
  buildPath,
358
684
  buildPublicUrl,
685
+ buildPublicUrlAbsolute,
359
686
  buildServiceUrlMap,
360
687
  bumpPath,
361
688
  chatConversationPath,
@@ -392,12 +719,16 @@ export {
392
719
  eventsCheckoutSuccessPath,
393
720
  eventsCreatePath,
394
721
  eventsDashboardPath,
722
+ getClientIP,
723
+ getForestScopeConfig,
724
+ getNodeSelf,
395
725
  getPort,
396
726
  getPublicUrl,
397
727
  getService,
398
728
  getServiceUrl,
399
729
  getSessionCookieName,
400
730
  getSessionCookieOptions,
731
+ hasRegistryServiceUrl,
401
732
  healthPath,
402
733
  isAllowedOrigin,
403
734
  isReservedHandle,
@@ -435,12 +766,18 @@ export {
435
766
  profileRegisterPath,
436
767
  profileUrl,
437
768
  projectPath,
769
+ rateLimit,
438
770
  registryDocsPath,
439
771
  registryPath,
772
+ registryServiceUrl,
440
773
  servicesByTier,
441
774
  servicesByVisibility,
775
+ standaloneDashboardMiddleware,
442
776
  subscribePath,
777
+ tier1Headers,
778
+ tier2Headers,
779
+ tier3Headers,
443
780
  validateOrigin,
444
781
  whitepaperPath,
445
782
  withCors
446
- };
783
+ });