@agent-native/core 0.124.6 → 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 +14 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/server/email-template.ts +37 -1
- package/corpus/core/src/server/email.ts +40 -4
- package/corpus/core/src/sharing/actions/share-resource.ts +65 -2
- package/corpus/core/src/sharing/registry.ts +49 -0
- 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-organization-brand-logos-now-upload-to-configured-file-stora.md +6 -0
- 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 +45 -0
- package/corpus/templates/clips/server/lib/share-email-hero.ts +105 -0
- package/corpus/templates/clips/server/routes/api/media/index.post.ts +19 -31
- 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 +2 -2
- package/dist/observability/routes.d.ts +3 -3
- package/dist/provider-api/actions/provider-api.d.ts +8 -8
- package/dist/server/email-template.d.ts +12 -0
- package/dist/server/email-template.d.ts.map +1 -1
- package/dist/server/email-template.js +24 -1
- 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/server/transcribe-voice.d.ts +1 -1
- package/dist/sharing/actions/share-resource.d.ts.map +1 -1
- package/dist/sharing/actions/share-resource.js +57 -2
- package/dist/sharing/actions/share-resource.js.map +1 -1
- package/dist/sharing/registry.d.ts +46 -0
- 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 +37 -1
- package/src/server/email.ts +40 -4
- package/src/sharing/actions/share-resource.ts +65 -2
- package/src/sharing/registry.ts +49 -0
|
@@ -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 {
|
|
@@ -297,19 +298,81 @@ export default defineAction({
|
|
|
297
298
|
);
|
|
298
299
|
const appName =
|
|
299
300
|
process.env.APP_NAME || process.env.VITE_APP_NAME || "Agent Native";
|
|
301
|
+
let brandLogoUrl: string | undefined;
|
|
302
|
+
if (reg.getLogoUrl) {
|
|
303
|
+
try {
|
|
304
|
+
brandLogoUrl = (await reg.getLogoUrl(resource)) ?? undefined;
|
|
305
|
+
} catch (err) {
|
|
306
|
+
console.error(
|
|
307
|
+
"[share-resource] brand logo resolver failed; using default logo:",
|
|
308
|
+
err,
|
|
309
|
+
);
|
|
310
|
+
}
|
|
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
|
+
}
|
|
300
354
|
const subject = `${actor} shared "${resourceTitle}" with you on ${appName}`;
|
|
301
355
|
const { html, text } = renderEmail({
|
|
302
|
-
brandName
|
|
356
|
+
brandName,
|
|
357
|
+
brandLogoUrl,
|
|
303
358
|
preheader: subject,
|
|
304
359
|
heading: "You've been given access",
|
|
305
360
|
paragraphs: [
|
|
306
361
|
`${emailStrong(actor)} has shared the ${reg.displayName} ${emailStrong(resourceTitle)} with you as a ${emailStrong(args.role)}.`,
|
|
307
362
|
`Use the button below to open it. If prompted, sign in with ${emailStrong(principalId)}.`,
|
|
308
363
|
],
|
|
364
|
+
heroHtml,
|
|
309
365
|
cta: { label: `Open ${reg.displayName}`, url: notificationUrl },
|
|
310
366
|
footer: `You received this because ${actor} granted you ${args.role} access.`,
|
|
311
367
|
});
|
|
312
|
-
await sendEmail({
|
|
368
|
+
await sendEmail({
|
|
369
|
+
to: principalId,
|
|
370
|
+
subject,
|
|
371
|
+
html,
|
|
372
|
+
text,
|
|
373
|
+
fromName,
|
|
374
|
+
replyTo,
|
|
375
|
+
});
|
|
313
376
|
} catch (err) {
|
|
314
377
|
console.error(
|
|
315
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;
|
|
@@ -36,6 +38,53 @@ export interface ShareableResourceRegistration {
|
|
|
36
38
|
* when the caller does not pass a more specific resourceUrl.
|
|
37
39
|
*/
|
|
38
40
|
getResourcePath?: (resource: any) => string | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Optional resolver for the share-notification email's brand logo. Return an
|
|
43
|
+
* absolute `https://` URL to override the default embedded Agent Native logo
|
|
44
|
+
* (e.g. the sharing org's own logo), or undefined to fall back. Receives the
|
|
45
|
+
* resource row being shared so the template can scope the logo to its org.
|
|
46
|
+
*/
|
|
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?: (
|
|
85
|
+
resource: any,
|
|
86
|
+
ctx: { href: string; alt?: string },
|
|
87
|
+
) => string | undefined | Promise<string | undefined>;
|
|
39
88
|
/**
|
|
40
89
|
* Drizzle DB accessor from the template's server/db/index.ts. Required —
|
|
41
90
|
* the framework-level share actions and access helpers call this to reach
|