@dench.com/cli 3.8.6-staging.409 → 3.9.0-staging.415

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.
@@ -0,0 +1,205 @@
1
+ /** Explicit, portable navigation metadata. Never derive identities from prose. */
2
+ type ReferencePresentation = {
3
+ label: string;
4
+ href: string;
5
+ url?: string;
6
+ imageUrl?: string;
7
+ objectIcon?: string;
8
+ };
9
+
10
+ export type WorkspaceReference = ReferencePresentation &
11
+ (
12
+ | { kind: "crm-entry"; objectName: string; entryId: string }
13
+ | { kind: "crm-object"; objectName: string; objectId?: string }
14
+ | { kind: "campaign"; sequenceId: string }
15
+ );
16
+
17
+ export type WorkspaceReferenceCoverage = {
18
+ returned: number;
19
+ /** References available in this result, never the total matching dataset. */
20
+ available: number;
21
+ truncated: boolean;
22
+ };
23
+
24
+ export type WorkspaceReferences = {
25
+ references: WorkspaceReference[];
26
+ referenceCoverage: WorkspaceReferenceCoverage;
27
+ };
28
+
29
+ export const WORKSPACE_REFERENCE_LIMIT = 100;
30
+ export const WORKSPACE_REFERENCE_BYTE_LIMIT = 16 * 1024;
31
+
32
+ export function workspaceReferenceKey(reference: WorkspaceReference): string {
33
+ if (reference.kind === "campaign") return `campaign:${reference.sequenceId}`;
34
+ if (reference.kind === "crm-object")
35
+ return `crm-object:${reference.objectName}`;
36
+ return `crm-entry:${reference.objectName}:${reference.entryId}`;
37
+ }
38
+
39
+ export function workspaceReferenceHref(
40
+ reference:
41
+ | { kind: "crm-entry"; objectName: string; entryId: string }
42
+ | { kind: "crm-object"; objectName: string }
43
+ | { kind: "campaign"; sequenceId: string },
44
+ ): string {
45
+ if (reference.kind === "campaign")
46
+ return `/?path=${encodeURIComponent(`~outreach/sequences/${reference.sequenceId}`)}`;
47
+ const object = encodeURIComponent(reference.objectName);
48
+ return reference.kind === "crm-object"
49
+ ? `/?path=${object}`
50
+ : `/?path=${object}&entry=${object}:${encodeURIComponent(reference.entryId)}`;
51
+ }
52
+
53
+ export function withWorkspaceReferenceUrls(
54
+ reference: WorkspaceReference,
55
+ context: { host?: string; workspaceSlug?: string },
56
+ ): WorkspaceReference {
57
+ const href = workspaceReferenceHref(reference);
58
+ const { url: _oldUrl, ...rest } = reference;
59
+ const slug = context.workspaceSlug?.trim();
60
+ const host = context.host?.trim();
61
+ if (!host || !slug) return { ...rest, href };
62
+ try {
63
+ const origin = new URL(
64
+ /^https?:\/\//i.test(host) ? host : `https://${host}`,
65
+ );
66
+ if (!["http:", "https:"].includes(origin.protocol))
67
+ return { ...rest, href };
68
+ return {
69
+ ...rest,
70
+ href,
71
+ url: `${origin.origin}/${encodeURIComponent(slug)}${href.slice(1)}`,
72
+ };
73
+ } catch {
74
+ return { ...rest, href };
75
+ }
76
+ }
77
+
78
+ const text = (value: unknown, max: number): value is string =>
79
+ typeof value === "string" && value.trim().length > 0 && value.length <= max;
80
+
81
+ /** Validate typed metadata at the display boundary; ignore arbitrary ID fields. */
82
+ export function parseWorkspaceReference(
83
+ value: unknown,
84
+ ): WorkspaceReference | null {
85
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
86
+ const row = value as Record<string, unknown>;
87
+ if (!text(row.label, 2048) || !text(row.href, 4096)) return null;
88
+ const presentation: ReferencePresentation = {
89
+ label: row.label,
90
+ href: row.href,
91
+ };
92
+ if (text(row.objectIcon, 128)) presentation.objectIcon = row.objectIcon;
93
+ for (const key of ["imageUrl", "url"] as const) {
94
+ if (!text(row[key], 4096)) continue;
95
+ try {
96
+ const url = new URL(row[key]);
97
+ if (["http:", "https:"].includes(url.protocol))
98
+ presentation[key] = row[key];
99
+ } catch {
100
+ /* optional invalid URLs do not make an identity valid */
101
+ }
102
+ }
103
+ let reference: WorkspaceReference;
104
+ if (row.kind === "campaign" && text(row.sequenceId, 256)) {
105
+ reference = {
106
+ ...presentation,
107
+ kind: "campaign",
108
+ sequenceId: row.sequenceId,
109
+ };
110
+ } else if (
111
+ row.kind === "crm-entry" &&
112
+ text(row.objectName, 256) &&
113
+ text(row.entryId, 256)
114
+ ) {
115
+ reference = {
116
+ ...presentation,
117
+ kind: "crm-entry",
118
+ objectName: row.objectName,
119
+ entryId: row.entryId,
120
+ };
121
+ } else if (row.kind === "crm-object" && text(row.objectName, 256)) {
122
+ reference = {
123
+ ...presentation,
124
+ kind: "crm-object",
125
+ objectName: row.objectName,
126
+ ...(text(row.objectId, 256) ? { objectId: row.objectId } : {}),
127
+ };
128
+ } else return null;
129
+ return reference.href === workspaceReferenceHref(reference)
130
+ ? reference
131
+ : null;
132
+ }
133
+
134
+ /** Bound complete serialized metadata, including its coverage, in UTF-8 bytes. */
135
+ export function boundWorkspaceReferences(
136
+ candidates: readonly WorkspaceReference[],
137
+ available?: number,
138
+ ): WorkspaceReferences {
139
+ const unique = new Map<string, WorkspaceReference>();
140
+ for (const candidate of candidates) {
141
+ const reference = parseWorkspaceReference(candidate);
142
+ if (reference) unique.set(workspaceReferenceKey(reference), reference);
143
+ }
144
+ const count = Math.max(
145
+ unique.size,
146
+ typeof available === "number" && Number.isFinite(available)
147
+ ? Math.max(0, Math.trunc(available))
148
+ : unique.size,
149
+ );
150
+ const result: WorkspaceReferences = {
151
+ references: [],
152
+ referenceCoverage: { returned: 0, available: count, truncated: count > 0 },
153
+ };
154
+ const encoder = new TextEncoder();
155
+ for (const reference of unique.values()) {
156
+ if (result.references.length >= WORKSPACE_REFERENCE_LIMIT) break;
157
+ result.references.push(reference);
158
+ result.referenceCoverage.returned = result.references.length;
159
+ result.referenceCoverage.truncated = result.references.length < count;
160
+ if (
161
+ encoder.encode(JSON.stringify(result)).byteLength >
162
+ WORKSPACE_REFERENCE_BYTE_LIMIT
163
+ ) {
164
+ result.references.pop();
165
+ result.referenceCoverage.returned = result.references.length;
166
+ result.referenceCoverage.truncated = result.references.length < count;
167
+ break;
168
+ }
169
+ }
170
+ return result;
171
+ }
172
+
173
+ /** Add shareable links only to the explicit envelope, never inside user data. */
174
+ export function withWorkspaceReferenceEnvelopeUrls(
175
+ value: unknown,
176
+ context: { host?: string; workspaceSlug?: string },
177
+ ): unknown {
178
+ if (!value || typeof value !== "object" || Array.isArray(value)) return value;
179
+ const record = value as Record<string, unknown>;
180
+ if (!Array.isArray(record.references)) return value;
181
+ const coverage = record.referenceCoverage as
182
+ | Partial<WorkspaceReferenceCoverage>
183
+ | undefined;
184
+ if (
185
+ !coverage ||
186
+ typeof coverage !== "object" ||
187
+ Array.isArray(coverage) ||
188
+ !Number.isSafeInteger(coverage.returned) ||
189
+ coverage.returned !== record.references.length ||
190
+ typeof coverage.available !== "number" ||
191
+ !Number.isSafeInteger(coverage.available) ||
192
+ coverage.available < coverage.returned ||
193
+ typeof coverage.truncated !== "boolean" ||
194
+ coverage.truncated !== coverage.available > coverage.returned
195
+ )
196
+ return value;
197
+ const refs: WorkspaceReference[] = [];
198
+ for (const raw of record.references) {
199
+ const reference = parseWorkspaceReference(raw);
200
+ if (!reference) return value;
201
+ refs.push(withWorkspaceReferenceUrls(reference, context));
202
+ }
203
+ const metadata = boundWorkspaceReferences(refs, coverage.available);
204
+ return { ...record, ...metadata };
205
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dench.com/cli",
3
- "version": "3.8.6-staging.409",
3
+ "version": "3.9.0-staging.415",
4
4
  "description": "Dench agent workspace CLI.",
5
5
  "type": "module",
6
6
  "bin": {