@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.
- package/dist/{index.mjs → index.cjs} +356 -19
- package/dist/index.d.cts +485 -0
- package/dist/index.d.ts +485 -0
- package/dist/index.js +195 -166
- package/next-headers.cjs +57 -0
- package/package.json +17 -10
- package/src/base-path.ts +10 -10
- package/src/brand.ts +12 -0
- package/src/cors.ts +8 -1
- package/src/dashboard-redirect-middleware.ts +56 -0
- package/src/forest-config.ts +51 -0
- package/src/handles.ts +3 -3
- package/src/index.ts +16 -1
- package/src/node-self.ts +45 -0
- package/src/rate-limit.ts +54 -0
- package/src/registry-service-url.ts +54 -0
- package/src/security-headers.ts +45 -0
- package/src/services.ts +65 -6
- package/src/session.ts +28 -1
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
79
|
-
const domain =
|
|
80
|
-
const prefix = options
|
|
81
|
-
if (svc
|
|
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") ||
|
|
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
|
|
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
|
|
104
|
-
const d = domain ?? (typeof process
|
|
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
|
-
...
|
|
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 = /[
|
|
180
|
-
var HANDLE_INPUT_PATTERN =
|
|
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
|
+
});
|