@agent-native/core 0.125.0 → 0.126.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +8 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/server/email-template.ts +13 -0
- package/corpus/core/src/server/email.ts +40 -4
- package/corpus/core/src/sharing/actions/share-resource.ts +55 -5
- package/corpus/core/src/sharing/registry.ts +41 -1
- package/corpus/templates/assets/actions/edit-image.ts +31 -18
- package/corpus/templates/assets/actions/refine-image.ts +43 -29
- package/corpus/templates/assets/actions/restyle-image.ts +30 -19
- package/corpus/templates/assets/actions/variant-slots.ts +26 -0
- package/corpus/templates/assets/app/components/generation/GenerationResults.tsx +85 -17
- package/corpus/templates/clips/changelog/2026-07-27-share-notification-emails-now-include-a-clickable-recording-.md +6 -0
- package/corpus/templates/clips/server/db/index.ts +28 -6
- package/corpus/templates/clips/server/lib/share-email-hero.ts +105 -0
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +100 -12
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +17 -0
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +169 -22
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/provider-api/actions/provider-api.d.ts +8 -8
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/email-template.d.ts +6 -0
- package/dist/server/email-template.d.ts.map +1 -1
- package/dist/server/email-template.js +6 -0
- package/dist/server/email-template.js.map +1 -1
- package/dist/server/email.d.ts +7 -0
- package/dist/server/email.d.ts.map +1 -1
- package/dist/server/email.js +31 -6
- package/dist/server/email.js.map +1 -1
- package/dist/sharing/actions/share-resource.d.ts.map +1 -1
- package/dist/sharing/actions/share-resource.js +49 -5
- package/dist/sharing/actions/share-resource.js.map +1 -1
- package/dist/sharing/registry.d.ts +40 -1
- package/dist/sharing/registry.d.ts.map +1 -1
- package/dist/sharing/registry.js.map +1 -1
- package/package.json +1 -1
- package/src/server/email-template.ts +13 -0
- package/src/server/email.ts +40 -4
- package/src/sharing/actions/share-resource.ts +55 -5
- package/src/sharing/registry.ts +41 -1
|
@@ -8,6 +8,7 @@ import { renderEmail, emailStrong } from "../../server/email-template.js";
|
|
|
8
8
|
import { sendEmail, isEmailConfigured } from "../../server/email.js";
|
|
9
9
|
import { invalidateCollabAccessCache } from "../../server/poll.js";
|
|
10
10
|
import { getRequestUserEmail } from "../../server/request-context.js";
|
|
11
|
+
import { getUserProfile } from "../../user-profile/store.js";
|
|
11
12
|
import { assertAccess, ForbiddenError } from "../access.js";
|
|
12
13
|
import { requireShareableResource } from "../registry.js";
|
|
13
14
|
import {
|
|
@@ -298,10 +299,9 @@ export default defineAction({
|
|
|
298
299
|
const appName =
|
|
299
300
|
process.env.APP_NAME || process.env.VITE_APP_NAME || "Agent Native";
|
|
300
301
|
let brandLogoUrl: string | undefined;
|
|
301
|
-
if (reg.
|
|
302
|
+
if (reg.getLogoUrl) {
|
|
302
303
|
try {
|
|
303
|
-
brandLogoUrl =
|
|
304
|
-
(await reg.getShareEmailLogoUrl(resource)) ?? undefined;
|
|
304
|
+
brandLogoUrl = (await reg.getLogoUrl(resource)) ?? undefined;
|
|
305
305
|
} catch (err) {
|
|
306
306
|
console.error(
|
|
307
307
|
"[share-resource] brand logo resolver failed; using default logo:",
|
|
@@ -309,9 +309,51 @@ export default defineAction({
|
|
|
309
309
|
);
|
|
310
310
|
}
|
|
311
311
|
}
|
|
312
|
+
let brandName = appName;
|
|
313
|
+
if (reg.getBrandName) {
|
|
314
|
+
try {
|
|
315
|
+
brandName = (await reg.getBrandName(resource))?.trim() || appName;
|
|
316
|
+
} catch (err) {
|
|
317
|
+
console.error(
|
|
318
|
+
"[share-resource] brand name resolver failed; using app name:",
|
|
319
|
+
err,
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
let fromName: string | undefined;
|
|
324
|
+
let replyTo: string | undefined;
|
|
325
|
+
if (reg.getSender) {
|
|
326
|
+
try {
|
|
327
|
+
const sender = await reg.getSender(resource, {
|
|
328
|
+
sender: await getUserProfile(actor),
|
|
329
|
+
});
|
|
330
|
+
fromName = sender?.fromName?.trim() || undefined;
|
|
331
|
+
replyTo = sender?.replyTo?.trim() || undefined;
|
|
332
|
+
} catch (err) {
|
|
333
|
+
console.error(
|
|
334
|
+
"[share-resource] sender resolver failed; using default sender:",
|
|
335
|
+
err,
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
let heroHtml: string | undefined;
|
|
340
|
+
if (reg.getHeroHtml) {
|
|
341
|
+
try {
|
|
342
|
+
heroHtml =
|
|
343
|
+
(await reg.getHeroHtml(resource, {
|
|
344
|
+
href: notificationUrl,
|
|
345
|
+
alt: resourceTitle,
|
|
346
|
+
})) ?? undefined;
|
|
347
|
+
} catch (err) {
|
|
348
|
+
console.error(
|
|
349
|
+
"[share-resource] hero html resolver failed; omitting preview:",
|
|
350
|
+
err,
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
312
354
|
const subject = `${actor} shared "${resourceTitle}" with you on ${appName}`;
|
|
313
355
|
const { html, text } = renderEmail({
|
|
314
|
-
brandName
|
|
356
|
+
brandName,
|
|
315
357
|
brandLogoUrl,
|
|
316
358
|
preheader: subject,
|
|
317
359
|
heading: "You've been given access",
|
|
@@ -319,10 +361,18 @@ export default defineAction({
|
|
|
319
361
|
`${emailStrong(actor)} has shared the ${reg.displayName} ${emailStrong(resourceTitle)} with you as a ${emailStrong(args.role)}.`,
|
|
320
362
|
`Use the button below to open it. If prompted, sign in with ${emailStrong(principalId)}.`,
|
|
321
363
|
],
|
|
364
|
+
heroHtml,
|
|
322
365
|
cta: { label: `Open ${reg.displayName}`, url: notificationUrl },
|
|
323
366
|
footer: `You received this because ${actor} granted you ${args.role} access.`,
|
|
324
367
|
});
|
|
325
|
-
await sendEmail({
|
|
368
|
+
await sendEmail({
|
|
369
|
+
to: principalId,
|
|
370
|
+
subject,
|
|
371
|
+
html,
|
|
372
|
+
text,
|
|
373
|
+
fromName,
|
|
374
|
+
replyTo,
|
|
375
|
+
});
|
|
326
376
|
} catch (err) {
|
|
327
377
|
console.error(
|
|
328
378
|
"[share-resource] failed to send share notification:",
|
package/src/sharing/registry.ts
CHANGED
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
* });
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
+
import type { UserProfile } from "../user-profile/shared.js";
|
|
21
|
+
|
|
20
22
|
export interface ShareableResourceRegistration {
|
|
21
23
|
/** Stable identifier used across actions, UI, and analytics. e.g. "document". */
|
|
22
24
|
type: string;
|
|
@@ -42,8 +44,46 @@ export interface ShareableResourceRegistration {
|
|
|
42
44
|
* (e.g. the sharing org's own logo), or undefined to fall back. Receives the
|
|
43
45
|
* resource row being shared so the template can scope the logo to its org.
|
|
44
46
|
*/
|
|
45
|
-
|
|
47
|
+
getLogoUrl?: (
|
|
48
|
+
resource: any,
|
|
49
|
+
) => string | undefined | Promise<string | undefined>;
|
|
50
|
+
/**
|
|
51
|
+
* Optional resolver for the brand name shown beside the logo in the
|
|
52
|
+
* share-notification email header. Return a display name (e.g. the sharing
|
|
53
|
+
* org's name) to override the app name, or undefined to keep the default.
|
|
54
|
+
* Receives the resource row being shared.
|
|
55
|
+
*/
|
|
56
|
+
getBrandName?: (
|
|
57
|
+
resource: any,
|
|
58
|
+
) => string | undefined | Promise<string | undefined>;
|
|
59
|
+
/**
|
|
60
|
+
* Optional resolver for who the share-notification email appears to come
|
|
61
|
+
* from. `fromName` changes only the display name and keeps the configured,
|
|
62
|
+
* domain-verified sending address (e.g. "Alice via Clips"); `replyTo` routes
|
|
63
|
+
* replies to the sharer. `ctx.sender` is the account doing the sharing, so the
|
|
64
|
+
* template decides how to present them (name, email, avatar).
|
|
65
|
+
*
|
|
66
|
+
* Do not put a user's address in the sending address itself — SPF/DKIM sign
|
|
67
|
+
* the app's domain, so recipients would bounce or spam-filter it.
|
|
68
|
+
*/
|
|
69
|
+
getSender?: (
|
|
70
|
+
resource: any,
|
|
71
|
+
ctx: { sender: UserProfile },
|
|
72
|
+
) =>
|
|
73
|
+
| { fromName?: string; replyTo?: string }
|
|
74
|
+
| undefined
|
|
75
|
+
| Promise<{ fromName?: string; replyTo?: string } | undefined>;
|
|
76
|
+
/**
|
|
77
|
+
* Optional resolver for a preview block shown above the CTA in the
|
|
78
|
+
* share-notification email — e.g. a recording thumbnail with a play badge.
|
|
79
|
+
* Return trusted HTML (built by template code, dynamic values escaped) that
|
|
80
|
+
* is injected verbatim, or undefined to omit it. `ctx.href` is the resolved
|
|
81
|
+
* link to the resource; `ctx.alt` is its title. The template owns the entire
|
|
82
|
+
* preview markup so the generic share action stays app-agnostic.
|
|
83
|
+
*/
|
|
84
|
+
getHeroHtml?: (
|
|
46
85
|
resource: any,
|
|
86
|
+
ctx: { href: string; alt?: string },
|
|
47
87
|
) => string | undefined | Promise<string | undefined>;
|
|
48
88
|
/**
|
|
49
89
|
* Drizzle DB accessor from the template's server/db/index.ts. Required —
|