@ima-jin/config 0.7.0 → 0.8.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.
@@ -1,7 +1,162 @@
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
+ HANDLE_ALLOWED_CHARS: () => HANDLE_ALLOWED_CHARS,
25
+ HANDLE_ERROR: () => HANDLE_ERROR,
26
+ HANDLE_INPUT_PATTERN: () => HANDLE_INPUT_PATTERN,
27
+ HANDLE_PATTERN: () => HANDLE_PATTERN,
28
+ RESERVED_HANDLES: () => RESERVED_HANDLES,
29
+ SERVICES: () => SERVICES,
30
+ SERVICE_NAMES: () => SERVICE_NAMES,
31
+ SESSION_COOKIE_NAME: () => SESSION_COOKIE_NAME,
32
+ apiFetch: () => apiFetch,
33
+ apiUrl: () => apiUrl,
34
+ articleAuthorPath: () => articleAuthorPath,
35
+ articlePath: () => articlePath,
36
+ articlesPath: () => articlesPath,
37
+ authAgentsPath: () => authAgentsPath,
38
+ authAppsPath: () => authAppsPath,
39
+ authAttestationsPath: () => authAttestationsPath,
40
+ authAuthorizePath: () => authAuthorizePath,
41
+ authDeveloperAppPath: () => authDeveloperAppPath,
42
+ authDeveloperAppsPath: () => authDeveloperAppsPath,
43
+ authGroupSettingsPath: () => authGroupSettingsPath,
44
+ authGroupsPath: () => authGroupsPath,
45
+ authLoginPath: () => authLoginPath,
46
+ authMembersPath: () => authMembersPath,
47
+ authNewGroupPath: () => authNewGroupPath,
48
+ authNewStubPath: () => authNewStubPath,
49
+ authNotificationsPath: () => authNotificationsPath,
50
+ authOnboardPath: () => authOnboardPath,
51
+ authRegisterPath: () => authRegisterPath,
52
+ authSecurityPath: () => authSecurityPath,
53
+ authSettingsPath: () => authSettingsPath,
54
+ authStubsPath: () => authStubsPath,
55
+ bugsAdminPath: () => bugsAdminPath,
56
+ bugsPath: () => bugsPath,
57
+ buildPath: () => buildPath,
58
+ buildPublicUrl: () => buildPublicUrl,
59
+ buildPublicUrlAbsolute: () => buildPublicUrlAbsolute,
60
+ buildServiceUrlMap: () => buildServiceUrlMap,
61
+ bumpPath: () => bumpPath,
62
+ chatConversationPath: () => chatConversationPath,
63
+ chatConversationsPath: () => chatConversationsPath,
64
+ chatPath: () => chatPath,
65
+ coffeeDashboardPath: () => coffeeDashboardPath,
66
+ coffeeEditPath: () => coffeeEditPath,
67
+ coffeeHandlePath: () => coffeeHandlePath,
68
+ coffeeSuccessPath: () => coffeeSuccessPath,
69
+ connectionsInvitePath: () => connectionsInvitePath,
70
+ connectionsPath: () => connectionsPath,
71
+ connectionsPodPath: () => connectionsPodPath,
72
+ corsHeaders: () => corsHeaders,
73
+ corsOptions: () => corsOptions,
74
+ developerGuidePath: () => developerGuidePath,
75
+ docsPath: () => docsPath,
76
+ dykilCreatePath: () => dykilCreatePath,
77
+ dykilDashboardPath: () => dykilDashboardPath,
78
+ dykilEmbedPath: () => dykilEmbedPath,
79
+ dykilHandlePath: () => dykilHandlePath,
80
+ dykilResultsPath: () => dykilResultsPath,
81
+ dykilSurveyPath: () => dykilSurveyPath,
82
+ eventAdminPath: () => eventAdminPath,
83
+ eventCheckoutSuccessPath: () => eventCheckoutSuccessPath,
84
+ eventEditPath: () => eventEditPath,
85
+ eventEditUrl: () => eventEditUrl,
86
+ eventMyTicketsPath: () => eventMyTicketsPath,
87
+ eventMyTicketsUrl: () => eventMyTicketsUrl,
88
+ eventPath: () => eventPath,
89
+ eventRegisterPath: () => eventRegisterPath,
90
+ eventRegisterUrl: () => eventRegisterUrl,
91
+ eventUrl: () => eventUrl,
92
+ eventsAdminListPath: () => eventsAdminListPath,
93
+ eventsCheckoutSuccessPath: () => eventsCheckoutSuccessPath,
94
+ eventsCreatePath: () => eventsCreatePath,
95
+ eventsDashboardPath: () => eventsDashboardPath,
96
+ getClientIP: () => getClientIP,
97
+ getPort: () => getPort,
98
+ getPublicUrl: () => getPublicUrl,
99
+ getService: () => getService,
100
+ getServiceUrl: () => getServiceUrl,
101
+ getSessionCookieName: () => getSessionCookieName,
102
+ getSessionCookieOptions: () => getSessionCookieOptions,
103
+ healthPath: () => healthPath,
104
+ isAllowedOrigin: () => isAllowedOrigin,
105
+ isReservedHandle: () => isReservedHandle,
106
+ isValidHandle: () => isValidHandle,
107
+ learnCourseDashboardPath: () => learnCourseDashboardPath,
108
+ learnCourseLessonPath: () => learnCourseLessonPath,
109
+ learnCoursePath: () => learnCoursePath,
110
+ learnCoursePresentPath: () => learnCoursePresentPath,
111
+ learnCourseStudentsPath: () => learnCourseStudentsPath,
112
+ learnDashboardPath: () => learnDashboardPath,
113
+ learnHandlePath: () => learnHandlePath,
114
+ linksDashboardPath: () => linksDashboardPath,
115
+ linksEditPath: () => linksEditPath,
116
+ linksHandlePath: () => linksHandlePath,
117
+ marketCheckoutSuccessPath: () => marketCheckoutSuccessPath,
118
+ marketDashboardPath: () => marketDashboardPath,
119
+ marketListingEditPath: () => marketListingEditPath,
120
+ marketListingPath: () => marketListingPath,
121
+ marketNewListingPath: () => marketNewListingPath,
122
+ marketSellerPath: () => marketSellerPath,
123
+ marketSettingsPath: () => marketSettingsPath,
124
+ mediaPath: () => mediaPath,
125
+ normalizeHandleInput: () => normalizeHandleInput,
126
+ notifyPath: () => notifyPath,
127
+ notifySettingsPath: () => notifySettingsPath,
128
+ payHistoryPath: () => payHistoryPath,
129
+ payPath: () => payPath,
130
+ payPayoutsPath: () => payPayoutsPath,
131
+ payTopupPath: () => payTopupPath,
132
+ payTopupSuccessPath: () => payTopupSuccessPath,
133
+ privacyPath: () => privacyPath,
134
+ profileEditPath: () => profileEditPath,
135
+ profileLoginPath: () => profileLoginPath,
136
+ profilePath: () => profilePath,
137
+ profileRegisterPath: () => profileRegisterPath,
138
+ profileUrl: () => profileUrl,
139
+ projectPath: () => projectPath,
140
+ rateLimit: () => rateLimit,
141
+ registryDocsPath: () => registryDocsPath,
142
+ registryPath: () => registryPath,
143
+ servicesByTier: () => servicesByTier,
144
+ servicesByVisibility: () => servicesByVisibility,
145
+ subscribePath: () => subscribePath,
146
+ tier1Headers: () => tier1Headers,
147
+ tier2Headers: () => tier2Headers,
148
+ tier3Headers: () => tier3Headers,
149
+ validateOrigin: () => validateOrigin,
150
+ whitepaperPath: () => whitepaperPath,
151
+ withCors: () => withCors
152
+ });
153
+ module.exports = __toCommonJS(index_exports);
154
+
1
155
  // src/cors.ts
2
- import { NextResponse } from "next/server";
156
+ var import_server = require("next/server");
3
157
  var ORIGIN_PATTERN = /^https:\/\/(dev-)?[a-z-]+\.imajin\.ai$/;
4
158
  var LOCAL_PATTERN = /^http:\/\/localhost:\d+$/;
159
+ var ALLOWED_FRAME_ORIGINS = "https://*.imajin.ai https://imajin.ai";
5
160
  function isAllowedOrigin(origin) {
6
161
  if (!origin) return false;
7
162
  if (ORIGIN_PATTERN.test(origin)) return true;
@@ -20,7 +175,7 @@ function corsHeaders(request) {
20
175
  };
21
176
  }
22
177
  function corsOptions(request) {
23
- return new NextResponse(null, { status: 204, headers: corsHeaders(request) });
178
+ return new import_server.NextResponse(null, { status: 204, headers: corsHeaders(request) });
24
179
  }
25
180
  function withCors(response, request) {
26
181
  const headers = corsHeaders(request);
@@ -35,6 +190,27 @@ function validateOrigin(request) {
35
190
  return isAllowedOrigin(origin);
36
191
  }
37
192
 
193
+ // src/security-headers.ts
194
+ function buildFrameAncestors() {
195
+ const local = process.env.NODE_ENV !== "production" ? " http://localhost:*" : "";
196
+ return `frame-ancestors 'self' ${ALLOWED_FRAME_ORIGINS}${local}`;
197
+ }
198
+ function tier1Headers() {
199
+ return [
200
+ { key: "Content-Security-Policy", value: "frame-ancestors 'none'" },
201
+ { key: "X-Frame-Options", value: "DENY" }
202
+ ];
203
+ }
204
+ function tier2Headers() {
205
+ return [{ key: "Content-Security-Policy", value: buildFrameAncestors() }];
206
+ }
207
+ function tier3Headers() {
208
+ return [
209
+ { key: "X-Content-Type-Options", value: "nosniff" },
210
+ { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" }
211
+ ];
212
+ }
213
+
38
214
  // src/services.ts
39
215
  var SERVICES = [
40
216
  // Kernel services — individually visible, all run on the kernel process (port 3000/7000)
@@ -58,7 +234,9 @@ var SERVICES = [
58
234
  // Meta — project info and external resources surfaced in the launcher
59
235
  { 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
236
  { 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" }
237
+ { 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" },
238
+ // Daemon processes — not web apps, no HTTP port exposed
239
+ { 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" }
62
240
  // Connected apps (separate repos) will use the plugin architecture (#249).
63
241
  // Not included here — they authenticate via delegated sessions, not the monorepo manifest.
64
242
  ];
@@ -67,7 +245,8 @@ function getService(name) {
67
245
  }
68
246
  function getPort(name, env = "dev") {
69
247
  const svc = getService(name);
70
- return svc ? env === "prod" ? svc.prodPort : svc.devPort : void 0;
248
+ if (!svc) return void 0;
249
+ return env === "prod" ? svc.prodPort : svc.devPort;
71
250
  }
72
251
  function getServiceUrl(name, env = "dev") {
73
252
  const port = getPort(name, env);
@@ -75,18 +254,18 @@ function getServiceUrl(name, env = "dev") {
75
254
  }
76
255
  function getPublicUrl(name, options) {
77
256
  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) {
257
+ if (svc?.externalUrl) return svc.externalUrl;
258
+ const domain = options?.domain || "imajin.ai";
259
+ const prefix = options?.prefix;
260
+ if (svc?.wwwPath) {
82
261
  const wwwUrl = getPublicUrl("www", options);
83
262
  return `${wwwUrl}${svc.wwwPath}`;
84
263
  }
85
- if (domain.includes("localhost") || (prefix == null ? void 0 : prefix.includes("localhost"))) {
264
+ if (domain.includes("localhost") || prefix?.includes("localhost")) {
86
265
  const port = getPort(name, "dev");
87
266
  return port ? `http://localhost:${port}` : `http://localhost:3000`;
88
267
  }
89
- if (prefix && prefix.includes(".")) {
268
+ if (prefix?.includes(".")) {
90
269
  const base = prefix.endsWith("/") ? prefix.slice(0, -1) : prefix;
91
270
  if (name === "www" || name === "kernel") return `https://${base}`;
92
271
  return `https://${base}/${name}`;
@@ -100,8 +279,8 @@ function buildPublicUrl(name, servicePrefix, domain) {
100
279
  const explicit = process.env[envKey];
101
280
  if (explicit) return explicit;
102
281
  }
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";
282
+ const p = servicePrefix ?? (typeof process === "undefined" ? void 0 : process.env.NEXT_PUBLIC_SERVICE_PREFIX) ?? "https://";
283
+ const d = domain ?? (typeof process === "undefined" ? void 0 : process.env.NEXT_PUBLIC_DOMAIN) ?? "imajin.ai";
105
284
  if (p.includes("localhost") || d.includes("localhost")) {
106
285
  const port = getPort(name, "dev");
107
286
  return port ? `http://localhost:${port}` : `http://localhost:3000`;
@@ -112,6 +291,20 @@ function buildPublicUrl(name, servicePrefix, domain) {
112
291
  const match = p.replace(/^https?:\/\//, "").replace(/-$/, "") || void 0;
113
292
  return getPublicUrl(name, { prefix: match, domain: d });
114
293
  }
294
+ function buildPublicUrlAbsolute(name) {
295
+ if (typeof process !== "undefined") {
296
+ const explicit = process.env[`NEXT_PUBLIC_${name.toUpperCase()}_URL`];
297
+ if (explicit && /^https?:\/\//.test(explicit)) return explicit;
298
+ }
299
+ const prefix = (typeof process === "undefined" ? void 0 : process.env.NEXT_PUBLIC_SERVICE_PREFIX) ?? "https://";
300
+ const domain = (typeof process === "undefined" ? void 0 : process.env.NEXT_PUBLIC_DOMAIN) ?? "imajin.ai";
301
+ if (prefix.includes("localhost") || domain.includes("localhost")) {
302
+ const port = getPort(name, "dev");
303
+ return port ? `http://localhost:${port}` : "http://localhost:3000";
304
+ }
305
+ const match = prefix.replace(/^https?:\/\//, "").replace(/-$/, "") || void 0;
306
+ return getPublicUrl(name, { prefix: match, domain });
307
+ }
115
308
  var SERVICE_NAMES = SERVICES.map((s) => s.name);
116
309
  function servicesByTier(tier) {
117
310
  return SERVICES.filter((s) => s.tier === tier);
@@ -173,10 +366,45 @@ function apiFetch(path, init) {
173
366
  return fetch(apiUrl(path), init);
174
367
  }
175
368
 
369
+ // src/rate-limit.ts
370
+ var store = /* @__PURE__ */ new Map();
371
+ var lastGlobalCleanup = Date.now();
372
+ function pruneStore(now) {
373
+ if (now - lastGlobalCleanup < 6e4) return;
374
+ store.forEach((entry, key) => {
375
+ if (now - entry.lastSeen > 12e4) {
376
+ store.delete(key);
377
+ }
378
+ });
379
+ lastGlobalCleanup = now;
380
+ }
381
+ function rateLimit(key, limit, windowMs) {
382
+ const now = Date.now();
383
+ pruneStore(now);
384
+ const windowStart = now - windowMs;
385
+ const entry = store.get(key) ?? { timestamps: [], lastSeen: now };
386
+ entry.timestamps = entry.timestamps.filter((t) => t > windowStart);
387
+ entry.lastSeen = now;
388
+ if (entry.timestamps.length >= limit) {
389
+ const oldest = entry.timestamps[0];
390
+ const retryAfter = Math.ceil((oldest + windowMs - now) / 1e3);
391
+ store.set(key, entry);
392
+ return { limited: true, retryAfter: Math.max(1, retryAfter) };
393
+ }
394
+ entry.timestamps.push(now);
395
+ store.set(key, entry);
396
+ return { limited: false, retryAfter: 0 };
397
+ }
398
+ function getClientIP(request) {
399
+ const forwarded = request.headers.get("x-forwarded-for");
400
+ if (forwarded) return forwarded.split(",")[0].trim();
401
+ return "127.0.0.1";
402
+ }
403
+
176
404
  // src/handles.ts
177
405
  var HANDLE_PATTERN = /^[a-z0-9._-]{3,30}$/;
178
- var HANDLE_EDGE = /^[.\-]|[.\-]$/;
179
- var HANDLE_CONSECUTIVE = /[.\-]{2}/;
406
+ var HANDLE_EDGE = /^[.-]|[.-]$/;
407
+ var HANDLE_CONSECUTIVE = /[.-]{2}/;
180
408
  var HANDLE_INPUT_PATTERN = "[a-z0-9._\\-]{3,30}";
181
409
  var HANDLE_ALLOWED_CHARS = /[^a-z0-9._-]/g;
182
410
  var RESERVED_HANDLES = /* @__PURE__ */ new Set([
@@ -320,7 +548,9 @@ var docsPath = () => `/docs`;
320
548
  var projectPath = () => `/project`;
321
549
  var notifyPath = () => `/notify`;
322
550
  var notifySettingsPath = () => `/notify/settings`;
323
- export {
551
+ // Annotate the CommonJS export names for ESM import in node:
552
+ 0 && (module.exports = {
553
+ ALLOWED_FRAME_ORIGINS,
324
554
  HANDLE_ALLOWED_CHARS,
325
555
  HANDLE_ERROR,
326
556
  HANDLE_INPUT_PATTERN,
@@ -356,6 +586,7 @@ export {
356
586
  bugsPath,
357
587
  buildPath,
358
588
  buildPublicUrl,
589
+ buildPublicUrlAbsolute,
359
590
  buildServiceUrlMap,
360
591
  bumpPath,
361
592
  chatConversationPath,
@@ -392,6 +623,7 @@ export {
392
623
  eventsCheckoutSuccessPath,
393
624
  eventsCreatePath,
394
625
  eventsDashboardPath,
626
+ getClientIP,
395
627
  getPort,
396
628
  getPublicUrl,
397
629
  getService,
@@ -435,12 +667,16 @@ export {
435
667
  profileRegisterPath,
436
668
  profileUrl,
437
669
  projectPath,
670
+ rateLimit,
438
671
  registryDocsPath,
439
672
  registryPath,
440
673
  servicesByTier,
441
674
  servicesByVisibility,
442
675
  subscribePath,
676
+ tier1Headers,
677
+ tier2Headers,
678
+ tier3Headers,
443
679
  validateOrigin,
444
680
  whitepaperPath,
445
681
  withCors
446
- };
682
+ });