@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.
Files changed (42) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +8 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/server/email-template.ts +13 -0
  5. package/corpus/core/src/server/email.ts +40 -4
  6. package/corpus/core/src/sharing/actions/share-resource.ts +55 -5
  7. package/corpus/core/src/sharing/registry.ts +41 -1
  8. package/corpus/templates/assets/actions/edit-image.ts +31 -18
  9. package/corpus/templates/assets/actions/refine-image.ts +43 -29
  10. package/corpus/templates/assets/actions/restyle-image.ts +30 -19
  11. package/corpus/templates/assets/actions/variant-slots.ts +26 -0
  12. package/corpus/templates/assets/app/components/generation/GenerationResults.tsx +85 -17
  13. package/corpus/templates/clips/changelog/2026-07-27-share-notification-emails-now-include-a-clickable-recording-.md +6 -0
  14. package/corpus/templates/clips/server/db/index.ts +28 -6
  15. package/corpus/templates/clips/server/lib/share-email-hero.ts +105 -0
  16. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +100 -12
  17. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +17 -0
  18. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +169 -22
  19. package/dist/collab/routes.d.ts +1 -1
  20. package/dist/collab/struct-routes.d.ts +1 -1
  21. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  22. package/dist/provider-api/actions/provider-api.d.ts +8 -8
  23. package/dist/secrets/routes.d.ts +9 -9
  24. package/dist/server/email-template.d.ts +6 -0
  25. package/dist/server/email-template.d.ts.map +1 -1
  26. package/dist/server/email-template.js +6 -0
  27. package/dist/server/email-template.js.map +1 -1
  28. package/dist/server/email.d.ts +7 -0
  29. package/dist/server/email.d.ts.map +1 -1
  30. package/dist/server/email.js +31 -6
  31. package/dist/server/email.js.map +1 -1
  32. package/dist/sharing/actions/share-resource.d.ts.map +1 -1
  33. package/dist/sharing/actions/share-resource.js +49 -5
  34. package/dist/sharing/actions/share-resource.js.map +1 -1
  35. package/dist/sharing/registry.d.ts +40 -1
  36. package/dist/sharing/registry.d.ts.map +1 -1
  37. package/dist/sharing/registry.js.map +1 -1
  38. package/package.json +1 -1
  39. package/src/server/email-template.ts +13 -0
  40. package/src/server/email.ts +40 -4
  41. package/src/sharing/actions/share-resource.ts +55 -5
  42. 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.getShareEmailLogoUrl) {
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: appName,
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({ to: principalId, subject, html, text });
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:",
@@ -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
- getShareEmailLogoUrl?: (
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 —