crewly 1.20.29 → 1.20.30

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 (98) hide show
  1. package/config/skills/agent/core/canva-create/SKILL.md +53 -0
  2. package/config/skills/agent/core/canva-create/execute.sh +88 -0
  3. package/config/skills/agent/core/canva-create/execute.test.sh +54 -0
  4. package/config/skills/agent/core/canva-designs/SKILL.md +51 -0
  5. package/config/skills/agent/core/canva-designs/execute.sh +96 -0
  6. package/config/skills/agent/core/canva-designs/execute.test.sh +54 -0
  7. package/config/skills/agent/core/canva-export/SKILL.md +52 -0
  8. package/config/skills/agent/core/canva-export/execute.sh +111 -0
  9. package/config/skills/agent/core/canva-export/execute.test.sh +55 -0
  10. package/config/skills/agent/core/canva-upload/SKILL.md +49 -0
  11. package/config/skills/agent/core/canva-upload/execute.sh +72 -0
  12. package/config/skills/agent/core/canva-upload/execute.test.sh +54 -0
  13. package/config/skills/agent/core/docs-read/SKILL.md +50 -0
  14. package/config/skills/agent/core/docs-read/execute.sh +68 -0
  15. package/config/skills/agent/core/docs-read/execute.test.sh +52 -0
  16. package/config/skills/agent/core/docs-write/SKILL.md +55 -0
  17. package/config/skills/agent/core/docs-write/execute.sh +90 -0
  18. package/config/skills/agent/core/docs-write/execute.test.sh +54 -0
  19. package/config/skills/agent/core/drive-read/SKILL.md +53 -0
  20. package/config/skills/agent/core/drive-read/execute.sh +79 -0
  21. package/config/skills/agent/core/drive-read/execute.test.sh +55 -0
  22. package/config/skills/agent/core/drive-search/SKILL.md +55 -0
  23. package/config/skills/agent/core/drive-search/execute.sh +87 -0
  24. package/config/skills/agent/core/drive-search/execute.test.sh +54 -0
  25. package/config/skills/agent/core/drive-upload/SKILL.md +54 -0
  26. package/config/skills/agent/core/drive-upload/execute.sh +117 -0
  27. package/config/skills/agent/core/drive-upload/execute.test.sh +57 -0
  28. package/config/skills/agent/core/sheets-read/SKILL.md +53 -0
  29. package/config/skills/agent/core/sheets-read/execute.sh +81 -0
  30. package/config/skills/agent/core/sheets-read/execute.test.sh +52 -0
  31. package/config/skills/agent/core/sheets-write/SKILL.md +56 -0
  32. package/config/skills/agent/core/sheets-write/execute.sh +103 -0
  33. package/config/skills/agent/core/sheets-write/execute.test.sh +57 -0
  34. package/config/skills/agent/core/slides-create/SKILL.md +61 -0
  35. package/config/skills/agent/core/slides-create/execute.sh +92 -0
  36. package/config/skills/agent/core/slides-create/execute.test.sh +54 -0
  37. package/config/skills/agent/core/slides-read/SKILL.md +49 -0
  38. package/config/skills/agent/core/slides-read/execute.sh +67 -0
  39. package/config/skills/agent/core/slides-read/execute.test.sh +50 -0
  40. package/dist/backend/backend/src/constants.d.ts +69 -0
  41. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  42. package/dist/backend/backend/src/constants.js +73 -0
  43. package/dist/backend/backend/src/constants.js.map +1 -1
  44. package/dist/backend/backend/src/controllers/canva/canva.controller.d.ts +48 -0
  45. package/dist/backend/backend/src/controllers/canva/canva.controller.d.ts.map +1 -0
  46. package/dist/backend/backend/src/controllers/canva/canva.controller.js +183 -0
  47. package/dist/backend/backend/src/controllers/canva/canva.controller.js.map +1 -0
  48. package/dist/backend/backend/src/controllers/canva/canva.routes.d.ts +22 -0
  49. package/dist/backend/backend/src/controllers/canva/canva.routes.d.ts.map +1 -0
  50. package/dist/backend/backend/src/controllers/canva/canva.routes.js +34 -0
  51. package/dist/backend/backend/src/controllers/canva/canva.routes.js.map +1 -0
  52. package/dist/backend/backend/src/controllers/google/google.controller.d.ts +100 -0
  53. package/dist/backend/backend/src/controllers/google/google.controller.d.ts.map +1 -1
  54. package/dist/backend/backend/src/controllers/google/google.controller.js +237 -1
  55. package/dist/backend/backend/src/controllers/google/google.controller.js.map +1 -1
  56. package/dist/backend/backend/src/controllers/google/google.routes.d.ts +13 -0
  57. package/dist/backend/backend/src/controllers/google/google.routes.d.ts.map +1 -1
  58. package/dist/backend/backend/src/controllers/google/google.routes.js +27 -1
  59. package/dist/backend/backend/src/controllers/google/google.routes.js.map +1 -1
  60. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  61. package/dist/backend/backend/src/routes/api.routes.js +3 -0
  62. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  63. package/dist/backend/backend/src/services/canva/canva-token.service.d.ts +98 -0
  64. package/dist/backend/backend/src/services/canva/canva-token.service.d.ts.map +1 -0
  65. package/dist/backend/backend/src/services/canva/canva-token.service.js +198 -0
  66. package/dist/backend/backend/src/services/canva/canva-token.service.js.map +1 -0
  67. package/dist/backend/backend/src/services/canva/canva.service.d.ts +184 -0
  68. package/dist/backend/backend/src/services/canva/canva.service.d.ts.map +1 -0
  69. package/dist/backend/backend/src/services/canva/canva.service.js +274 -0
  70. package/dist/backend/backend/src/services/canva/canva.service.js.map +1 -0
  71. package/dist/backend/backend/src/services/google/docs.service.d.ts +117 -0
  72. package/dist/backend/backend/src/services/google/docs.service.d.ts.map +1 -0
  73. package/dist/backend/backend/src/services/google/docs.service.js +152 -0
  74. package/dist/backend/backend/src/services/google/docs.service.js.map +1 -0
  75. package/dist/backend/backend/src/services/google/drive.service.d.ts +157 -0
  76. package/dist/backend/backend/src/services/google/drive.service.d.ts.map +1 -0
  77. package/dist/backend/backend/src/services/google/drive.service.js +203 -0
  78. package/dist/backend/backend/src/services/google/drive.service.js.map +1 -0
  79. package/dist/backend/backend/src/services/google/google-api.client.d.ts +15 -7
  80. package/dist/backend/backend/src/services/google/google-api.client.d.ts.map +1 -1
  81. package/dist/backend/backend/src/services/google/google-api.client.js +13 -6
  82. package/dist/backend/backend/src/services/google/google-api.client.js.map +1 -1
  83. package/dist/backend/backend/src/services/google/sheets.service.d.ts +118 -0
  84. package/dist/backend/backend/src/services/google/sheets.service.d.ts.map +1 -0
  85. package/dist/backend/backend/src/services/google/sheets.service.js +158 -0
  86. package/dist/backend/backend/src/services/google/sheets.service.js.map +1 -0
  87. package/dist/backend/backend/src/services/google/slides.service.d.ts +136 -0
  88. package/dist/backend/backend/src/services/google/slides.service.d.ts.map +1 -0
  89. package/dist/backend/backend/src/services/google/slides.service.js +153 -0
  90. package/dist/backend/backend/src/services/google/slides.service.js.map +1 -0
  91. package/dist/backend/build-info.json +2 -2
  92. package/dist/cli/backend/src/constants.d.ts +69 -0
  93. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  94. package/dist/cli/backend/src/constants.js +73 -0
  95. package/dist/cli/backend/src/constants.js.map +1 -1
  96. package/frontend/dist/assets/{index-d1bd0dec.js → index-96b51cd9.js} +243 -243
  97. package/frontend/dist/index.html +1 -1
  98. package/package.json +1 -1
@@ -0,0 +1,184 @@
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
+ /** Token provider slice. */
14
+ export interface CanvaTokenProvider {
15
+ getAccessToken(): Promise<string>;
16
+ clearCache(): void;
17
+ }
18
+ /** Service dependencies. */
19
+ export interface CanvaApiDeps {
20
+ tokens: CanvaTokenProvider;
21
+ fetchImpl?: typeof fetch;
22
+ /** Sleep between job polls (injectable for tests). */
23
+ sleep?: (ms: number) => Promise<void>;
24
+ now?: () => number;
25
+ }
26
+ /** A design, trimmed. */
27
+ export interface CanvaDesign {
28
+ id: string;
29
+ title: string;
30
+ editUrl?: string;
31
+ viewUrl?: string;
32
+ thumbnailUrl?: string;
33
+ pageCount?: number;
34
+ createdAt?: string;
35
+ updatedAt?: string;
36
+ }
37
+ /** List input. */
38
+ export interface CanvaListInput {
39
+ query?: string;
40
+ ownership?: 'any' | 'owned' | 'shared';
41
+ sortBy?: 'relevance' | 'modified_descending' | 'modified_ascending' | 'title_descending' | 'title_ascending';
42
+ limit?: number;
43
+ continuation?: string;
44
+ }
45
+ /** Create input. */
46
+ export interface CanvaCreateInput {
47
+ title?: string;
48
+ /** `doc` | `whiteboard` | `presentation` */
49
+ preset?: string;
50
+ /** Custom size in px (40–8000) */
51
+ width?: number;
52
+ height?: number;
53
+ /** Start from an uploaded asset (image) */
54
+ assetId?: string;
55
+ }
56
+ /** Export input. */
57
+ export interface CanvaExportInput {
58
+ designId: string;
59
+ format: string;
60
+ /** JPG quality 1–100 (default 80) */
61
+ quality?: number;
62
+ /** MP4 quality preset, e.g. `horizontal_1080p` (default) */
63
+ videoQuality?: string;
64
+ /** Page numbers (1-based) */
65
+ pages?: number[];
66
+ }
67
+ /** Export result. */
68
+ export interface CanvaExport {
69
+ jobId: string;
70
+ status: 'success' | 'failed' | 'in_progress';
71
+ /** Download URLs (short-lived), one per file */
72
+ urls: string[];
73
+ error?: {
74
+ code?: string;
75
+ message?: string;
76
+ };
77
+ }
78
+ /** An uploaded asset. */
79
+ export interface CanvaAsset {
80
+ id: string;
81
+ name: string;
82
+ thumbnailUrl?: string;
83
+ createdAt?: string;
84
+ }
85
+ interface WireDesign {
86
+ id?: string;
87
+ title?: string;
88
+ urls?: {
89
+ edit_url?: string;
90
+ view_url?: string;
91
+ };
92
+ thumbnail?: {
93
+ url?: string;
94
+ };
95
+ page_count?: number;
96
+ created_at?: number;
97
+ updated_at?: number;
98
+ }
99
+ /**
100
+ * Trim a Canva design resource.
101
+ *
102
+ * @param d - Wire design
103
+ * @returns Trimmed
104
+ */
105
+ export declare function toDesign(d: WireDesign): CanvaDesign;
106
+ /**
107
+ * The `format` object for an export job.
108
+ *
109
+ * @param input - Export input
110
+ * @returns Canva format object
111
+ * @throws CanvaError(400, validation) for an unknown format / bad quality
112
+ */
113
+ export declare function buildExportFormat(input: CanvaExportInput): Record<string, unknown>;
114
+ /**
115
+ * Canva Connect calls.
116
+ */
117
+ export declare class CanvaService {
118
+ private readonly deps;
119
+ private readonly base;
120
+ /**
121
+ * @param deps - Token provider, fetch, sleep
122
+ */
123
+ constructor(deps: CanvaApiDeps);
124
+ /**
125
+ * `GET /designs` — search / list.
126
+ *
127
+ * @param input - Query, ownership, sort, limit, continuation
128
+ * @returns Designs + continuation token
129
+ */
130
+ listDesigns(input?: CanvaListInput): Promise<{
131
+ designs: CanvaDesign[];
132
+ continuation?: string;
133
+ }>;
134
+ /**
135
+ * `GET /designs/:id`.
136
+ *
137
+ * @param id - Design id
138
+ * @returns The design
139
+ */
140
+ getDesign(id: string): Promise<CanvaDesign>;
141
+ /**
142
+ * `POST /designs` — a new design from a preset type, a custom size, or an asset.
143
+ *
144
+ * @param input - Title + type/size/asset
145
+ * @returns The new design (with editUrl)
146
+ * @throws CanvaError(400, validation) when neither a valid preset, size nor asset is given
147
+ */
148
+ createDesign(input: CanvaCreateInput): Promise<CanvaDesign>;
149
+ /**
150
+ * `POST /exports` then poll `GET /exports/:id` until done.
151
+ *
152
+ * @param input - Design, format, options
153
+ * @returns Download URLs (or the failure)
154
+ */
155
+ exportDesign(input: CanvaExportInput): Promise<CanvaExport>;
156
+ /**
157
+ * `POST /asset-uploads` (binary body) then poll `GET /asset-uploads/:id`.
158
+ *
159
+ * @param name - Asset name (≤ 50 chars)
160
+ * @param bytes - File content
161
+ * @returns The asset
162
+ * @throws CanvaError(400, validation) for an empty/oversized file; 502 when the job fails
163
+ */
164
+ uploadAsset(name: string, bytes: Buffer): Promise<CanvaAsset>;
165
+ /**
166
+ * Poll a job until it leaves `in_progress` or the ceiling passes.
167
+ *
168
+ * @param url - Job URL
169
+ * @param first - The job as returned by the create call
170
+ * @returns The final job
171
+ */
172
+ private pollJob;
173
+ /**
174
+ * Authenticated call; 401 drops the cached token, 403/404/429 pass
175
+ * through, other failures fold into 502.
176
+ *
177
+ * @param url - Absolute URL
178
+ * @param init - Method / body / headers
179
+ * @returns Parsed JSON
180
+ */
181
+ private request;
182
+ }
183
+ export {};
184
+ //# sourceMappingURL=canva.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canva.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/canva/canva.service.ts"],"names":[],"mappings":"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"}
@@ -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"}