@anthusai/papyrus 2.0.0-next.91 → 2.0.0-next.92
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/amplify/functions/monitoring-view/schema.js +6 -0
- package/amplify/functions/monitoring-view/schema.ts +6 -0
- package/app/api/newsroom/chat/[...path]/route.ts +17 -0
- package/app/layout.tsx +5 -1
- package/components/monitoring-overview-view.tsx +48 -2
- package/components/monitoring-panel.tsx +11 -3
- package/components/papyrus-console-conversation.css +14 -0
- package/components/papyrus-console-conversation.tsx +55 -0
- package/components/papyrus-console-shell.tsx +62 -420
- package/components/papyrus-private-chat-panel.tsx +134 -0
- package/infra/amplify-app-shell.js +2 -0
- package/infra/amplify-app-shell.ts +2 -0
- package/infra/site-config.js +4 -0
- package/infra/site-config.ts +4 -0
- package/lib/monitoring-client.ts +20 -15
- package/lib/monitoring-overview.ts +13 -0
- package/lib/papyrus-chat-admission.ts +65 -0
- package/lib/papyrus-hosted-chat.ts +217 -0
- package/lib/papyrus-private-chat-client.ts +81 -0
- package/lib/prospectus-session.ts +15 -0
- package/lib/prospectus-sign-in-routes.ts +2 -12
- package/lib/shared-chat-admission.ts +182 -0
- package/lib/site-origin-value.ts +50 -0
- package/lib/site-origin.ts +3 -62
- package/package.json +10 -1
- package/routes.manifest.json +13 -1
- package/src/with-papyrus.mjs +1 -1
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
PROSPECTUS_SESSION_COOKIE,
|
|
13
13
|
openProspectusCookie,
|
|
14
14
|
resolveProspectusSignInRuntime,
|
|
15
|
+
signedInProspectusSession,
|
|
15
16
|
sameSiteReturnPath,
|
|
16
17
|
sealProspectusCookie,
|
|
17
18
|
sealedCookieAttributes,
|
|
@@ -115,18 +116,7 @@ function signInFailedRedirect(request: NextRequest, options: ProspectusSignInRou
|
|
|
115
116
|
return NextResponse.redirect(target, { status: 303, headers: NO_STORE_HEADERS });
|
|
116
117
|
}
|
|
117
118
|
|
|
118
|
-
export
|
|
119
|
-
request: NextRequest,
|
|
120
|
-
sealingSecret: string,
|
|
121
|
-
nowInSeconds?: number,
|
|
122
|
-
): ProspectusSignedInSession | null {
|
|
123
|
-
return openProspectusCookie<ProspectusSignedInSession>(
|
|
124
|
-
sealingSecret,
|
|
125
|
-
PROSPECTUS_SESSION_COOKIE,
|
|
126
|
-
request.cookies.get(PROSPECTUS_SESSION_COOKIE)?.value,
|
|
127
|
-
nowInSeconds,
|
|
128
|
-
);
|
|
129
|
-
}
|
|
119
|
+
export { signedInProspectusSession } from "./prospectus-session";
|
|
130
120
|
|
|
131
121
|
/** `returnTo` from the query (a link) or, for the POST form the reader plugin's button submits, from the form body. */
|
|
132
122
|
async function requestedReturnPath(request: NextRequest): Promise<string | null> {
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code-local trust contract for a site-hosted shared chat adapter.
|
|
3
|
+
*
|
|
4
|
+
* This module does not verify JWT signatures and is not an HTTP endpoint. The
|
|
5
|
+
* hosting server must inject a real verifier and authoritative membership
|
|
6
|
+
* resolver. Never construct VerifiedChatCredential from request JSON.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export type TokenUse = string;
|
|
10
|
+
|
|
11
|
+
/** Claims returned only after the injected host verifier has validated the JWT. */
|
|
12
|
+
export interface VerifiedChatCredential {
|
|
13
|
+
subject: string;
|
|
14
|
+
issuer: string;
|
|
15
|
+
audiences: readonly string[];
|
|
16
|
+
clientId?: string;
|
|
17
|
+
tokenUse?: TokenUse;
|
|
18
|
+
expiresAtEpochSeconds: number;
|
|
19
|
+
notBeforeEpochSeconds?: number;
|
|
20
|
+
issuedAtEpochSeconds?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface AudienceRule {
|
|
24
|
+
/** Explicitly choose which JWT claim is authoritative for this host. */
|
|
25
|
+
claim: "aud" | "client_id";
|
|
26
|
+
expectedValue: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface ChatHostTrustProfile {
|
|
30
|
+
issuer: string;
|
|
31
|
+
audienceRule: AudienceRule;
|
|
32
|
+
/** Must be configured by the host after verifying its actual token contract. */
|
|
33
|
+
acceptedTokenUses: readonly TokenUse[];
|
|
34
|
+
configuredSiteId: string;
|
|
35
|
+
clockSkewSeconds?: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface ChatRequest {
|
|
39
|
+
authorization?: string;
|
|
40
|
+
channelId: string;
|
|
41
|
+
idempotencyKey: string;
|
|
42
|
+
message: { text: string; authorSub?: string; accountId?: string; siteId?: string };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface ChatMembership {
|
|
46
|
+
accountId: string;
|
|
47
|
+
siteId: string;
|
|
48
|
+
editorSub: string;
|
|
49
|
+
active: boolean;
|
|
50
|
+
/** Host-derived authorization for the editorial chat surface (editor/admin policy). */
|
|
51
|
+
canUseEditorialChat: boolean;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface TranscriptOwner {
|
|
55
|
+
accountId: string;
|
|
56
|
+
siteId: string;
|
|
57
|
+
editorSub: string;
|
|
58
|
+
channelId: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface SharedChatAdmissionDependencies {
|
|
62
|
+
trust: ChatHostTrustProfile;
|
|
63
|
+
nowEpochSeconds?: () => number;
|
|
64
|
+
verifyCredential: (rawCredential: string) => Promise<VerifiedChatCredential | null>;
|
|
65
|
+
resolveMembership: (subject: string, configuredSiteId: string) => Promise<ChatMembership | null>;
|
|
66
|
+
resolveTranscriptOwner: (channelId: string) => Promise<TranscriptOwner | null>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface AdmittedChatMessage {
|
|
70
|
+
owner: TranscriptOwner;
|
|
71
|
+
idempotencyKey: string;
|
|
72
|
+
/** Stable canonical representation used for payload-reuse detection. */
|
|
73
|
+
payloadFingerprint: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export class ChatAdmissionError extends Error {
|
|
77
|
+
readonly code: "unauthorized" | "forbidden" | "invalid_request" | "idempotency_conflict";
|
|
78
|
+
|
|
79
|
+
constructor(code: ChatAdmissionError["code"]) {
|
|
80
|
+
super(code);
|
|
81
|
+
this.name = "ChatAdmissionError";
|
|
82
|
+
this.code = code;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const reject = (code: ChatAdmissionError["code"]): never => { throw new ChatAdmissionError(code); };
|
|
87
|
+
|
|
88
|
+
function bearerToken(value: string | undefined): string {
|
|
89
|
+
const match = value?.match(/^Bearer ([^\s]+)$/i);
|
|
90
|
+
if (!match) return reject("unauthorized");
|
|
91
|
+
return match[1];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function assertCredential(credential: VerifiedChatCredential, trust: ChatHostTrustProfile, now: number): void {
|
|
95
|
+
const skew = Math.max(0, trust.clockSkewSeconds ?? 0);
|
|
96
|
+
if (!trust.issuer || credential.issuer !== trust.issuer) reject("unauthorized");
|
|
97
|
+
if (!trust.acceptedTokenUses.length || !credential.tokenUse || !trust.acceptedTokenUses.includes(credential.tokenUse)) reject("unauthorized");
|
|
98
|
+
if (!Number.isFinite(credential.expiresAtEpochSeconds) || now - skew >= credential.expiresAtEpochSeconds) reject("unauthorized");
|
|
99
|
+
if (credential.notBeforeEpochSeconds !== undefined && now + skew < credential.notBeforeEpochSeconds) reject("unauthorized");
|
|
100
|
+
if (credential.issuedAtEpochSeconds !== undefined && now + skew < credential.issuedAtEpochSeconds) reject("unauthorized");
|
|
101
|
+
|
|
102
|
+
const audienceMatches = trust.audienceRule.claim === "aud"
|
|
103
|
+
? credential.audiences.includes(trust.audienceRule.expectedValue)
|
|
104
|
+
: credential.clientId === trust.audienceRule.expectedValue;
|
|
105
|
+
if (!audienceMatches) reject("unauthorized");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Authenticate, derive the current host membership, and enforce private channel ownership. */
|
|
109
|
+
export async function admitSharedChatMessage(
|
|
110
|
+
request: ChatRequest,
|
|
111
|
+
dependencies: SharedChatAdmissionDependencies,
|
|
112
|
+
): Promise<AdmittedChatMessage> {
|
|
113
|
+
if (!request.channelId || !request.message.text.trim() || !/^[A-Za-z0-9._~-]{16,128}$/.test(request.idempotencyKey)) {
|
|
114
|
+
return reject("invalid_request");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const rawCredential = bearerToken(request.authorization);
|
|
118
|
+
const credential = await dependencies.verifyCredential(rawCredential);
|
|
119
|
+
if (!credential) return reject("unauthorized");
|
|
120
|
+
const now = (dependencies.nowEpochSeconds ?? (() => Date.now() / 1000))();
|
|
121
|
+
assertCredential(credential, dependencies.trust, now);
|
|
122
|
+
|
|
123
|
+
const membership = await dependencies.resolveMembership(credential.subject, dependencies.trust.configuredSiteId);
|
|
124
|
+
if (!membership || !membership.active || !membership.canUseEditorialChat
|
|
125
|
+
|| membership.editorSub !== credential.subject || membership.siteId !== dependencies.trust.configuredSiteId) {
|
|
126
|
+
return reject("forbidden");
|
|
127
|
+
}
|
|
128
|
+
if ((request.message.authorSub && request.message.authorSub !== membership.editorSub)
|
|
129
|
+
|| (request.message.accountId && request.message.accountId !== membership.accountId)
|
|
130
|
+
|| (request.message.siteId && request.message.siteId !== membership.siteId)) {
|
|
131
|
+
return reject("forbidden");
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const expectedOwner: TranscriptOwner = {
|
|
135
|
+
accountId: membership.accountId,
|
|
136
|
+
siteId: membership.siteId,
|
|
137
|
+
editorSub: membership.editorSub,
|
|
138
|
+
channelId: request.channelId,
|
|
139
|
+
};
|
|
140
|
+
const actualOwner = await dependencies.resolveTranscriptOwner(request.channelId);
|
|
141
|
+
if (!actualOwner || actualOwner.accountId !== expectedOwner.accountId || actualOwner.siteId !== expectedOwner.siteId
|
|
142
|
+
|| actualOwner.editorSub !== expectedOwner.editorSub || actualOwner.channelId !== expectedOwner.channelId) {
|
|
143
|
+
return reject("forbidden");
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
owner: expectedOwner,
|
|
148
|
+
idempotencyKey: request.idempotencyKey,
|
|
149
|
+
payloadFingerprint: JSON.stringify([request.channelId, request.message.text]),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export interface IdempotencyRequest<T> {
|
|
154
|
+
/** Storage must atomically scope key by the derived owner and operation. */
|
|
155
|
+
scope: string;
|
|
156
|
+
key: string;
|
|
157
|
+
payloadFingerprint: string;
|
|
158
|
+
run: () => Promise<T>;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Store contract for replay-safe writes. Production implementations must be
|
|
163
|
+
* atomic/durable (for example conditional put + canonical result); this module
|
|
164
|
+
* deliberately supplies no in-memory production store.
|
|
165
|
+
*/
|
|
166
|
+
export interface ChatIdempotencyStore {
|
|
167
|
+
executeOnce<T>(request: IdempotencyRequest<T>): Promise<T>;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function runAdmittedChatMessage<T>(
|
|
171
|
+
admission: AdmittedChatMessage,
|
|
172
|
+
store: ChatIdempotencyStore,
|
|
173
|
+
operation: () => Promise<T>,
|
|
174
|
+
): Promise<T> {
|
|
175
|
+
const { accountId, siteId, editorSub, channelId } = admission.owner;
|
|
176
|
+
return store.executeOnce({
|
|
177
|
+
scope: JSON.stringify(["chat-message", accountId, siteId, editorSub, channelId]),
|
|
178
|
+
key: admission.idempotencyKey,
|
|
179
|
+
payloadFingerprint: admission.payloadFingerprint,
|
|
180
|
+
run: operation,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { NextRequest } from "next/server";
|
|
2
|
+
import { getSiteEnv } from "./site-env";
|
|
3
|
+
|
|
4
|
+
type EnvironmentVariables = Record<string, string | undefined>;
|
|
5
|
+
|
|
6
|
+
export const SITE_ORIGIN_ENV = "PAPYRUS_SITE_ORIGIN";
|
|
7
|
+
|
|
8
|
+
export class SiteOriginNotConfiguredError extends Error {
|
|
9
|
+
readonly status = 503;
|
|
10
|
+
readonly code = "site_origin_not_configured";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function isLoopbackHostname(hostname: string): boolean {
|
|
14
|
+
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function configuredOrigin(value: string): string {
|
|
18
|
+
const invalid = () => new SiteOriginNotConfiguredError(`${SITE_ORIGIN_ENV} must be an https origin such as https://example.com with no path.`);
|
|
19
|
+
let parsed: URL;
|
|
20
|
+
try {
|
|
21
|
+
parsed = new URL(value);
|
|
22
|
+
} catch {
|
|
23
|
+
throw invalid();
|
|
24
|
+
}
|
|
25
|
+
if (parsed.protocol !== "https:" || parsed.origin !== value) throw invalid();
|
|
26
|
+
return parsed.origin;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function siteEnvOrNull(environment: EnvironmentVariables): string | null {
|
|
30
|
+
try {
|
|
31
|
+
return getSiteEnv(environment);
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** The site's public origin from trusted configuration, never Host or forwarded headers. */
|
|
38
|
+
export function publicSiteOrigin(request: Pick<NextRequest, "nextUrl">, environment: EnvironmentVariables = process.env): string {
|
|
39
|
+
const configured = (environment[SITE_ORIGIN_ENV] ?? "").trim();
|
|
40
|
+
if (configured) return configuredOrigin(configured);
|
|
41
|
+
const { hostname, origin } = request.nextUrl;
|
|
42
|
+
const developing = siteEnvOrNull(environment) === "development" && environment.NODE_ENV !== "production";
|
|
43
|
+
if (isLoopbackHostname(hostname) && developing) return origin;
|
|
44
|
+
throw new SiteOriginNotConfiguredError(`${SITE_ORIGIN_ENV} is not set; this site cannot tell its public origin.`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** An absolute URL on the site's trusted public origin. */
|
|
48
|
+
export function publicSiteUrl(path: string, request: Pick<NextRequest, "nextUrl">, environment: EnvironmentVariables = process.env): URL {
|
|
49
|
+
return new URL(path, publicSiteOrigin(request, environment));
|
|
50
|
+
}
|
package/lib/site-origin.ts
CHANGED
|
@@ -1,67 +1,8 @@
|
|
|
1
|
-
import { NextResponse
|
|
2
|
-
import {
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { SiteOriginNotConfiguredError } from "./site-origin-value";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export const SITE_ORIGIN_ENV = "PAPYRUS_SITE_ORIGIN";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* The site's public origin cannot be read from the request on Amplify SSR (WEB_COMPUTE):
|
|
10
|
-
* there `request.nextUrl.origin` is the compute adapter's internal https://localhost:3000.
|
|
11
|
-
* It also must never be derived from Host or X-Forwarded-* headers, which a client can set.
|
|
12
|
-
* The one trusted source is PAPYRUS_SITE_ORIGIN, set by the app shell from the site's host.
|
|
13
|
-
*/
|
|
14
|
-
export class SiteOriginNotConfiguredError extends Error {
|
|
15
|
-
readonly status = 503;
|
|
16
|
-
readonly code = "site_origin_not_configured";
|
|
17
|
-
}
|
|
4
|
+
export { SITE_ORIGIN_ENV, SiteOriginNotConfiguredError, publicSiteOrigin, publicSiteUrl } from "./site-origin-value";
|
|
18
5
|
|
|
19
6
|
export function siteOriginNotConfiguredResponse(error: SiteOriginNotConfiguredError): NextResponse {
|
|
20
7
|
return NextResponse.json({ error: error.code, message: error.message }, { status: error.status, headers: { "cache-control": "no-store" } });
|
|
21
8
|
}
|
|
22
|
-
|
|
23
|
-
function isLoopbackHostname(hostname: string): boolean {
|
|
24
|
-
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function configuredOrigin(value: string): string {
|
|
28
|
-
const invalid = () => new SiteOriginNotConfiguredError(`${SITE_ORIGIN_ENV} must be an https origin such as https://example.com with no path.`);
|
|
29
|
-
let parsed: URL;
|
|
30
|
-
try {
|
|
31
|
-
parsed = new URL(value);
|
|
32
|
-
} catch {
|
|
33
|
-
throw invalid();
|
|
34
|
-
}
|
|
35
|
-
if (parsed.protocol !== "https:" || parsed.origin !== value) throw invalid();
|
|
36
|
-
return parsed.origin;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function siteEnvOrNull(environment: EnvironmentVariables): string | null {
|
|
40
|
-
try {
|
|
41
|
-
return getSiteEnv(environment);
|
|
42
|
-
} catch {
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* The site's public origin, from trusted configuration.
|
|
49
|
-
* - PAPYRUS_SITE_ORIGIN set: it must be an https origin with no path; it is used as is.
|
|
50
|
-
* - Unset: `request.nextUrl.origin` only when it is loopback, SITE_ENV resolves to development
|
|
51
|
-
* and NODE_ENV is not production (a local `next dev` server). Anything else, production and staging included, throws
|
|
52
|
-
* SiteOriginNotConfiguredError so routes answer 503 instead of redirecting to localhost.
|
|
53
|
-
*/
|
|
54
|
-
export function publicSiteOrigin(request: Pick<NextRequest, "nextUrl">, environment: EnvironmentVariables = process.env): string {
|
|
55
|
-
const configured = (environment[SITE_ORIGIN_ENV] ?? "").trim();
|
|
56
|
-
if (configured) return configuredOrigin(configured);
|
|
57
|
-
const { hostname, origin } = request.nextUrl;
|
|
58
|
-
// SITE_ENV defaults to development when a runtime never received it, so NODE_ENV=production also closes the fallback.
|
|
59
|
-
const developing = siteEnvOrNull(environment) === "development" && environment.NODE_ENV !== "production";
|
|
60
|
-
if (isLoopbackHostname(hostname) && developing) return origin;
|
|
61
|
-
throw new SiteOriginNotConfiguredError(`${SITE_ORIGIN_ENV} is not set; this site cannot tell its public origin.`);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/** An absolute URL on the site's public origin, for redirects. Fails closed like publicSiteOrigin. */
|
|
65
|
-
export function publicSiteUrl(path: string, request: Pick<NextRequest, "nextUrl">, environment: EnvironmentVariables = process.env): URL {
|
|
66
|
-
return new URL(path, publicSiteOrigin(request, environment));
|
|
67
|
-
}
|
package/package.json
CHANGED
|
@@ -117,7 +117,9 @@
|
|
|
117
117
|
"./components/newsroom-theme": "./components/newsroom-theme.tsx",
|
|
118
118
|
"./components/newsroom-topics-view": "./components/newsroom-topics-view.tsx",
|
|
119
119
|
"./components/notification-center": "./components/notification-center.tsx",
|
|
120
|
+
"./components/papyrus-console-conversation": "./components/papyrus-console-conversation.tsx",
|
|
120
121
|
"./components/papyrus-console-shell": "./components/papyrus-console-shell.tsx",
|
|
122
|
+
"./components/papyrus-private-chat-panel": "./components/papyrus-private-chat-panel.tsx",
|
|
121
123
|
"./components/pictogram-figure": "./components/pictogram-figure.tsx",
|
|
122
124
|
"./components/presentation-footer": "./components/presentation-footer.tsx",
|
|
123
125
|
"./components/presentation-header": "./components/presentation-header.tsx",
|
|
@@ -271,7 +273,10 @@
|
|
|
271
273
|
"./lib/newsroom-sections": "./lib/newsroom-sections.ts",
|
|
272
274
|
"./lib/newsroom-topics": "./lib/newsroom-topics.ts",
|
|
273
275
|
"./lib/oauth-redirect-priority": "./lib/oauth-redirect-priority.ts",
|
|
276
|
+
"./lib/papyrus-chat-admission": "./lib/papyrus-chat-admission.ts",
|
|
277
|
+
"./lib/papyrus-hosted-chat": "./lib/papyrus-hosted-chat.ts",
|
|
274
278
|
"./lib/papyrus-object-kinds": "./lib/papyrus-object-kinds.ts",
|
|
279
|
+
"./lib/papyrus-private-chat-client": "./lib/papyrus-private-chat-client.ts",
|
|
275
280
|
"./lib/papyrus-web-locations": "./lib/papyrus-web-locations.ts",
|
|
276
281
|
"./lib/pilobol-sample": "./lib/pilobol-sample.ts",
|
|
277
282
|
"./lib/plugin-settings": "./lib/plugin-settings.ts",
|
|
@@ -315,11 +320,13 @@
|
|
|
315
320
|
"./lib/robots-policy": "./lib/robots-policy.ts",
|
|
316
321
|
"./lib/root-route-redirect": "./lib/root-route-redirect.ts",
|
|
317
322
|
"./lib/semantic-graph": "./lib/semantic-graph.ts",
|
|
323
|
+
"./lib/shared-chat-admission": "./lib/shared-chat-admission.ts",
|
|
318
324
|
"./lib/shared-credentials-provider": "./lib/shared-credentials-provider.ts",
|
|
319
325
|
"./lib/signup-csv": "./lib/signup-csv.ts",
|
|
320
326
|
"./lib/site-brand-tenant": "./lib/site-brand-tenant.ts",
|
|
321
327
|
"./lib/site-brand": "./lib/site-brand.ts",
|
|
322
328
|
"./lib/site-env": "./lib/site-env.ts",
|
|
329
|
+
"./lib/site-origin-value": "./lib/site-origin-value.ts",
|
|
323
330
|
"./lib/site-origin": "./lib/site-origin.ts",
|
|
324
331
|
"./lib/site-renderer": "./lib/site-renderer.ts",
|
|
325
332
|
"./lib/site-section-suggestions": "./lib/site-section-suggestions.ts",
|
|
@@ -369,6 +376,7 @@
|
|
|
369
376
|
"./app/api/newsletter/state/route": "./app/api/newsletter/state/route.ts",
|
|
370
377
|
"./app/api/newsletter/subscribe/route": "./app/api/newsletter/subscribe/route.ts",
|
|
371
378
|
"./app/api/newsletter/unsubscribe/route": "./app/api/newsletter/unsubscribe/route.ts",
|
|
379
|
+
"./app/api/newsroom/chat/[...path]/route": "./app/api/newsroom/chat/[...path]/route.ts",
|
|
372
380
|
"./app/api/newsroom/curation/context/route": "./app/api/newsroom/curation/context/route.ts",
|
|
373
381
|
"./app/api/newsroom/curation/priming/route": "./app/api/newsroom/curation/priming/route.ts",
|
|
374
382
|
"./app/api/newsroom/curation/publication/route": "./app/api/newsroom/curation/publication/route.ts",
|
|
@@ -448,7 +456,7 @@
|
|
|
448
456
|
"optional": true
|
|
449
457
|
}
|
|
450
458
|
},
|
|
451
|
-
"version": "2.0.0-next.
|
|
459
|
+
"version": "2.0.0-next.92",
|
|
452
460
|
"dependencies": {
|
|
453
461
|
"@aws-amplify/adapter-nextjs": "^1.7.3",
|
|
454
462
|
"@aws-crypto/sha256-js": "5.2.0",
|
|
@@ -485,6 +493,7 @@
|
|
|
485
493
|
"anthus-vultus": "github:AnthusAI/Vultus#af98d57",
|
|
486
494
|
"aws-amplify": "^6.17.0",
|
|
487
495
|
"aws-jwt-verify": "4.0.1",
|
|
496
|
+
"chatticus": "https://github.com/AnthusAI/Chatticus/archive/db862e386119f97922cf303fd00ef0505d86a08a.tar.gz",
|
|
488
497
|
"class-variance-authority": "^0.7.1",
|
|
489
498
|
"clsx": "^2.1.1",
|
|
490
499
|
"cmdk": "^1.1.1",
|
package/routes.manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.0.0-next.
|
|
2
|
+
"version": "2.0.0-next.92",
|
|
3
3
|
"routes": [
|
|
4
4
|
{
|
|
5
5
|
"file": "app/%5F_preview/[[...path]]/route.ts",
|
|
@@ -229,6 +229,18 @@
|
|
|
229
229
|
"runtime": "\"nodejs\""
|
|
230
230
|
}
|
|
231
231
|
},
|
|
232
|
+
{
|
|
233
|
+
"file": "app/api/newsroom/chat/[...path]/route.ts",
|
|
234
|
+
"hasDefault": false,
|
|
235
|
+
"exports": [
|
|
236
|
+
"GET",
|
|
237
|
+
"POST"
|
|
238
|
+
],
|
|
239
|
+
"config": {
|
|
240
|
+
"dynamic": "\"force-dynamic\"",
|
|
241
|
+
"runtime": "\"nodejs\""
|
|
242
|
+
}
|
|
243
|
+
},
|
|
232
244
|
{
|
|
233
245
|
"file": "app/api/newsroom/curation/context/route.ts",
|
|
234
246
|
"hasDefault": false,
|
package/src/with-papyrus.mjs
CHANGED
|
@@ -50,7 +50,7 @@ export function staticGenerationSettings() {
|
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export const DEFAULT_TRANSPILE_PACKAGES = ["@anthusai/papyrus", "cyclotron"];
|
|
53
|
+
export const DEFAULT_TRANSPILE_PACKAGES = ["@anthusai/papyrus", "cyclotron", "chatticus"];
|
|
54
54
|
|
|
55
55
|
export function mergeTranspilePackages(existing = []) {
|
|
56
56
|
return [...new Set([...existing, ...DEFAULT_TRANSPILE_PACKAGES])];
|