crewly 1.20.29 → 1.20.31
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/config/skills/agent/core/canva-create/SKILL.md +53 -0
- package/config/skills/agent/core/canva-create/execute.sh +88 -0
- package/config/skills/agent/core/canva-create/execute.test.sh +54 -0
- package/config/skills/agent/core/canva-designs/SKILL.md +51 -0
- package/config/skills/agent/core/canva-designs/execute.sh +96 -0
- package/config/skills/agent/core/canva-designs/execute.test.sh +54 -0
- package/config/skills/agent/core/canva-export/SKILL.md +52 -0
- package/config/skills/agent/core/canva-export/execute.sh +111 -0
- package/config/skills/agent/core/canva-export/execute.test.sh +55 -0
- package/config/skills/agent/core/canva-upload/SKILL.md +49 -0
- package/config/skills/agent/core/canva-upload/execute.sh +72 -0
- package/config/skills/agent/core/canva-upload/execute.test.sh +54 -0
- package/config/skills/agent/core/docs-read/SKILL.md +50 -0
- package/config/skills/agent/core/docs-read/execute.sh +68 -0
- package/config/skills/agent/core/docs-read/execute.test.sh +52 -0
- package/config/skills/agent/core/docs-write/SKILL.md +55 -0
- package/config/skills/agent/core/docs-write/execute.sh +90 -0
- package/config/skills/agent/core/docs-write/execute.test.sh +54 -0
- package/config/skills/agent/core/drive-read/SKILL.md +53 -0
- package/config/skills/agent/core/drive-read/execute.sh +79 -0
- package/config/skills/agent/core/drive-read/execute.test.sh +55 -0
- package/config/skills/agent/core/drive-search/SKILL.md +55 -0
- package/config/skills/agent/core/drive-search/execute.sh +87 -0
- package/config/skills/agent/core/drive-search/execute.test.sh +54 -0
- package/config/skills/agent/core/drive-upload/SKILL.md +54 -0
- package/config/skills/agent/core/drive-upload/execute.sh +117 -0
- package/config/skills/agent/core/drive-upload/execute.test.sh +57 -0
- package/config/skills/agent/core/sheets-read/SKILL.md +53 -0
- package/config/skills/agent/core/sheets-read/execute.sh +81 -0
- package/config/skills/agent/core/sheets-read/execute.test.sh +52 -0
- package/config/skills/agent/core/sheets-write/SKILL.md +56 -0
- package/config/skills/agent/core/sheets-write/execute.sh +103 -0
- package/config/skills/agent/core/sheets-write/execute.test.sh +57 -0
- package/config/skills/agent/core/slides-create/SKILL.md +61 -0
- package/config/skills/agent/core/slides-create/execute.sh +92 -0
- package/config/skills/agent/core/slides-create/execute.test.sh +54 -0
- package/config/skills/agent/core/slides-read/SKILL.md +49 -0
- package/config/skills/agent/core/slides-read/execute.sh +67 -0
- package/config/skills/agent/core/slides-read/execute.test.sh +50 -0
- package/dist/backend/backend/src/constants.d.ts +69 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +73 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/canva/canva.controller.d.ts +48 -0
- package/dist/backend/backend/src/controllers/canva/canva.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/canva/canva.controller.js +183 -0
- package/dist/backend/backend/src/controllers/canva/canva.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/canva/canva.routes.d.ts +22 -0
- package/dist/backend/backend/src/controllers/canva/canva.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/canva/canva.routes.js +34 -0
- package/dist/backend/backend/src/controllers/canva/canva.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/google/google.controller.d.ts +100 -0
- package/dist/backend/backend/src/controllers/google/google.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/google/google.controller.js +237 -1
- package/dist/backend/backend/src/controllers/google/google.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/google/google.routes.d.ts +13 -0
- package/dist/backend/backend/src/controllers/google/google.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/google/google.routes.js +27 -1
- package/dist/backend/backend/src/controllers/google/google.routes.js.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.js +3 -0
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.js +22 -4
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/canva/canva-token.service.d.ts +98 -0
- package/dist/backend/backend/src/services/canva/canva-token.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/canva/canva-token.service.js +198 -0
- package/dist/backend/backend/src/services/canva/canva-token.service.js.map +1 -0
- package/dist/backend/backend/src/services/canva/canva.service.d.ts +184 -0
- package/dist/backend/backend/src/services/canva/canva.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/canva/canva.service.js +274 -0
- package/dist/backend/backend/src/services/canva/canva.service.js.map +1 -0
- package/dist/backend/backend/src/services/google/docs.service.d.ts +117 -0
- package/dist/backend/backend/src/services/google/docs.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/google/docs.service.js +152 -0
- package/dist/backend/backend/src/services/google/docs.service.js.map +1 -0
- package/dist/backend/backend/src/services/google/drive.service.d.ts +157 -0
- package/dist/backend/backend/src/services/google/drive.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/google/drive.service.js +203 -0
- package/dist/backend/backend/src/services/google/drive.service.js.map +1 -0
- package/dist/backend/backend/src/services/google/google-api.client.d.ts +15 -7
- package/dist/backend/backend/src/services/google/google-api.client.d.ts.map +1 -1
- package/dist/backend/backend/src/services/google/google-api.client.js +13 -6
- package/dist/backend/backend/src/services/google/google-api.client.js.map +1 -1
- package/dist/backend/backend/src/services/google/sheets.service.d.ts +118 -0
- package/dist/backend/backend/src/services/google/sheets.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/google/sheets.service.js +158 -0
- package/dist/backend/backend/src/services/google/sheets.service.js.map +1 -0
- package/dist/backend/backend/src/services/google/slides.service.d.ts +136 -0
- package/dist/backend/backend/src/services/google/slides.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/google/slides.service.js +153 -0
- package/dist/backend/backend/src/services/google/slides.service.js.map +1 -0
- package/dist/backend/backend/src/utils/tool-call-markup.utils.d.ts +45 -0
- package/dist/backend/backend/src/utils/tool-call-markup.utils.d.ts.map +1 -0
- package/dist/backend/backend/src/utils/tool-call-markup.utils.js +83 -0
- package/dist/backend/backend/src/utils/tool-call-markup.utils.js.map +1 -0
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +69 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +73 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.js +22 -4
- package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/cli/backend/src/utils/tool-call-markup.utils.d.ts +45 -0
- package/dist/cli/backend/src/utils/tool-call-markup.utils.d.ts.map +1 -0
- package/dist/cli/backend/src/utils/tool-call-markup.utils.js +83 -0
- package/dist/cli/backend/src/utils/tool-call-markup.utils.js.map +1 -0
- package/frontend/dist/assets/{index-d1bd0dec.js → index-96b51cd9.js} +243 -243
- package/frontend/dist/index.html +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CanvaService — Canva Connect REST on the owner's grant.
|
|
3
|
+
*
|
|
4
|
+
* What agents can do: find designs, create a blank design (preset type or
|
|
5
|
+
* custom size, optionally from an uploaded asset), export a design
|
|
6
|
+
* (PDF / PNG / JPG / PPTX / GIF / MP4 — an async job, polled here to a
|
|
7
|
+
* download URL), and upload images / videos as assets. Video *generation*
|
|
8
|
+
* is not in the API: agents fill, duplicate and export, they do not render
|
|
9
|
+
* from scratch. Brand templates need Canva Enterprise and are not wired.
|
|
10
|
+
*
|
|
11
|
+
* @module services/canva/canva.service
|
|
12
|
+
*/
|
|
13
|
+
import { CANVA_CONSTANTS } from '../../constants.js';
|
|
14
|
+
import { CanvaError } from './canva-token.service.js';
|
|
15
|
+
/**
|
|
16
|
+
* Trim a Canva design resource.
|
|
17
|
+
*
|
|
18
|
+
* @param d - Wire design
|
|
19
|
+
* @returns Trimmed
|
|
20
|
+
*/
|
|
21
|
+
export function toDesign(d) {
|
|
22
|
+
return {
|
|
23
|
+
id: d.id ?? '',
|
|
24
|
+
title: d.title ?? '',
|
|
25
|
+
...(d.urls?.edit_url ? { editUrl: d.urls.edit_url } : {}),
|
|
26
|
+
...(d.urls?.view_url ? { viewUrl: d.urls.view_url } : {}),
|
|
27
|
+
...(d.thumbnail?.url ? { thumbnailUrl: d.thumbnail.url } : {}),
|
|
28
|
+
...(d.page_count !== undefined ? { pageCount: d.page_count } : {}),
|
|
29
|
+
...(d.created_at ? { createdAt: new Date(d.created_at * 1000).toISOString() } : {}),
|
|
30
|
+
...(d.updated_at ? { updatedAt: new Date(d.updated_at * 1000).toISOString() } : {}),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The `format` object for an export job.
|
|
35
|
+
*
|
|
36
|
+
* @param input - Export input
|
|
37
|
+
* @returns Canva format object
|
|
38
|
+
* @throws CanvaError(400, validation) for an unknown format / bad quality
|
|
39
|
+
*/
|
|
40
|
+
export function buildExportFormat(input) {
|
|
41
|
+
const CODES = CANVA_CONSTANTS.ERROR_CODES;
|
|
42
|
+
const type = (input.format ?? '').trim().toLowerCase();
|
|
43
|
+
if (!CANVA_CONSTANTS.EXPORT_FORMATS.includes(type)) {
|
|
44
|
+
throw new CanvaError(400, CODES.VALIDATION, `format must be one of ${CANVA_CONSTANTS.EXPORT_FORMATS.join(', ')}`);
|
|
45
|
+
}
|
|
46
|
+
const pages = (input.pages ?? []).map((p) => Number(p)).filter((p) => Number.isInteger(p) && p > 0);
|
|
47
|
+
const format = { type, ...(pages.length ? { pages } : {}) };
|
|
48
|
+
if (type === 'jpg') {
|
|
49
|
+
const quality = input.quality ?? 80;
|
|
50
|
+
if (!Number.isInteger(quality) || quality < 1 || quality > 100)
|
|
51
|
+
throw new CanvaError(400, CODES.VALIDATION, 'quality must be 1–100');
|
|
52
|
+
format.quality = quality;
|
|
53
|
+
}
|
|
54
|
+
if (type === 'mp4')
|
|
55
|
+
format.quality = (input.videoQuality ?? '').trim() || 'horizontal_1080p';
|
|
56
|
+
return format;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Canva Connect calls.
|
|
60
|
+
*/
|
|
61
|
+
export class CanvaService {
|
|
62
|
+
deps;
|
|
63
|
+
base = CANVA_CONSTANTS.API_BASE;
|
|
64
|
+
/**
|
|
65
|
+
* @param deps - Token provider, fetch, sleep
|
|
66
|
+
*/
|
|
67
|
+
constructor(deps) {
|
|
68
|
+
this.deps = {
|
|
69
|
+
...deps,
|
|
70
|
+
fetchImpl: deps.fetchImpl ?? fetch,
|
|
71
|
+
sleep: deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms))),
|
|
72
|
+
now: deps.now ?? (() => Date.now()),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* `GET /designs` — search / list.
|
|
77
|
+
*
|
|
78
|
+
* @param input - Query, ownership, sort, limit, continuation
|
|
79
|
+
* @returns Designs + continuation token
|
|
80
|
+
*/
|
|
81
|
+
async listDesigns(input = {}) {
|
|
82
|
+
const limit = Math.min(Math.max(1, input.limit ?? CANVA_CONSTANTS.DESIGNS_DEFAULT_LIMIT), CANVA_CONSTANTS.DESIGNS_LIMIT_CEILING);
|
|
83
|
+
const url = new URL(`${this.base}/designs`);
|
|
84
|
+
url.searchParams.set('limit', String(limit));
|
|
85
|
+
if (input.query?.trim())
|
|
86
|
+
url.searchParams.set('query', input.query.trim());
|
|
87
|
+
if (input.ownership)
|
|
88
|
+
url.searchParams.set('ownership', input.ownership);
|
|
89
|
+
if (input.sortBy)
|
|
90
|
+
url.searchParams.set('sort_by', input.sortBy);
|
|
91
|
+
if (input.continuation)
|
|
92
|
+
url.searchParams.set('continuation', input.continuation);
|
|
93
|
+
const data = await this.request(url.toString());
|
|
94
|
+
return { designs: (data.items ?? []).map(toDesign), ...(data.continuation ? { continuation: data.continuation } : {}) };
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* `GET /designs/:id`.
|
|
98
|
+
*
|
|
99
|
+
* @param id - Design id
|
|
100
|
+
* @returns The design
|
|
101
|
+
*/
|
|
102
|
+
async getDesign(id) {
|
|
103
|
+
const designId = (id ?? '').trim();
|
|
104
|
+
if (!designId)
|
|
105
|
+
throw new CanvaError(400, CANVA_CONSTANTS.ERROR_CODES.VALIDATION, '"id" is required');
|
|
106
|
+
const data = await this.request(`${this.base}/designs/${encodeURIComponent(designId)}`);
|
|
107
|
+
return toDesign(data.design ?? {});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* `POST /designs` — a new design from a preset type, a custom size, or an asset.
|
|
111
|
+
*
|
|
112
|
+
* @param input - Title + type/size/asset
|
|
113
|
+
* @returns The new design (with editUrl)
|
|
114
|
+
* @throws CanvaError(400, validation) when neither a valid preset, size nor asset is given
|
|
115
|
+
*/
|
|
116
|
+
async createDesign(input) {
|
|
117
|
+
const CODES = CANVA_CONSTANTS.ERROR_CODES;
|
|
118
|
+
const body = {};
|
|
119
|
+
const title = (input.title ?? '').trim();
|
|
120
|
+
if (title)
|
|
121
|
+
body.title = title.slice(0, 255);
|
|
122
|
+
const preset = (input.preset ?? '').trim().toLowerCase();
|
|
123
|
+
if (preset) {
|
|
124
|
+
if (!CANVA_CONSTANTS.PRESET_DESIGN_TYPES.includes(preset)) {
|
|
125
|
+
throw new CanvaError(400, CODES.VALIDATION, `preset must be one of ${CANVA_CONSTANTS.PRESET_DESIGN_TYPES.join(', ')} (or give width/height)`);
|
|
126
|
+
}
|
|
127
|
+
body.design_type = { type: 'preset', name: preset };
|
|
128
|
+
}
|
|
129
|
+
else if (input.width !== undefined || input.height !== undefined) {
|
|
130
|
+
const w = Number(input.width);
|
|
131
|
+
const h = Number(input.height);
|
|
132
|
+
if (![w, h].every((v) => Number.isInteger(v) && v >= 40 && v <= 8000)) {
|
|
133
|
+
throw new CanvaError(400, CODES.VALIDATION, 'width and height must be integers between 40 and 8000');
|
|
134
|
+
}
|
|
135
|
+
body.design_type = { type: 'custom', width: w, height: h };
|
|
136
|
+
}
|
|
137
|
+
if (input.assetId?.trim())
|
|
138
|
+
body.asset_id = input.assetId.trim();
|
|
139
|
+
if (!body.design_type && !body.asset_id) {
|
|
140
|
+
throw new CanvaError(400, CODES.VALIDATION, 'give a preset (doc|whiteboard|presentation), a width+height, or an assetId');
|
|
141
|
+
}
|
|
142
|
+
const data = await this.request(`${this.base}/designs`, { method: 'POST', body });
|
|
143
|
+
return toDesign(data.design ?? {});
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* `POST /exports` then poll `GET /exports/:id` until done.
|
|
147
|
+
*
|
|
148
|
+
* @param input - Design, format, options
|
|
149
|
+
* @returns Download URLs (or the failure)
|
|
150
|
+
*/
|
|
151
|
+
async exportDesign(input) {
|
|
152
|
+
const designId = (input.designId ?? '').trim();
|
|
153
|
+
if (!designId)
|
|
154
|
+
throw new CanvaError(400, CANVA_CONSTANTS.ERROR_CODES.VALIDATION, '"designId" is required');
|
|
155
|
+
const format = buildExportFormat(input);
|
|
156
|
+
const started = await this.request(`${this.base}/exports`, { method: 'POST', body: { design_id: designId, format } });
|
|
157
|
+
const job = await this.pollJob(`${this.base}/exports/${encodeURIComponent(started.job?.id ?? '')}`, started.job);
|
|
158
|
+
return { jobId: job.id ?? '', status: job.status ?? 'failed', urls: job.urls ?? [], ...(job.error ? { error: job.error } : {}) };
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* `POST /asset-uploads` (binary body) then poll `GET /asset-uploads/:id`.
|
|
162
|
+
*
|
|
163
|
+
* @param name - Asset name (≤ 50 chars)
|
|
164
|
+
* @param bytes - File content
|
|
165
|
+
* @returns The asset
|
|
166
|
+
* @throws CanvaError(400, validation) for an empty/oversized file; 502 when the job fails
|
|
167
|
+
*/
|
|
168
|
+
async uploadAsset(name, bytes) {
|
|
169
|
+
const CODES = CANVA_CONSTANTS.ERROR_CODES;
|
|
170
|
+
const assetName = (name ?? '').trim().slice(0, 50);
|
|
171
|
+
if (!assetName)
|
|
172
|
+
throw new CanvaError(400, CODES.VALIDATION, '"name" is required');
|
|
173
|
+
if (!bytes || bytes.length === 0)
|
|
174
|
+
throw new CanvaError(400, CODES.VALIDATION, 'file is empty');
|
|
175
|
+
if (bytes.length > CANVA_CONSTANTS.ASSET_MAX_BYTES)
|
|
176
|
+
throw new CanvaError(400, CODES.VALIDATION, `file exceeds ${CANVA_CONSTANTS.ASSET_MAX_BYTES} bytes`);
|
|
177
|
+
const started = await this.request(`${this.base}/asset-uploads`, {
|
|
178
|
+
method: 'POST',
|
|
179
|
+
rawBody: bytes,
|
|
180
|
+
headers: {
|
|
181
|
+
'Content-Type': 'application/octet-stream',
|
|
182
|
+
'Asset-Upload-Metadata': JSON.stringify({ name_base64: Buffer.from(assetName, 'utf8').toString('base64') }),
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
const job = await this.pollJob(`${this.base}/asset-uploads/${encodeURIComponent(started.job?.id ?? '')}`, started.job);
|
|
186
|
+
if (job.status !== 'success' || !job.asset) {
|
|
187
|
+
throw new CanvaError(502, CODES.CANVA_ERROR, `Asset upload failed: ${job.error?.message ?? job.error?.code ?? job.status}`);
|
|
188
|
+
}
|
|
189
|
+
return {
|
|
190
|
+
id: job.asset.id ?? '',
|
|
191
|
+
name: job.asset.name ?? assetName,
|
|
192
|
+
...(job.asset.thumbnail?.url ? { thumbnailUrl: job.asset.thumbnail.url } : {}),
|
|
193
|
+
...(job.asset.created_at ? { createdAt: new Date(job.asset.created_at * 1000).toISOString() } : {}),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
// -------------------------------------------------------------------------
|
|
197
|
+
// Internals
|
|
198
|
+
// -------------------------------------------------------------------------
|
|
199
|
+
/**
|
|
200
|
+
* Poll a job until it leaves `in_progress` or the ceiling passes.
|
|
201
|
+
*
|
|
202
|
+
* @param url - Job URL
|
|
203
|
+
* @param first - The job as returned by the create call
|
|
204
|
+
* @returns The final job
|
|
205
|
+
*/
|
|
206
|
+
async pollJob(url, first) {
|
|
207
|
+
let job = first ?? {};
|
|
208
|
+
const deadline = this.deps.now() + CANVA_CONSTANTS.JOB_POLL_TIMEOUT_MS;
|
|
209
|
+
while (job.status === 'in_progress' && this.deps.now() < deadline) {
|
|
210
|
+
await this.deps.sleep(CANVA_CONSTANTS.JOB_POLL_INTERVAL_MS);
|
|
211
|
+
job = (await this.request(url)).job ?? {};
|
|
212
|
+
}
|
|
213
|
+
if (job.status === 'in_progress') {
|
|
214
|
+
throw new CanvaError(504, CANVA_CONSTANTS.ERROR_CODES.CANVA_ERROR, `Canva job ${job.id ?? ''} is still running after ${CANVA_CONSTANTS.JOB_POLL_TIMEOUT_MS / 1000}s`);
|
|
215
|
+
}
|
|
216
|
+
return job;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Authenticated call; 401 drops the cached token, 403/404/429 pass
|
|
220
|
+
* through, other failures fold into 502.
|
|
221
|
+
*
|
|
222
|
+
* @param url - Absolute URL
|
|
223
|
+
* @param init - Method / body / headers
|
|
224
|
+
* @returns Parsed JSON
|
|
225
|
+
*/
|
|
226
|
+
async request(url, init = {}) {
|
|
227
|
+
const CODES = CANVA_CONSTANTS.ERROR_CODES;
|
|
228
|
+
const token = await this.deps.tokens.getAccessToken();
|
|
229
|
+
let res;
|
|
230
|
+
try {
|
|
231
|
+
res = await this.deps.fetchImpl(url, {
|
|
232
|
+
method: init.method ?? 'GET',
|
|
233
|
+
headers: {
|
|
234
|
+
Authorization: `Bearer ${token}`,
|
|
235
|
+
Accept: 'application/json',
|
|
236
|
+
...(init.body !== undefined ? { 'Content-Type': 'application/json' } : {}),
|
|
237
|
+
...(init.headers ?? {}),
|
|
238
|
+
},
|
|
239
|
+
body: init.rawBody ?? (init.body !== undefined ? JSON.stringify(init.body) : undefined),
|
|
240
|
+
signal: AbortSignal.timeout(CANVA_CONSTANTS.REQUEST_TIMEOUT_MS),
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
throw new CanvaError(502, CODES.NETWORK, `Canva unreachable: ${err instanceof Error ? err.message : String(err)}`);
|
|
245
|
+
}
|
|
246
|
+
const text = await res.text();
|
|
247
|
+
if (!res.ok) {
|
|
248
|
+
let message = `Canva request failed (${res.status})`;
|
|
249
|
+
try {
|
|
250
|
+
const parsed = JSON.parse(text);
|
|
251
|
+
message = parsed.message ?? parsed.code ?? message;
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
if (text)
|
|
255
|
+
message = text.slice(0, 200);
|
|
256
|
+
}
|
|
257
|
+
if (res.status === 401) {
|
|
258
|
+
this.deps.tokens.clearCache();
|
|
259
|
+
throw new CanvaError(401, CODES.CANVA_ERROR, `Canva rejected the access token: ${message}`);
|
|
260
|
+
}
|
|
261
|
+
const passthrough = res.status === 403 || res.status === 404 || res.status === 429;
|
|
262
|
+
throw new CanvaError(passthrough ? res.status : 502, CODES.CANVA_ERROR, message);
|
|
263
|
+
}
|
|
264
|
+
if (!text)
|
|
265
|
+
return {};
|
|
266
|
+
try {
|
|
267
|
+
return JSON.parse(text);
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
270
|
+
throw new CanvaError(502, CODES.CANVA_ERROR, 'Canva returned a non-JSON response.');
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
//# sourceMappingURL=canva.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canva.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/canva/canva.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DocsService — Google Docs over the owner's Workspace grant.
|
|
3
|
+
*
|
|
4
|
+
* Reads any document the owner can see (`documents.readonly` /
|
|
5
|
+
* `drive.readonly`) and creates or appends to documents Crewly created
|
|
6
|
+
* (`drive.file`). Appending to a document the owner made elsewhere needs
|
|
7
|
+
* the `documents` scope, which the grant does not carry yet; Google then
|
|
8
|
+
* answers 403 and the error says so.
|
|
9
|
+
*
|
|
10
|
+
* @module services/google/docs.service
|
|
11
|
+
*/
|
|
12
|
+
import { type GoogleApiDeps } from './google-api.client.js';
|
|
13
|
+
/** A document, flattened. */
|
|
14
|
+
export interface DocText {
|
|
15
|
+
id: string;
|
|
16
|
+
title: string;
|
|
17
|
+
/** Plain text: headings prefixed with `#`, table cells joined with ` | `. */
|
|
18
|
+
text: string;
|
|
19
|
+
webViewLink: string;
|
|
20
|
+
}
|
|
21
|
+
/** Create input. */
|
|
22
|
+
export interface DocCreateInput {
|
|
23
|
+
title: string;
|
|
24
|
+
/** Initial body (plain text; blank lines make paragraphs). */
|
|
25
|
+
text?: string;
|
|
26
|
+
}
|
|
27
|
+
interface WireTextRun {
|
|
28
|
+
content?: string;
|
|
29
|
+
}
|
|
30
|
+
interface WireParagraph {
|
|
31
|
+
elements?: Array<{
|
|
32
|
+
textRun?: WireTextRun;
|
|
33
|
+
endIndex?: number;
|
|
34
|
+
}>;
|
|
35
|
+
paragraphStyle?: {
|
|
36
|
+
namedStyleType?: string;
|
|
37
|
+
};
|
|
38
|
+
bullet?: unknown;
|
|
39
|
+
}
|
|
40
|
+
interface WireStructuralElement {
|
|
41
|
+
endIndex?: number;
|
|
42
|
+
paragraph?: WireParagraph;
|
|
43
|
+
table?: {
|
|
44
|
+
tableRows?: Array<{
|
|
45
|
+
tableCells?: Array<{
|
|
46
|
+
content?: WireStructuralElement[];
|
|
47
|
+
}>;
|
|
48
|
+
}>;
|
|
49
|
+
};
|
|
50
|
+
sectionBreak?: unknown;
|
|
51
|
+
}
|
|
52
|
+
interface WireDocument {
|
|
53
|
+
documentId?: string;
|
|
54
|
+
title?: string;
|
|
55
|
+
body?: {
|
|
56
|
+
content?: WireStructuralElement[];
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Flatten a document body to plain text.
|
|
61
|
+
*
|
|
62
|
+
* @param content - `body.content`
|
|
63
|
+
* @returns Lines joined with `\n`
|
|
64
|
+
*/
|
|
65
|
+
export declare function flattenDocBody(content: WireStructuralElement[] | undefined): string;
|
|
66
|
+
/**
|
|
67
|
+
* The document's end index (where `insertText` appends).
|
|
68
|
+
*
|
|
69
|
+
* @param doc - Document
|
|
70
|
+
* @returns Index just before the final newline (Docs refuses inserts after it)
|
|
71
|
+
*/
|
|
72
|
+
export declare function docEndIndex(doc: WireDocument): number;
|
|
73
|
+
/**
|
|
74
|
+
* Docs: read, create, append.
|
|
75
|
+
*/
|
|
76
|
+
export declare class DocsService {
|
|
77
|
+
private readonly deps;
|
|
78
|
+
private readonly base;
|
|
79
|
+
/**
|
|
80
|
+
* @param deps - Token provider and optional fetch override
|
|
81
|
+
*/
|
|
82
|
+
constructor(deps: GoogleApiDeps);
|
|
83
|
+
/**
|
|
84
|
+
* `documents.get`, flattened to text.
|
|
85
|
+
*
|
|
86
|
+
* @param id - Document id
|
|
87
|
+
* @returns Title + text
|
|
88
|
+
*/
|
|
89
|
+
read(id: string): Promise<DocText>;
|
|
90
|
+
/**
|
|
91
|
+
* `documents.create` + one `insertText` for the body.
|
|
92
|
+
*
|
|
93
|
+
* @param input - Title and optional body
|
|
94
|
+
* @returns The new document (text as written)
|
|
95
|
+
* @throws GoogleWorkspaceError(400, validation) without a title
|
|
96
|
+
*/
|
|
97
|
+
create(input: DocCreateInput): Promise<DocText>;
|
|
98
|
+
/**
|
|
99
|
+
* Append text at the end of a document (`documents.get` for the end
|
|
100
|
+
* index, then `insertText`).
|
|
101
|
+
*
|
|
102
|
+
* @param id - Document id
|
|
103
|
+
* @param text - Text to append (a newline is prepended when the doc is not empty)
|
|
104
|
+
* @returns The updated document, flattened
|
|
105
|
+
* @throws GoogleWorkspaceError(400, validation) without text
|
|
106
|
+
*/
|
|
107
|
+
append(id: string, text: string): Promise<DocText>;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Browser link for a document.
|
|
111
|
+
*
|
|
112
|
+
* @param id - Document id
|
|
113
|
+
* @returns URL
|
|
114
|
+
*/
|
|
115
|
+
export declare function docLink(id: string): string;
|
|
116
|
+
export {};
|
|
117
|
+
//# sourceMappingURL=docs.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/google/docs.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAG3E,6BAA6B;AAC7B,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,oBAAoB;AACpB,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,UAAU,WAAW;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD,UAAU,aAAa;IACrB,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAE,OAAO,CAAC,EAAE,WAAW,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/D,cAAc,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AACD,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,KAAK,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,KAAK,CAAC;YAAE,UAAU,CAAC,EAAE,KAAK,CAAC;gBAAE,OAAO,CAAC,EAAE,qBAAqB,EAAE,CAAA;aAAE,CAAC,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC;IAC7F,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AACD,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,qBAAqB,EAAE,CAAA;KAAE,CAAC;CAC9C;AAyBD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,EAAE,GAAG,SAAS,GAAG,MAAM,CAanF;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAKrD;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA4C;IAEjE;;OAEG;gBACS,IAAI,EAAE,aAAa;IAI/B;;;;;OAKG;IACG,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMxC;;;;;;OAMG;IACG,MAAM,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;IAerD;;;;;;;;OAQG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAazD;AAOD;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE1C"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DocsService — Google Docs over the owner's Workspace grant.
|
|
3
|
+
*
|
|
4
|
+
* Reads any document the owner can see (`documents.readonly` /
|
|
5
|
+
* `drive.readonly`) and creates or appends to documents Crewly created
|
|
6
|
+
* (`drive.file`). Appending to a document the owner made elsewhere needs
|
|
7
|
+
* the `documents` scope, which the grant does not carry yet; Google then
|
|
8
|
+
* answers 403 and the error says so.
|
|
9
|
+
*
|
|
10
|
+
* @module services/google/docs.service
|
|
11
|
+
*/
|
|
12
|
+
import { GOOGLE_WORKSPACE_CONSTANTS } from '../../constants.js';
|
|
13
|
+
import { GoogleWorkspaceError } from './google-workspace-token.service.js';
|
|
14
|
+
import { googleRequest } from './google-api.client.js';
|
|
15
|
+
import { requireId } from './drive.service.js';
|
|
16
|
+
const HEADING_PREFIX = {
|
|
17
|
+
TITLE: '# ',
|
|
18
|
+
HEADING_1: '# ',
|
|
19
|
+
HEADING_2: '## ',
|
|
20
|
+
HEADING_3: '### ',
|
|
21
|
+
HEADING_4: '#### ',
|
|
22
|
+
HEADING_5: '##### ',
|
|
23
|
+
HEADING_6: '###### ',
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Flatten a paragraph to one line.
|
|
27
|
+
*
|
|
28
|
+
* @param p - Paragraph
|
|
29
|
+
* @returns Text without the trailing newline
|
|
30
|
+
*/
|
|
31
|
+
function paragraphText(p) {
|
|
32
|
+
const raw = (p.elements ?? []).map((e) => e.textRun?.content ?? '').join('');
|
|
33
|
+
const line = raw.replace(/\n$/, '');
|
|
34
|
+
const prefix = HEADING_PREFIX[p.paragraphStyle?.namedStyleType ?? ''] ?? (p.bullet ? '- ' : '');
|
|
35
|
+
return `${prefix}${line}`;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Flatten a document body to plain text.
|
|
39
|
+
*
|
|
40
|
+
* @param content - `body.content`
|
|
41
|
+
* @returns Lines joined with `\n`
|
|
42
|
+
*/
|
|
43
|
+
export function flattenDocBody(content) {
|
|
44
|
+
const lines = [];
|
|
45
|
+
for (const el of content ?? []) {
|
|
46
|
+
if (el.paragraph) {
|
|
47
|
+
lines.push(paragraphText(el.paragraph));
|
|
48
|
+
}
|
|
49
|
+
else if (el.table) {
|
|
50
|
+
for (const row of el.table.tableRows ?? []) {
|
|
51
|
+
const cells = (row.tableCells ?? []).map((cell) => flattenDocBody(cell.content).replace(/\n+/g, ' ').trim());
|
|
52
|
+
lines.push(cells.join(' | '));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return lines.join('\n').replace(/\n{3,}/g, '\n\n').trim();
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The document's end index (where `insertText` appends).
|
|
60
|
+
*
|
|
61
|
+
* @param doc - Document
|
|
62
|
+
* @returns Index just before the final newline (Docs refuses inserts after it)
|
|
63
|
+
*/
|
|
64
|
+
export function docEndIndex(doc) {
|
|
65
|
+
const content = doc.body?.content ?? [];
|
|
66
|
+
const last = content[content.length - 1];
|
|
67
|
+
const end = last?.endIndex ?? 1;
|
|
68
|
+
return Math.max(1, end - 1);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Docs: read, create, append.
|
|
72
|
+
*/
|
|
73
|
+
export class DocsService {
|
|
74
|
+
deps;
|
|
75
|
+
base = GOOGLE_WORKSPACE_CONSTANTS.DOCS_API_BASE;
|
|
76
|
+
/**
|
|
77
|
+
* @param deps - Token provider and optional fetch override
|
|
78
|
+
*/
|
|
79
|
+
constructor(deps) {
|
|
80
|
+
this.deps = deps;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* `documents.get`, flattened to text.
|
|
84
|
+
*
|
|
85
|
+
* @param id - Document id
|
|
86
|
+
* @returns Title + text
|
|
87
|
+
*/
|
|
88
|
+
async read(id) {
|
|
89
|
+
const documentId = requireId(id);
|
|
90
|
+
const doc = await googleRequest(this.deps, `${this.base}/documents/${encodeURIComponent(documentId)}`);
|
|
91
|
+
return toDocText(doc);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* `documents.create` + one `insertText` for the body.
|
|
95
|
+
*
|
|
96
|
+
* @param input - Title and optional body
|
|
97
|
+
* @returns The new document (text as written)
|
|
98
|
+
* @throws GoogleWorkspaceError(400, validation) without a title
|
|
99
|
+
*/
|
|
100
|
+
async create(input) {
|
|
101
|
+
const title = (input.title ?? '').trim();
|
|
102
|
+
if (!title)
|
|
103
|
+
throw new GoogleWorkspaceError(400, GOOGLE_WORKSPACE_CONSTANTS.ERROR_CODES.VALIDATION, '"title" is required');
|
|
104
|
+
const created = await googleRequest(this.deps, `${this.base}/documents`, { method: 'POST', body: { title } });
|
|
105
|
+
const documentId = created.documentId ?? '';
|
|
106
|
+
const text = (input.text ?? '').replace(/\r\n/g, '\n');
|
|
107
|
+
if (text.trim()) {
|
|
108
|
+
await googleRequest(this.deps, `${this.base}/documents/${encodeURIComponent(documentId)}:batchUpdate`, {
|
|
109
|
+
method: 'POST',
|
|
110
|
+
body: { requests: [{ insertText: { location: { index: 1 }, text } }] },
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
return { id: documentId, title: created.title ?? title, text, webViewLink: docLink(documentId) };
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Append text at the end of a document (`documents.get` for the end
|
|
117
|
+
* index, then `insertText`).
|
|
118
|
+
*
|
|
119
|
+
* @param id - Document id
|
|
120
|
+
* @param text - Text to append (a newline is prepended when the doc is not empty)
|
|
121
|
+
* @returns The updated document, flattened
|
|
122
|
+
* @throws GoogleWorkspaceError(400, validation) without text
|
|
123
|
+
*/
|
|
124
|
+
async append(id, text) {
|
|
125
|
+
const documentId = requireId(id);
|
|
126
|
+
const body = (text ?? '').replace(/\r\n/g, '\n');
|
|
127
|
+
if (!body.trim())
|
|
128
|
+
throw new GoogleWorkspaceError(400, GOOGLE_WORKSPACE_CONSTANTS.ERROR_CODES.VALIDATION, '"text" is required');
|
|
129
|
+
const doc = await googleRequest(this.deps, `${this.base}/documents/${encodeURIComponent(documentId)}`);
|
|
130
|
+
const index = docEndIndex(doc);
|
|
131
|
+
await googleRequest(this.deps, `${this.base}/documents/${encodeURIComponent(documentId)}:batchUpdate`, {
|
|
132
|
+
method: 'POST',
|
|
133
|
+
body: { requests: [{ insertText: { location: { index }, text: index > 1 ? `\n${body}` : body } }] },
|
|
134
|
+
});
|
|
135
|
+
const after = await googleRequest(this.deps, `${this.base}/documents/${encodeURIComponent(documentId)}`);
|
|
136
|
+
return toDocText(after);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function toDocText(doc) {
|
|
140
|
+
const id = doc.documentId ?? '';
|
|
141
|
+
return { id, title: doc.title ?? '', text: flattenDocBody(doc.body?.content), webViewLink: docLink(id) };
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Browser link for a document.
|
|
145
|
+
*
|
|
146
|
+
* @param id - Document id
|
|
147
|
+
* @returns URL
|
|
148
|
+
*/
|
|
149
|
+
export function docLink(id) {
|
|
150
|
+
return `https://docs.google.com/document/d/${id}/edit`;
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=docs.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/google/docs.service.ts"],"names":[],"mappings":"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"}
|