@tangle-network/agent-app 0.42.6 → 0.42.8
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/{InvitationsPanel-ZKAUYZYU.js → InvitationsPanel-XUUWZBPV.js} +2 -2
- package/dist/{chunk-F7D7YCUL.js → chunk-7C64WKAH.js} +16 -10
- package/dist/chunk-7C64WKAH.js.map +1 -0
- package/dist/teams/index.js +5 -5
- package/dist/teams/invitations-api.js +1 -1
- package/dist/teams/resend.d.ts +36 -0
- package/dist/teams/resend.js +38 -0
- package/dist/teams/resend.js.map +1 -0
- package/dist/teams-react/index.js +1 -1
- package/dist/teams-react/lazy.js +1 -1
- package/package.json +12 -2
- package/dist/chunk-F7D7YCUL.js.map +0 -1
- /package/dist/{InvitationsPanel-ZKAUYZYU.js.map → InvitationsPanel-XUUWZBPV.js.map} +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
InvitationsPanel
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-7C64WKAH.js";
|
|
4
4
|
import "./chunk-63CE7FEZ.js";
|
|
5
5
|
export {
|
|
6
6
|
InvitationsPanel
|
|
7
7
|
};
|
|
8
|
-
//# sourceMappingURL=InvitationsPanel-
|
|
8
|
+
//# sourceMappingURL=InvitationsPanel-XUUWZBPV.js.map
|
|
@@ -10,6 +10,18 @@ var ASSIGNABLE = [
|
|
|
10
10
|
{ value: "editor", label: "Editor" },
|
|
11
11
|
{ value: "admin", label: "Admin" }
|
|
12
12
|
];
|
|
13
|
+
var BADGE_BASE = "inline-flex items-center rounded border px-2 py-0.5 text-[10px] font-medium uppercase";
|
|
14
|
+
var STATUS_BADGE = {
|
|
15
|
+
accepted: "border-[var(--surface-success-border)] bg-[var(--surface-success-bg)] text-[var(--surface-success-text)]",
|
|
16
|
+
pending: "border-[var(--surface-warning-border)] bg-[var(--surface-warning-bg)] text-[var(--surface-warning-text)]",
|
|
17
|
+
revoked: "border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] text-[var(--surface-danger-text)]",
|
|
18
|
+
expired: "border-[var(--border-default)] text-[var(--text-muted)]"
|
|
19
|
+
};
|
|
20
|
+
var EMAIL_BADGE = {
|
|
21
|
+
sent: "border-[var(--border-default)] text-[var(--text-muted)]",
|
|
22
|
+
not_sent: "border-[var(--surface-warning-border)] bg-[var(--surface-warning-bg)] text-[var(--surface-warning-text)]",
|
|
23
|
+
failed: "border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] text-[var(--surface-danger-text)]"
|
|
24
|
+
};
|
|
13
25
|
function InvitationsPanel({
|
|
14
26
|
invitations,
|
|
15
27
|
currentRole,
|
|
@@ -152,17 +164,11 @@ function InvitationRow({ invitation, canManage, busy, onCopy, onResend, onRevoke
|
|
|
152
164
|
" \xB7 expires ",
|
|
153
165
|
expiry
|
|
154
166
|
] }),
|
|
155
|
-
emailFailed && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-[var(--
|
|
167
|
+
emailFailed && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-[var(--surface-danger-text)]", children: "Email was not sent \u2014 copy the link to share it." })
|
|
156
168
|
] }),
|
|
157
169
|
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
158
|
-
/* @__PURE__ */ jsx("span", { className:
|
|
159
|
-
/* @__PURE__ */ jsx(
|
|
160
|
-
"span",
|
|
161
|
-
{
|
|
162
|
-
className: `rounded border border-[var(--border-default)] px-2 py-0.5 text-[10px] uppercase ${emailFailed ? "text-[var(--text-danger)]" : "text-[var(--text-muted)]"}`,
|
|
163
|
-
children: invitation.emailStatus.replace("_", " ")
|
|
164
|
-
}
|
|
165
|
-
)
|
|
170
|
+
/* @__PURE__ */ jsx("span", { className: `${BADGE_BASE} ${STATUS_BADGE[invitation.status]}`, children: invitation.status }),
|
|
171
|
+
/* @__PURE__ */ jsx("span", { className: `${BADGE_BASE} ${EMAIL_BADGE[invitation.emailStatus]}`, children: invitation.emailStatus.replace("_", " ") })
|
|
166
172
|
] })
|
|
167
173
|
] }),
|
|
168
174
|
canManage && isPending && /* @__PURE__ */ jsxs("div", { className: "mt-3 flex items-center justify-end gap-2", children: [
|
|
@@ -203,4 +209,4 @@ function InvitationRow({ invitation, canManage, busy, onCopy, onResend, onRevoke
|
|
|
203
209
|
export {
|
|
204
210
|
InvitationsPanel
|
|
205
211
|
};
|
|
206
|
-
//# sourceMappingURL=chunk-
|
|
212
|
+
//# sourceMappingURL=chunk-7C64WKAH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/teams-react/components/InvitationsPanel.tsx"],"sourcesContent":["/**\n * Email-invitation panel: invite by email + role, and a history of every\n * invitation (pending / accepted / expired / revoked) with its email-delivery\n * status. Pending rows expose copy-link / resend / revoke. Fully callback-driven\n * — the host supplies the data and the async `onInvite` / `onResend` / `onRevoke`\n * callbacks (backed by `./teams/invitations-api`), so this imports no app router,\n * fetch client, or toast. Styled with the shipped Tangle Quiet tokens (`var(--*)`).\n *\n * Mount alongside a list-only `MembersPanel` (`showInviteForm={false}`): the\n * members panel shows accepted members, this owns the invite flow + pending list.\n */\n\nimport { useState } from 'react'\nimport type { WorkspaceRole } from '../../teams/roles'\nimport { hasWorkspaceRole } from '../../teams/roles'\nimport type { InvitationView, InvitationsPanelProps } from '../contracts'\n\nconst ASSIGNABLE: { value: WorkspaceRole; label: string }[] = [\n { value: 'viewer', label: 'Viewer' },\n { value: 'editor', label: 'Editor' },\n { value: 'admin', label: 'Admin' },\n]\n\nconst BADGE_BASE = 'inline-flex items-center rounded border px-2 py-0.5 text-[10px] font-medium uppercase'\n\n// Lifecycle status: green = in, amber = awaiting, red = killed, muted = lapsed.\nconst STATUS_BADGE: Record<InvitationView['status'], string> = {\n accepted: 'border-[var(--surface-success-border)] bg-[var(--surface-success-bg)] text-[var(--surface-success-text)]',\n pending: 'border-[var(--surface-warning-border)] bg-[var(--surface-warning-bg)] text-[var(--surface-warning-text)]',\n revoked: 'border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] text-[var(--surface-danger-text)]',\n expired: 'border-[var(--border-default)] text-[var(--text-muted)]',\n}\n\n// Delivery status: red = bounced, amber = not yet attempted, muted = the normal happy path.\nconst EMAIL_BADGE: Record<InvitationView['emailStatus'], string> = {\n sent: 'border-[var(--border-default)] text-[var(--text-muted)]',\n not_sent: 'border-[var(--surface-warning-border)] bg-[var(--surface-warning-bg)] text-[var(--surface-warning-text)]',\n failed: 'border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] text-[var(--surface-danger-text)]',\n}\n\nexport function InvitationsPanel({\n invitations,\n currentRole,\n onInvite,\n onResend,\n onRevoke,\n onCopy,\n onNotice,\n}: InvitationsPanelProps) {\n const [inviteEmail, setInviteEmail] = useState('')\n const [inviteRole, setInviteRole] = useState<WorkspaceRole>('editor')\n const [inviting, setInviting] = useState(false)\n const [busyId, setBusyId] = useState<string | null>(null)\n\n const canManage = hasWorkspaceRole(currentRole, 'admin')\n\n function notify(kind: 'success' | 'error', message: string) {\n onNotice?.({ kind, message })\n }\n\n async function submitInvite() {\n const email = inviteEmail.trim()\n if (!email || inviting) return\n setInviting(true)\n try {\n await onInvite({ email, role: inviteRole })\n notify('success', `Invitation sent to ${email}`)\n setInviteEmail('')\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to invite')\n } finally {\n setInviting(false)\n }\n }\n\n async function copyLink(inviteUrl: string) {\n try {\n if (onCopy) await onCopy({ inviteUrl })\n else await navigator.clipboard.writeText(inviteUrl)\n notify('success', 'Invite link copied')\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to copy link')\n }\n }\n\n async function resend(invitationId: string) {\n setBusyId(invitationId)\n try {\n await onResend({ invitationId })\n notify('success', 'Invitation resent')\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to resend invitation')\n } finally {\n setBusyId(null)\n }\n }\n\n async function revoke(invitationId: string) {\n setBusyId(invitationId)\n try {\n await onRevoke({ invitationId })\n notify('success', 'Invitation revoked')\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to revoke invitation')\n } finally {\n setBusyId(null)\n }\n }\n\n return (\n <section className=\"flex flex-col gap-4\">\n {canManage && (\n <div className=\"flex flex-col gap-1.5\">\n <label className=\"text-xs font-medium text-[var(--text-muted)]\">Invite by email</label>\n <div className=\"flex gap-2\">\n <input\n type=\"email\"\n placeholder=\"colleague@example.com\"\n value={inviteEmail}\n aria-label=\"Invite email address\"\n onChange={(event) => setInviteEmail(event.target.value)}\n onKeyDown={(event) => { if (event.key === 'Enter') void submitInvite() }}\n className=\"flex-1 rounded border border-[var(--border-default)] bg-[var(--bg-input)] px-3 py-1.5 text-sm text-[var(--text-primary)] placeholder:text-[var(--text-muted)]\"\n />\n <select\n value={inviteRole}\n aria-label=\"Invite role\"\n onChange={(event) => setInviteRole(event.target.value as WorkspaceRole)}\n className=\"rounded border border-[var(--border-default)] bg-[var(--bg-input)] px-2 py-1.5 text-xs text-[var(--text-secondary)]\"\n >\n {ASSIGNABLE.map((option) => (\n <option key={option.value} value={option.value}>{option.label}</option>\n ))}\n </select>\n <button\n type=\"button\"\n onClick={() => void submitInvite()}\n disabled={inviting || !inviteEmail.trim()}\n className=\"rounded bg-[var(--brand-primary)] px-3 py-1.5 text-sm text-white disabled:opacity-50\"\n >\n {inviting ? 'Inviting…' : 'Invite'}\n </button>\n </div>\n </div>\n )}\n\n <div className=\"flex flex-col gap-2 border-t border-[var(--border-default)] pt-3\">\n <div className=\"flex items-center justify-between\">\n <h4 className=\"text-xs font-semibold text-[var(--text-primary)]\">Invitation history</h4>\n <span className=\"text-xs text-[var(--text-muted)]\">{invitations.length} total</span>\n </div>\n {invitations.length === 0 ? (\n <p className=\"text-sm text-[var(--text-muted)]\">No invitations yet.</p>\n ) : (\n invitations.map((invitation) => (\n <InvitationRow\n key={invitation.id}\n invitation={invitation}\n canManage={canManage}\n busy={busyId === invitation.id}\n onCopy={() => void copyLink(invitation.inviteUrl)}\n onResend={() => void resend(invitation.id)}\n onRevoke={() => void revoke(invitation.id)}\n />\n ))\n )}\n </div>\n </section>\n )\n}\n\ninterface InvitationRowProps {\n invitation: InvitationView\n canManage: boolean\n busy: boolean\n onCopy(): void\n onResend(): void\n onRevoke(): void\n}\n\nfunction InvitationRow({ invitation, canManage, busy, onCopy, onResend, onRevoke }: InvitationRowProps) {\n const isPending = invitation.status === 'pending'\n const emailFailed = invitation.emailStatus === 'failed'\n const expiry = new Date(invitation.expiresAt).toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n })\n\n return (\n <div className=\"rounded-lg border border-[var(--border-default)] p-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-[var(--text-primary)]\">{invitation.email}</p>\n <p className=\"text-xs capitalize text-[var(--text-muted)]\">\n {invitation.permissions} · expires {expiry}\n </p>\n {emailFailed && (\n <p className=\"mt-1 text-xs text-[var(--surface-danger-text)]\">Email was not sent — copy the link to share it.</p>\n )}\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n <span className={`${BADGE_BASE} ${STATUS_BADGE[invitation.status]}`}>\n {invitation.status}\n </span>\n <span className={`${BADGE_BASE} ${EMAIL_BADGE[invitation.emailStatus]}`}>\n {invitation.emailStatus.replace('_', ' ')}\n </span>\n </div>\n </div>\n {canManage && isPending && (\n <div className=\"mt-3 flex items-center justify-end gap-2\">\n <button\n type=\"button\"\n onClick={onCopy}\n disabled={busy}\n className=\"rounded border border-[var(--border-default)] px-2 py-1 text-xs text-[var(--text-secondary)] hover:text-[var(--text-primary)] disabled:opacity-50\"\n >\n Copy link\n </button>\n <button\n type=\"button\"\n onClick={onResend}\n disabled={busy}\n className=\"rounded border border-[var(--border-default)] px-2 py-1 text-xs text-[var(--text-secondary)] hover:text-[var(--text-primary)] disabled:opacity-50\"\n >\n {busy ? 'Working…' : 'Resend'}\n </button>\n <button\n type=\"button\"\n onClick={onRevoke}\n disabled={busy}\n className=\"rounded px-2 py-1 text-xs text-[var(--text-danger)] hover:bg-[var(--border-default)] disabled:opacity-50\"\n >\n Revoke\n </button>\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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","names":[]}
|
package/dist/teams/index.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
generateInviteToken,
|
|
3
|
+
isInviteTokenShape,
|
|
4
|
+
validateInviteToken
|
|
5
|
+
} from "../chunk-3SVAA3MA.js";
|
|
1
6
|
import {
|
|
2
7
|
INVITATION_EXPIRY_DAYS,
|
|
3
8
|
generateInvitationToken,
|
|
@@ -7,11 +12,6 @@ import {
|
|
|
7
12
|
parseInvitationPermission,
|
|
8
13
|
renderInvitationEmail
|
|
9
14
|
} from "../chunk-WEBBJBDH.js";
|
|
10
|
-
import {
|
|
11
|
-
generateInviteToken,
|
|
12
|
-
isInviteTokenShape,
|
|
13
|
-
validateInviteToken
|
|
14
|
-
} from "../chunk-3SVAA3MA.js";
|
|
15
15
|
import {
|
|
16
16
|
ASSIGNABLE_WORKSPACE_ROLES,
|
|
17
17
|
ORGANIZATION_ROLES,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SeatLimitError
|
|
3
3
|
} from "../chunk-SWUVTGMR.js";
|
|
4
|
+
import "../chunk-3SVAA3MA.js";
|
|
4
5
|
import {
|
|
5
6
|
generateInvitationToken,
|
|
6
7
|
getInvitationExpiresAt,
|
|
@@ -8,7 +9,6 @@ import {
|
|
|
8
9
|
normalizeInvitationEmail,
|
|
9
10
|
parseInvitationPermission
|
|
10
11
|
} from "../chunk-WEBBJBDH.js";
|
|
11
|
-
import "../chunk-3SVAA3MA.js";
|
|
12
12
|
import {
|
|
13
13
|
hasWorkspaceRole
|
|
14
14
|
} from "../chunk-63CE7FEZ.js";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { SendInvitationEmailSeam } from './invitations-api.js';
|
|
2
|
+
import '../invitations-CZ5G2tIn.js';
|
|
3
|
+
import '../roles-BC1n4t37.js';
|
|
4
|
+
import './members-api.js';
|
|
5
|
+
import '../access-BZ81Btt5.js';
|
|
6
|
+
import 'drizzle-orm/sqlite-core';
|
|
7
|
+
import '../invitations-schema-DaMO4hZE.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Opt-in Resend transport for the teams invitations `sendInvitationEmail` seam.
|
|
11
|
+
* Most adopters back the seam with Resend and hand-roll the same wrapper — and
|
|
12
|
+
* the same mistake: `resend.emails.send()` returns `{ data, error }` and does NOT
|
|
13
|
+
* throw on an API-level failure (unverified domain, rate limit, bad recipient),
|
|
14
|
+
* so a `try/catch` alone records a failed send as a success. This helper sends
|
|
15
|
+
* through the shared `renderInvitationEmail` template and returns a typed failure
|
|
16
|
+
* on BOTH a thrown error AND a non-null `result.error`.
|
|
17
|
+
*
|
|
18
|
+
* `resend` is an OPTIONAL peer, imported only here: apps not on Resend keep
|
|
19
|
+
* passing a raw seam, and the package core never pulls a mail dependency.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
interface ResendInvitationSenderOptions {
|
|
23
|
+
/** RFC-5322 From header, e.g. `GTM Agent <noreply@gtm.tangle.tools>`. */
|
|
24
|
+
from: string;
|
|
25
|
+
/** Resend API key. Defaults to `process.env.RESEND_API_KEY`. */
|
|
26
|
+
apiKey?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Build a `sendInvitationEmail` seam backed by Resend. Wire it into
|
|
30
|
+
* `createInvitationsApi({ sendInvitationEmail: createResendInvitationSender({ from }) })`.
|
|
31
|
+
* The client is built lazily on first send; with no key the seam fails typed
|
|
32
|
+
* (the invitation is still created — emailStatus becomes 'failed').
|
|
33
|
+
*/
|
|
34
|
+
declare function createResendInvitationSender(opts: ResendInvitationSenderOptions): SendInvitationEmailSeam;
|
|
35
|
+
|
|
36
|
+
export { type ResendInvitationSenderOptions, createResendInvitationSender };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {
|
|
2
|
+
renderInvitationEmail
|
|
3
|
+
} from "../chunk-WEBBJBDH.js";
|
|
4
|
+
|
|
5
|
+
// src/teams/resend.ts
|
|
6
|
+
import { Resend } from "resend";
|
|
7
|
+
function createResendInvitationSender(opts) {
|
|
8
|
+
let client = null;
|
|
9
|
+
function getClient() {
|
|
10
|
+
if (client) return client;
|
|
11
|
+
const key = opts.apiKey ?? (typeof process !== "undefined" ? process.env.RESEND_API_KEY : void 0);
|
|
12
|
+
if (!key) return null;
|
|
13
|
+
client = new Resend(key);
|
|
14
|
+
return client;
|
|
15
|
+
}
|
|
16
|
+
return async (input) => {
|
|
17
|
+
const resend = getClient();
|
|
18
|
+
if (!resend) return { succeeded: false, error: "RESEND_API_KEY is not configured" };
|
|
19
|
+
const msg = renderInvitationEmail(input, { fromAddress: opts.from });
|
|
20
|
+
try {
|
|
21
|
+
const result = await resend.emails.send({
|
|
22
|
+
from: msg.from,
|
|
23
|
+
to: input.to,
|
|
24
|
+
subject: msg.subject,
|
|
25
|
+
html: msg.html,
|
|
26
|
+
text: msg.text
|
|
27
|
+
});
|
|
28
|
+
if (result.error) return { succeeded: false, error: result.error.message };
|
|
29
|
+
return { succeeded: true };
|
|
30
|
+
} catch (err) {
|
|
31
|
+
return { succeeded: false, error: err instanceof Error ? err.message : "Invitation email failed to send" };
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
createResendInvitationSender
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=resend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/teams/resend.ts"],"sourcesContent":["/**\n * Opt-in Resend transport for the teams invitations `sendInvitationEmail` seam.\n * Most adopters back the seam with Resend and hand-roll the same wrapper — and\n * the same mistake: `resend.emails.send()` returns `{ data, error }` and does NOT\n * throw on an API-level failure (unverified domain, rate limit, bad recipient),\n * so a `try/catch` alone records a failed send as a success. This helper sends\n * through the shared `renderInvitationEmail` template and returns a typed failure\n * on BOTH a thrown error AND a non-null `result.error`.\n *\n * `resend` is an OPTIONAL peer, imported only here: apps not on Resend keep\n * passing a raw seam, and the package core never pulls a mail dependency.\n */\n\nimport { Resend } from 'resend'\nimport { renderInvitationEmail } from './invitations'\nimport type { SendInvitationEmailSeam } from './invitations-api'\n\nexport interface ResendInvitationSenderOptions {\n /** RFC-5322 From header, e.g. `GTM Agent <noreply@gtm.tangle.tools>`. */\n from: string\n /** Resend API key. Defaults to `process.env.RESEND_API_KEY`. */\n apiKey?: string\n}\n\n/**\n * Build a `sendInvitationEmail` seam backed by Resend. Wire it into\n * `createInvitationsApi({ sendInvitationEmail: createResendInvitationSender({ from }) })`.\n * The client is built lazily on first send; with no key the seam fails typed\n * (the invitation is still created — emailStatus becomes 'failed').\n */\nexport function createResendInvitationSender(opts: ResendInvitationSenderOptions): SendInvitationEmailSeam {\n let client: Resend | null = null\n\n function getClient(): Resend | null {\n if (client) return client\n const key = opts.apiKey ?? (typeof process !== 'undefined' ? process.env.RESEND_API_KEY : undefined)\n if (!key) return null\n client = new Resend(key)\n return client\n }\n\n return async (input) => {\n const resend = getClient()\n if (!resend) return { succeeded: false, error: 'RESEND_API_KEY is not configured' }\n\n const msg = renderInvitationEmail(input, { fromAddress: opts.from })\n try {\n const result = await resend.emails.send({\n from: msg.from,\n to: input.to,\n subject: msg.subject,\n html: msg.html,\n text: msg.text,\n })\n // Resend reports API-level failures in `result.error` WITHOUT throwing — a\n // try/catch alone would mark a failed send as a success.\n if (result.error) return { succeeded: false, error: result.error.message }\n return { succeeded: true }\n } catch (err) {\n return { succeeded: false, error: err instanceof Error ? err.message : 'Invitation email failed to send' }\n }\n }\n}\n"],"mappings":";;;;;AAaA,SAAS,cAAc;AAiBhB,SAAS,6BAA6B,MAA8D;AACzG,MAAI,SAAwB;AAE5B,WAAS,YAA2B;AAClC,QAAI,OAAQ,QAAO;AACnB,UAAM,MAAM,KAAK,WAAW,OAAO,YAAY,cAAc,QAAQ,IAAI,iBAAiB;AAC1F,QAAI,CAAC,IAAK,QAAO;AACjB,aAAS,IAAI,OAAO,GAAG;AACvB,WAAO;AAAA,EACT;AAEA,SAAO,OAAO,UAAU;AACtB,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,OAAQ,QAAO,EAAE,WAAW,OAAO,OAAO,mCAAmC;AAElF,UAAM,MAAM,sBAAsB,OAAO,EAAE,aAAa,KAAK,KAAK,CAAC;AACnE,QAAI;AACF,YAAM,SAAS,MAAM,OAAO,OAAO,KAAK;AAAA,QACtC,MAAM,IAAI;AAAA,QACV,IAAI,MAAM;AAAA,QACV,SAAS,IAAI;AAAA,QACb,MAAM,IAAI;AAAA,QACV,MAAM,IAAI;AAAA,MACZ,CAAC;AAGD,UAAI,OAAO,MAAO,QAAO,EAAE,WAAW,OAAO,OAAO,OAAO,MAAM,QAAQ;AACzE,aAAO,EAAE,WAAW,KAAK;AAAA,IAC3B,SAAS,KAAK;AACZ,aAAO,EAAE,WAAW,OAAO,OAAO,eAAe,QAAQ,IAAI,UAAU,kCAAkC;AAAA,IAC3G;AAAA,EACF;AACF;","names":[]}
|
package/dist/teams-react/lazy.js
CHANGED
|
@@ -4,7 +4,7 @@ var MembersPanelLazy = lazy(
|
|
|
4
4
|
() => import("../MembersPanel-FOVHWUQ3.js").then((m) => ({ default: m.MembersPanel }))
|
|
5
5
|
);
|
|
6
6
|
var InvitationsPanelLazy = lazy(
|
|
7
|
-
() => import("../InvitationsPanel-
|
|
7
|
+
() => import("../InvitationsPanel-XUUWZBPV.js").then((m) => ({ default: m.InvitationsPanel }))
|
|
8
8
|
);
|
|
9
9
|
var InviteAcceptPageLazy = lazy(
|
|
10
10
|
() => import("../InviteAcceptPage-P3QJC3C6.js").then((m) => ({ default: m.InviteAcceptPage }))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-app",
|
|
3
|
-
"version": "0.42.
|
|
3
|
+
"version": "0.42.8",
|
|
4
4
|
"packageManager": "pnpm@10.33.4",
|
|
5
5
|
"description": "Application-shell framework for Tangle agent products: a bounded tool loop, the structured agent→app tool side channel, integration-hub client, per-workspace billing, and crypto — composed over the Tangle agent substrate through typed seams.",
|
|
6
6
|
"keywords": [
|
|
@@ -254,6 +254,11 @@
|
|
|
254
254
|
"import": "./dist/teams/invitations-api.js",
|
|
255
255
|
"default": "./dist/teams/invitations-api.js"
|
|
256
256
|
},
|
|
257
|
+
"./teams/resend": {
|
|
258
|
+
"types": "./dist/teams/resend.d.ts",
|
|
259
|
+
"import": "./dist/teams/resend.js",
|
|
260
|
+
"default": "./dist/teams/resend.js"
|
|
261
|
+
},
|
|
257
262
|
"./teams-react": {
|
|
258
263
|
"types": "./dist/teams-react/index.d.ts",
|
|
259
264
|
"import": "./dist/teams-react/index.js",
|
|
@@ -351,6 +356,7 @@
|
|
|
351
356
|
"react-dom": "^19.2.7",
|
|
352
357
|
"react-konva": "^19.2.5",
|
|
353
358
|
"react-router": "^7.15.1",
|
|
359
|
+
"resend": "^6.12.4",
|
|
354
360
|
"tsup": "^8.0.0",
|
|
355
361
|
"typescript": "^5.7.0",
|
|
356
362
|
"vitest": "^3.0.0"
|
|
@@ -369,7 +375,8 @@
|
|
|
369
375
|
"lucide-react": ">=1",
|
|
370
376
|
"react": ">=18",
|
|
371
377
|
"react-konva": ">=18",
|
|
372
|
-
"react-router": ">=7"
|
|
378
|
+
"react-router": ">=7",
|
|
379
|
+
"resend": ">=6"
|
|
373
380
|
},
|
|
374
381
|
"peerDependenciesMeta": {
|
|
375
382
|
"@huggingface/transformers": {
|
|
@@ -407,6 +414,9 @@
|
|
|
407
414
|
},
|
|
408
415
|
"@radix-ui/react-dialog": {
|
|
409
416
|
"optional": true
|
|
417
|
+
},
|
|
418
|
+
"resend": {
|
|
419
|
+
"optional": true
|
|
410
420
|
}
|
|
411
421
|
},
|
|
412
422
|
"dependencies": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/teams-react/components/InvitationsPanel.tsx"],"sourcesContent":["/**\n * Email-invitation panel: invite by email + role, and a history of every\n * invitation (pending / accepted / expired / revoked) with its email-delivery\n * status. Pending rows expose copy-link / resend / revoke. Fully callback-driven\n * — the host supplies the data and the async `onInvite` / `onResend` / `onRevoke`\n * callbacks (backed by `./teams/invitations-api`), so this imports no app router,\n * fetch client, or toast. Styled with the shipped Tangle Quiet tokens (`var(--*)`).\n *\n * Mount alongside a list-only `MembersPanel` (`showInviteForm={false}`): the\n * members panel shows accepted members, this owns the invite flow + pending list.\n */\n\nimport { useState } from 'react'\nimport type { WorkspaceRole } from '../../teams/roles'\nimport { hasWorkspaceRole } from '../../teams/roles'\nimport type { InvitationView, InvitationsPanelProps } from '../contracts'\n\nconst ASSIGNABLE: { value: WorkspaceRole; label: string }[] = [\n { value: 'viewer', label: 'Viewer' },\n { value: 'editor', label: 'Editor' },\n { value: 'admin', label: 'Admin' },\n]\n\nexport function InvitationsPanel({\n invitations,\n currentRole,\n onInvite,\n onResend,\n onRevoke,\n onCopy,\n onNotice,\n}: InvitationsPanelProps) {\n const [inviteEmail, setInviteEmail] = useState('')\n const [inviteRole, setInviteRole] = useState<WorkspaceRole>('editor')\n const [inviting, setInviting] = useState(false)\n const [busyId, setBusyId] = useState<string | null>(null)\n\n const canManage = hasWorkspaceRole(currentRole, 'admin')\n\n function notify(kind: 'success' | 'error', message: string) {\n onNotice?.({ kind, message })\n }\n\n async function submitInvite() {\n const email = inviteEmail.trim()\n if (!email || inviting) return\n setInviting(true)\n try {\n await onInvite({ email, role: inviteRole })\n notify('success', `Invitation sent to ${email}`)\n setInviteEmail('')\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to invite')\n } finally {\n setInviting(false)\n }\n }\n\n async function copyLink(inviteUrl: string) {\n try {\n if (onCopy) await onCopy({ inviteUrl })\n else await navigator.clipboard.writeText(inviteUrl)\n notify('success', 'Invite link copied')\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to copy link')\n }\n }\n\n async function resend(invitationId: string) {\n setBusyId(invitationId)\n try {\n await onResend({ invitationId })\n notify('success', 'Invitation resent')\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to resend invitation')\n } finally {\n setBusyId(null)\n }\n }\n\n async function revoke(invitationId: string) {\n setBusyId(invitationId)\n try {\n await onRevoke({ invitationId })\n notify('success', 'Invitation revoked')\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to revoke invitation')\n } finally {\n setBusyId(null)\n }\n }\n\n return (\n <section className=\"flex flex-col gap-4\">\n {canManage && (\n <div className=\"flex flex-col gap-1.5\">\n <label className=\"text-xs font-medium text-[var(--text-muted)]\">Invite by email</label>\n <div className=\"flex gap-2\">\n <input\n type=\"email\"\n placeholder=\"colleague@example.com\"\n value={inviteEmail}\n aria-label=\"Invite email address\"\n onChange={(event) => setInviteEmail(event.target.value)}\n onKeyDown={(event) => { if (event.key === 'Enter') void submitInvite() }}\n className=\"flex-1 rounded border border-[var(--border-default)] bg-[var(--bg-input)] px-3 py-1.5 text-sm text-[var(--text-primary)] placeholder:text-[var(--text-muted)]\"\n />\n <select\n value={inviteRole}\n aria-label=\"Invite role\"\n onChange={(event) => setInviteRole(event.target.value as WorkspaceRole)}\n className=\"rounded border border-[var(--border-default)] bg-[var(--bg-input)] px-2 py-1.5 text-xs text-[var(--text-secondary)]\"\n >\n {ASSIGNABLE.map((option) => (\n <option key={option.value} value={option.value}>{option.label}</option>\n ))}\n </select>\n <button\n type=\"button\"\n onClick={() => void submitInvite()}\n disabled={inviting || !inviteEmail.trim()}\n className=\"rounded bg-[var(--brand-primary)] px-3 py-1.5 text-sm text-white disabled:opacity-50\"\n >\n {inviting ? 'Inviting…' : 'Invite'}\n </button>\n </div>\n </div>\n )}\n\n <div className=\"flex flex-col gap-2 border-t border-[var(--border-default)] pt-3\">\n <div className=\"flex items-center justify-between\">\n <h4 className=\"text-xs font-semibold text-[var(--text-primary)]\">Invitation history</h4>\n <span className=\"text-xs text-[var(--text-muted)]\">{invitations.length} total</span>\n </div>\n {invitations.length === 0 ? (\n <p className=\"text-sm text-[var(--text-muted)]\">No invitations yet.</p>\n ) : (\n invitations.map((invitation) => (\n <InvitationRow\n key={invitation.id}\n invitation={invitation}\n canManage={canManage}\n busy={busyId === invitation.id}\n onCopy={() => void copyLink(invitation.inviteUrl)}\n onResend={() => void resend(invitation.id)}\n onRevoke={() => void revoke(invitation.id)}\n />\n ))\n )}\n </div>\n </section>\n )\n}\n\ninterface InvitationRowProps {\n invitation: InvitationView\n canManage: boolean\n busy: boolean\n onCopy(): void\n onResend(): void\n onRevoke(): void\n}\n\nfunction InvitationRow({ invitation, canManage, busy, onCopy, onResend, onRevoke }: InvitationRowProps) {\n const isPending = invitation.status === 'pending'\n const emailFailed = invitation.emailStatus === 'failed'\n const expiry = new Date(invitation.expiresAt).toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n })\n\n return (\n <div className=\"rounded-lg border border-[var(--border-default)] p-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-[var(--text-primary)]\">{invitation.email}</p>\n <p className=\"text-xs capitalize text-[var(--text-muted)]\">\n {invitation.permissions} · expires {expiry}\n </p>\n {emailFailed && (\n <p className=\"mt-1 text-xs text-[var(--text-danger)]\">Email was not sent — copy the link to share it.</p>\n )}\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n <span className=\"rounded border border-[var(--border-default)] px-2 py-0.5 text-[10px] uppercase text-[var(--text-secondary)]\">\n {invitation.status}\n </span>\n <span\n className={`rounded border border-[var(--border-default)] px-2 py-0.5 text-[10px] uppercase ${\n emailFailed ? 'text-[var(--text-danger)]' : 'text-[var(--text-muted)]'\n }`}\n >\n {invitation.emailStatus.replace('_', ' ')}\n </span>\n </div>\n </div>\n {canManage && isPending && (\n <div className=\"mt-3 flex items-center justify-end gap-2\">\n <button\n type=\"button\"\n onClick={onCopy}\n disabled={busy}\n className=\"rounded border border-[var(--border-default)] px-2 py-1 text-xs text-[var(--text-secondary)] hover:text-[var(--text-primary)] disabled:opacity-50\"\n >\n Copy link\n </button>\n <button\n type=\"button\"\n onClick={onResend}\n disabled={busy}\n className=\"rounded border border-[var(--border-default)] px-2 py-1 text-xs text-[var(--text-secondary)] hover:text-[var(--text-primary)] disabled:opacity-50\"\n >\n {busy ? 'Working…' : 'Resend'}\n </button>\n <button\n type=\"button\"\n onClick={onRevoke}\n disabled={busy}\n className=\"rounded px-2 py-1 text-xs text-[var(--text-danger)] hover:bg-[var(--border-default)] disabled:opacity-50\"\n >\n Revoke\n </button>\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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","names":[]}
|
|
File without changes
|