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,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DriveService — Google Drive over the owner's Workspace grant.
|
|
3
|
+
*
|
|
4
|
+
* Works within the scopes the grant already carries: `drive.readonly`
|
|
5
|
+
* (search, metadata, download / export of anything the owner can see) and
|
|
6
|
+
* `drive.file` (upload; the created files are then editable by Crewly).
|
|
7
|
+
* Google-native files (Docs / Sheets / Slides) are read through `export`
|
|
8
|
+
* as text / CSV so an agent gets something it can reason about.
|
|
9
|
+
*
|
|
10
|
+
* @module services/google/drive.service
|
|
11
|
+
*/
|
|
12
|
+
import { type GoogleApiDeps } from './google-api.client.js';
|
|
13
|
+
/** Drive file metadata (the fields Crewly asks for). */
|
|
14
|
+
export interface DriveFile {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
mimeType: string;
|
|
18
|
+
modifiedTime?: string;
|
|
19
|
+
size?: number;
|
|
20
|
+
webViewLink?: string;
|
|
21
|
+
owners?: string[];
|
|
22
|
+
parents?: string[];
|
|
23
|
+
}
|
|
24
|
+
/** Search input. */
|
|
25
|
+
export interface DriveSearchInput {
|
|
26
|
+
/** Free text; matched against name and full text. Empty = most recent files. */
|
|
27
|
+
query?: string;
|
|
28
|
+
/** Restrict to a MIME type (e.g. `application/vnd.google-apps.spreadsheet`). */
|
|
29
|
+
mimeType?: string;
|
|
30
|
+
/** Restrict to a folder id. */
|
|
31
|
+
folderId?: string;
|
|
32
|
+
max?: number;
|
|
33
|
+
}
|
|
34
|
+
/** What `readContent` returns. */
|
|
35
|
+
export interface DriveContent {
|
|
36
|
+
file: DriveFile;
|
|
37
|
+
/** MIME type of `content` (`text/plain`, `text/csv`, or the file's own). */
|
|
38
|
+
contentType: string;
|
|
39
|
+
/** UTF-8 text for text-like files; base64 for binary files. */
|
|
40
|
+
content: string;
|
|
41
|
+
encoding: 'utf8' | 'base64';
|
|
42
|
+
bytes: number;
|
|
43
|
+
}
|
|
44
|
+
/** Upload input. */
|
|
45
|
+
export interface DriveUploadInput {
|
|
46
|
+
name: string;
|
|
47
|
+
mimeType?: string;
|
|
48
|
+
/** UTF-8 text, or base64 when `encoding` is `base64`. */
|
|
49
|
+
content: string;
|
|
50
|
+
encoding?: 'utf8' | 'base64';
|
|
51
|
+
folderId?: string;
|
|
52
|
+
/** Convert to the Google-native type (`application/vnd.google-apps.document` …) on upload. */
|
|
53
|
+
convertTo?: string;
|
|
54
|
+
}
|
|
55
|
+
interface DriveWireFile {
|
|
56
|
+
id?: string;
|
|
57
|
+
name?: string;
|
|
58
|
+
mimeType?: string;
|
|
59
|
+
modifiedTime?: string;
|
|
60
|
+
size?: string;
|
|
61
|
+
webViewLink?: string;
|
|
62
|
+
owners?: Array<{
|
|
63
|
+
emailAddress?: string;
|
|
64
|
+
}>;
|
|
65
|
+
parents?: string[];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Trim a Drive file resource to {@link DriveFile}.
|
|
69
|
+
*
|
|
70
|
+
* @param wire - Google's file resource
|
|
71
|
+
* @returns The trimmed file
|
|
72
|
+
*/
|
|
73
|
+
export declare function toDriveFile(wire: DriveWireFile): DriveFile;
|
|
74
|
+
/**
|
|
75
|
+
* Escape a value for a Drive `q` string literal.
|
|
76
|
+
*
|
|
77
|
+
* @param value - Raw text
|
|
78
|
+
* @returns Escaped text (backslashes and single quotes)
|
|
79
|
+
*/
|
|
80
|
+
export declare function escapeDriveQuery(value: string): string;
|
|
81
|
+
/**
|
|
82
|
+
* Build the Drive `q` expression for a search.
|
|
83
|
+
*
|
|
84
|
+
* @param input - Search input
|
|
85
|
+
* @returns The `q` string
|
|
86
|
+
*/
|
|
87
|
+
export declare function buildDriveQuery(input: DriveSearchInput): string;
|
|
88
|
+
/**
|
|
89
|
+
* Whether a MIME type is something an agent can read as text.
|
|
90
|
+
*
|
|
91
|
+
* @param mimeType - MIME type
|
|
92
|
+
* @returns True for text/*, JSON, XML, CSV and friends
|
|
93
|
+
*/
|
|
94
|
+
export declare function isTextMime(mimeType: string): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Drive: search, metadata, content, upload.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* const drive = new DriveService({ tokens });
|
|
101
|
+
* const hits = await drive.search({ query: 'Q3 plan' });
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export declare class DriveService {
|
|
105
|
+
private readonly deps;
|
|
106
|
+
private readonly base;
|
|
107
|
+
private readonly uploadBase;
|
|
108
|
+
/**
|
|
109
|
+
* @param deps - Token provider and optional fetch override
|
|
110
|
+
*/
|
|
111
|
+
constructor(deps: GoogleApiDeps);
|
|
112
|
+
/**
|
|
113
|
+
* `files.list` — most recently modified first.
|
|
114
|
+
*
|
|
115
|
+
* @param input - Query / MIME / folder / cap
|
|
116
|
+
* @returns Matching files
|
|
117
|
+
* @throws GoogleWorkspaceError on auth / Google failures
|
|
118
|
+
*/
|
|
119
|
+
search(input?: DriveSearchInput): Promise<DriveFile[]>;
|
|
120
|
+
/**
|
|
121
|
+
* `files.get` metadata.
|
|
122
|
+
*
|
|
123
|
+
* @param id - File id
|
|
124
|
+
* @returns The file
|
|
125
|
+
* @throws GoogleWorkspaceError(400, validation) without an id; Google 404 passes through
|
|
126
|
+
*/
|
|
127
|
+
get(id: string): Promise<DriveFile>;
|
|
128
|
+
/**
|
|
129
|
+
* File content: Google-native types are exported (Docs → text/plain,
|
|
130
|
+
* Sheets → text/csv, Slides → text/plain); other files are downloaded and
|
|
131
|
+
* returned as UTF-8 when text-like, else base64.
|
|
132
|
+
*
|
|
133
|
+
* @param id - File id
|
|
134
|
+
* @returns Content with its type and encoding
|
|
135
|
+
* @throws GoogleWorkspaceError(413, validation) when the file exceeds DRIVE_MAX_CONTENT_BYTES
|
|
136
|
+
*/
|
|
137
|
+
readContent(id: string): Promise<DriveContent>;
|
|
138
|
+
/**
|
|
139
|
+
* Multipart `files.create` — a new file in My Drive (or a folder),
|
|
140
|
+
* optionally converted to a Google-native type.
|
|
141
|
+
*
|
|
142
|
+
* @param input - Name, MIME, content, folder, conversion
|
|
143
|
+
* @returns The created file
|
|
144
|
+
* @throws GoogleWorkspaceError(400, validation) for a missing name/content or oversized content
|
|
145
|
+
*/
|
|
146
|
+
upload(input: DriveUploadInput): Promise<DriveFile>;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Validate a file / document id.
|
|
150
|
+
*
|
|
151
|
+
* @param id - Candidate id
|
|
152
|
+
* @returns The trimmed id
|
|
153
|
+
* @throws GoogleWorkspaceError(400, validation) when empty
|
|
154
|
+
*/
|
|
155
|
+
export declare function requireId(id: string | undefined): string;
|
|
156
|
+
export {};
|
|
157
|
+
//# sourceMappingURL=drive.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drive.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/google/drive.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DriveService — Google Drive over the owner's Workspace grant.
|
|
3
|
+
*
|
|
4
|
+
* Works within the scopes the grant already carries: `drive.readonly`
|
|
5
|
+
* (search, metadata, download / export of anything the owner can see) and
|
|
6
|
+
* `drive.file` (upload; the created files are then editable by Crewly).
|
|
7
|
+
* Google-native files (Docs / Sheets / Slides) are read through `export`
|
|
8
|
+
* as text / CSV so an agent gets something it can reason about.
|
|
9
|
+
*
|
|
10
|
+
* @module services/google/drive.service
|
|
11
|
+
*/
|
|
12
|
+
import { randomBytes } from 'crypto';
|
|
13
|
+
import { GOOGLE_WORKSPACE_CONSTANTS } from '../../constants.js';
|
|
14
|
+
import { GoogleWorkspaceError } from './google-workspace-token.service.js';
|
|
15
|
+
import { buildGoogleUrl, googleRequest } from './google-api.client.js';
|
|
16
|
+
import { clampMax } from './gmail.service.js';
|
|
17
|
+
const FILE_FIELDS = 'id,name,mimeType,modifiedTime,size,webViewLink,owners(emailAddress),parents';
|
|
18
|
+
/**
|
|
19
|
+
* Trim a Drive file resource to {@link DriveFile}.
|
|
20
|
+
*
|
|
21
|
+
* @param wire - Google's file resource
|
|
22
|
+
* @returns The trimmed file
|
|
23
|
+
*/
|
|
24
|
+
export function toDriveFile(wire) {
|
|
25
|
+
return {
|
|
26
|
+
id: wire.id ?? '',
|
|
27
|
+
name: wire.name ?? '',
|
|
28
|
+
mimeType: wire.mimeType ?? '',
|
|
29
|
+
...(wire.modifiedTime ? { modifiedTime: wire.modifiedTime } : {}),
|
|
30
|
+
...(wire.size ? { size: Number(wire.size) } : {}),
|
|
31
|
+
...(wire.webViewLink ? { webViewLink: wire.webViewLink } : {}),
|
|
32
|
+
...(wire.owners?.length ? { owners: wire.owners.map((o) => o.emailAddress ?? '').filter(Boolean) } : {}),
|
|
33
|
+
...(wire.parents?.length ? { parents: wire.parents } : {}),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Escape a value for a Drive `q` string literal.
|
|
38
|
+
*
|
|
39
|
+
* @param value - Raw text
|
|
40
|
+
* @returns Escaped text (backslashes and single quotes)
|
|
41
|
+
*/
|
|
42
|
+
export function escapeDriveQuery(value) {
|
|
43
|
+
return value.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Build the Drive `q` expression for a search.
|
|
47
|
+
*
|
|
48
|
+
* @param input - Search input
|
|
49
|
+
* @returns The `q` string
|
|
50
|
+
*/
|
|
51
|
+
export function buildDriveQuery(input) {
|
|
52
|
+
const terms = ['trashed = false'];
|
|
53
|
+
const text = (input.query ?? '').trim();
|
|
54
|
+
if (text) {
|
|
55
|
+
const escaped = escapeDriveQuery(text);
|
|
56
|
+
terms.push(`(name contains '${escaped}' or fullText contains '${escaped}')`);
|
|
57
|
+
}
|
|
58
|
+
if (input.mimeType?.trim())
|
|
59
|
+
terms.push(`mimeType = '${escapeDriveQuery(input.mimeType.trim())}'`);
|
|
60
|
+
if (input.folderId?.trim())
|
|
61
|
+
terms.push(`'${escapeDriveQuery(input.folderId.trim())}' in parents`);
|
|
62
|
+
return terms.join(' and ');
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Whether a MIME type is something an agent can read as text.
|
|
66
|
+
*
|
|
67
|
+
* @param mimeType - MIME type
|
|
68
|
+
* @returns True for text/*, JSON, XML, CSV and friends
|
|
69
|
+
*/
|
|
70
|
+
export function isTextMime(mimeType) {
|
|
71
|
+
return /^text\//.test(mimeType) || /\b(json|xml|csv|javascript|yaml|markdown)\b/.test(mimeType);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Drive: search, metadata, content, upload.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* const drive = new DriveService({ tokens });
|
|
79
|
+
* const hits = await drive.search({ query: 'Q3 plan' });
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export class DriveService {
|
|
83
|
+
deps;
|
|
84
|
+
base = GOOGLE_WORKSPACE_CONSTANTS.DRIVE_API_BASE;
|
|
85
|
+
uploadBase = GOOGLE_WORKSPACE_CONSTANTS.DRIVE_UPLOAD_BASE;
|
|
86
|
+
/**
|
|
87
|
+
* @param deps - Token provider and optional fetch override
|
|
88
|
+
*/
|
|
89
|
+
constructor(deps) {
|
|
90
|
+
this.deps = deps;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* `files.list` — most recently modified first.
|
|
94
|
+
*
|
|
95
|
+
* @param input - Query / MIME / folder / cap
|
|
96
|
+
* @returns Matching files
|
|
97
|
+
* @throws GoogleWorkspaceError on auth / Google failures
|
|
98
|
+
*/
|
|
99
|
+
async search(input = {}) {
|
|
100
|
+
const max = clampMax(input.max, GOOGLE_WORKSPACE_CONSTANTS.DRIVE_DEFAULT_MAX_RESULTS, GOOGLE_WORKSPACE_CONSTANTS.DRIVE_MAX_RESULTS_CEILING);
|
|
101
|
+
const data = await googleRequest(this.deps, buildGoogleUrl(`${this.base}/files`, {
|
|
102
|
+
q: buildDriveQuery(input),
|
|
103
|
+
pageSize: max,
|
|
104
|
+
orderBy: 'modifiedTime desc',
|
|
105
|
+
fields: `files(${FILE_FIELDS})`,
|
|
106
|
+
supportsAllDrives: 'true',
|
|
107
|
+
includeItemsFromAllDrives: 'true',
|
|
108
|
+
}));
|
|
109
|
+
return (data.files ?? []).map(toDriveFile);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* `files.get` metadata.
|
|
113
|
+
*
|
|
114
|
+
* @param id - File id
|
|
115
|
+
* @returns The file
|
|
116
|
+
* @throws GoogleWorkspaceError(400, validation) without an id; Google 404 passes through
|
|
117
|
+
*/
|
|
118
|
+
async get(id) {
|
|
119
|
+
const fileId = requireId(id);
|
|
120
|
+
const wire = await googleRequest(this.deps, buildGoogleUrl(`${this.base}/files/${encodeURIComponent(fileId)}`, { fields: FILE_FIELDS, supportsAllDrives: 'true' }));
|
|
121
|
+
return toDriveFile(wire);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* File content: Google-native types are exported (Docs → text/plain,
|
|
125
|
+
* Sheets → text/csv, Slides → text/plain); other files are downloaded and
|
|
126
|
+
* returned as UTF-8 when text-like, else base64.
|
|
127
|
+
*
|
|
128
|
+
* @param id - File id
|
|
129
|
+
* @returns Content with its type and encoding
|
|
130
|
+
* @throws GoogleWorkspaceError(413, validation) when the file exceeds DRIVE_MAX_CONTENT_BYTES
|
|
131
|
+
*/
|
|
132
|
+
async readContent(id) {
|
|
133
|
+
const file = await this.get(id);
|
|
134
|
+
const exportMime = GOOGLE_WORKSPACE_CONSTANTS.DRIVE_EXPORT_MIME[file.mimeType];
|
|
135
|
+
if (exportMime) {
|
|
136
|
+
const text = await googleRequest(this.deps, buildGoogleUrl(`${this.base}/files/${encodeURIComponent(file.id)}/export`, { mimeType: exportMime }), { responseType: 'text' });
|
|
137
|
+
return { file, contentType: exportMime, content: text, encoding: 'utf8', bytes: Buffer.byteLength(text, 'utf8') };
|
|
138
|
+
}
|
|
139
|
+
if (file.mimeType.startsWith('application/vnd.google-apps.')) {
|
|
140
|
+
throw new GoogleWorkspaceError(400, GOOGLE_WORKSPACE_CONSTANTS.ERROR_CODES.VALIDATION, `Cannot read a ${file.mimeType} as text`);
|
|
141
|
+
}
|
|
142
|
+
if ((file.size ?? 0) > GOOGLE_WORKSPACE_CONSTANTS.DRIVE_MAX_CONTENT_BYTES) {
|
|
143
|
+
throw new GoogleWorkspaceError(413, GOOGLE_WORKSPACE_CONSTANTS.ERROR_CODES.VALIDATION, `File is larger than ${GOOGLE_WORKSPACE_CONSTANTS.DRIVE_MAX_CONTENT_BYTES} bytes; open it via webViewLink instead`);
|
|
144
|
+
}
|
|
145
|
+
const raw = await googleRequest(this.deps, buildGoogleUrl(`${this.base}/files/${encodeURIComponent(file.id)}`, { alt: 'media', supportsAllDrives: 'true' }), { responseType: 'text' });
|
|
146
|
+
if (isTextMime(file.mimeType)) {
|
|
147
|
+
return { file, contentType: file.mimeType, content: raw, encoding: 'utf8', bytes: Buffer.byteLength(raw, 'utf8') };
|
|
148
|
+
}
|
|
149
|
+
// fetch's text() decoded as UTF-8; re-encode as latin1 to recover the bytes for small binaries.
|
|
150
|
+
const buf = Buffer.from(raw, 'latin1');
|
|
151
|
+
return { file, contentType: file.mimeType, content: buf.toString('base64'), encoding: 'base64', bytes: buf.length };
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Multipart `files.create` — a new file in My Drive (or a folder),
|
|
155
|
+
* optionally converted to a Google-native type.
|
|
156
|
+
*
|
|
157
|
+
* @param input - Name, MIME, content, folder, conversion
|
|
158
|
+
* @returns The created file
|
|
159
|
+
* @throws GoogleWorkspaceError(400, validation) for a missing name/content or oversized content
|
|
160
|
+
*/
|
|
161
|
+
async upload(input) {
|
|
162
|
+
const CODES = GOOGLE_WORKSPACE_CONSTANTS.ERROR_CODES;
|
|
163
|
+
const name = (input.name ?? '').trim();
|
|
164
|
+
if (!name)
|
|
165
|
+
throw new GoogleWorkspaceError(400, CODES.VALIDATION, '"name" is required');
|
|
166
|
+
if (typeof input.content !== 'string' || input.content.length === 0) {
|
|
167
|
+
throw new GoogleWorkspaceError(400, CODES.VALIDATION, '"content" is required');
|
|
168
|
+
}
|
|
169
|
+
const bytes = input.encoding === 'base64' ? Buffer.from(input.content, 'base64') : Buffer.from(input.content, 'utf8');
|
|
170
|
+
if (bytes.length > GOOGLE_WORKSPACE_CONSTANTS.DRIVE_MAX_CONTENT_BYTES) {
|
|
171
|
+
throw new GoogleWorkspaceError(400, CODES.VALIDATION, `content exceeds ${GOOGLE_WORKSPACE_CONSTANTS.DRIVE_MAX_CONTENT_BYTES} bytes`);
|
|
172
|
+
}
|
|
173
|
+
const mimeType = input.mimeType?.trim() || (input.encoding === 'base64' ? 'application/octet-stream' : 'text/plain');
|
|
174
|
+
const metadata = { name };
|
|
175
|
+
if (input.convertTo?.trim())
|
|
176
|
+
metadata.mimeType = input.convertTo.trim();
|
|
177
|
+
if (input.folderId?.trim())
|
|
178
|
+
metadata.parents = [input.folderId.trim()];
|
|
179
|
+
const boundary = `crewly-${randomBytes(12).toString('hex')}`;
|
|
180
|
+
const body = Buffer.concat([
|
|
181
|
+
Buffer.from(`--${boundary}\r\nContent-Type: application/json; charset=UTF-8\r\n\r\n${JSON.stringify(metadata)}\r\n`, 'utf8'),
|
|
182
|
+
Buffer.from(`--${boundary}\r\nContent-Type: ${mimeType}\r\n\r\n`, 'utf8'),
|
|
183
|
+
bytes,
|
|
184
|
+
Buffer.from(`\r\n--${boundary}--`, 'utf8'),
|
|
185
|
+
]);
|
|
186
|
+
const wire = await googleRequest(this.deps, buildGoogleUrl(`${this.uploadBase}/files`, { uploadType: 'multipart', fields: FILE_FIELDS, supportsAllDrives: 'true' }), { method: 'POST', rawBody: body, contentType: `multipart/related; boundary=${boundary}` });
|
|
187
|
+
return toDriveFile(wire);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Validate a file / document id.
|
|
192
|
+
*
|
|
193
|
+
* @param id - Candidate id
|
|
194
|
+
* @returns The trimmed id
|
|
195
|
+
* @throws GoogleWorkspaceError(400, validation) when empty
|
|
196
|
+
*/
|
|
197
|
+
export function requireId(id) {
|
|
198
|
+
const value = (id ?? '').trim();
|
|
199
|
+
if (!value)
|
|
200
|
+
throw new GoogleWorkspaceError(400, GOOGLE_WORKSPACE_CONSTANTS.ERROR_CODES.VALIDATION, '"id" is required');
|
|
201
|
+
return value;
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=drive.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drive.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/google/drive.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -26,19 +26,27 @@ export interface GoogleApiDeps {
|
|
|
26
26
|
* @returns The full URL string
|
|
27
27
|
*/
|
|
28
28
|
export declare function buildGoogleUrl(base: string, params?: Record<string, string | number | string[] | undefined>): string;
|
|
29
|
+
/** Request options for {@link googleRequest}. */
|
|
30
|
+
export interface GoogleRequestInit {
|
|
31
|
+
method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
32
|
+
/** JSON body (serialised, `Content-Type: application/json`). */
|
|
33
|
+
body?: unknown;
|
|
34
|
+
/** Pre-encoded body (multipart upload, binary) — needs `contentType`. */
|
|
35
|
+
rawBody?: string | Buffer;
|
|
36
|
+
contentType?: string;
|
|
37
|
+
/** `text` returns the body verbatim (Drive export / `alt=media`); default `json`. */
|
|
38
|
+
responseType?: 'json' | 'text';
|
|
39
|
+
}
|
|
29
40
|
/**
|
|
30
|
-
* Authenticated
|
|
41
|
+
* Authenticated call to a Google API.
|
|
31
42
|
*
|
|
32
43
|
* @param deps - Token provider + fetch
|
|
33
44
|
* @param url - Absolute URL (use {@link buildGoogleUrl})
|
|
34
|
-
* @param init - Method and
|
|
35
|
-
* @returns The parsed JSON response
|
|
45
|
+
* @param init - Method, body and response type
|
|
46
|
+
* @returns The parsed JSON response (or the raw text with `responseType: 'text'`)
|
|
36
47
|
* @throws GoogleWorkspaceError — token failures pass through; Google 401 →
|
|
37
48
|
* 401 google_error (cache dropped), 403/404/429 keep their status, other
|
|
38
49
|
* failures → 502 google_error, unreachable → 502 network
|
|
39
50
|
*/
|
|
40
|
-
export declare function googleRequest<T>(deps: GoogleApiDeps, url: string, init?:
|
|
41
|
-
method?: 'GET' | 'POST';
|
|
42
|
-
body?: unknown;
|
|
43
|
-
}): Promise<T>;
|
|
51
|
+
export declare function googleRequest<T>(deps: GoogleApiDeps, url: string, init?: GoogleRequestInit): Promise<T>;
|
|
44
52
|
//# sourceMappingURL=google-api.client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-api.client.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/google/google-api.client.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,yEAAyE;AACzE,MAAM,WAAW,mBAAmB;IAClC,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAClC,UAAU,IAAI,IAAI,CAAC;CACpB;AAED,qEAAqE;AACrE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAwBD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAM,GAAG,MAAM,CAWxH;AAED
|
|
1
|
+
{"version":3,"file":"google-api.client.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/google/google-api.client.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,yEAAyE;AACzE,MAAM,WAAW,mBAAmB;IAClC,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAClC,UAAU,IAAI,IAAI,CAAC;CACpB;AAED,qEAAqE;AACrE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAwBD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAM,GAAG,MAAM,CAWxH;AAED,iDAAiD;AACjD,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;IACrD,gEAAgE;IAChE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAChC;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,iBAAsB,GAAG,OAAO,CAAC,CAAC,CAAC,CA4CjH"}
|
|
@@ -51,12 +51,12 @@ export function buildGoogleUrl(base, params = {}) {
|
|
|
51
51
|
return url.toString();
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
54
|
-
* Authenticated
|
|
54
|
+
* Authenticated call to a Google API.
|
|
55
55
|
*
|
|
56
56
|
* @param deps - Token provider + fetch
|
|
57
57
|
* @param url - Absolute URL (use {@link buildGoogleUrl})
|
|
58
|
-
* @param init - Method and
|
|
59
|
-
* @returns The parsed JSON response
|
|
58
|
+
* @param init - Method, body and response type
|
|
59
|
+
* @returns The parsed JSON response (or the raw text with `responseType: 'text'`)
|
|
60
60
|
* @throws GoogleWorkspaceError — token failures pass through; Google 401 →
|
|
61
61
|
* 401 google_error (cache dropped), 403/404/429 keep their status, other
|
|
62
62
|
* failures → 502 google_error, unreachable → 502 network
|
|
@@ -65,16 +65,21 @@ export async function googleRequest(deps, url, init = {}) {
|
|
|
65
65
|
const token = await deps.tokens.getAccessToken();
|
|
66
66
|
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
67
67
|
const CODES = GOOGLE_WORKSPACE_CONSTANTS.ERROR_CODES;
|
|
68
|
+
const wantsText = init.responseType === 'text';
|
|
68
69
|
let res;
|
|
69
70
|
try {
|
|
70
71
|
res = await fetchImpl(url, {
|
|
71
72
|
method: init.method ?? 'GET',
|
|
72
73
|
headers: {
|
|
73
74
|
Authorization: `Bearer ${token}`,
|
|
74
|
-
Accept: 'application/json',
|
|
75
|
-
...(init.
|
|
75
|
+
Accept: wantsText ? '*/*' : 'application/json',
|
|
76
|
+
...(init.rawBody !== undefined
|
|
77
|
+
? { 'Content-Type': init.contentType ?? 'application/octet-stream' }
|
|
78
|
+
: init.body !== undefined
|
|
79
|
+
? { 'Content-Type': 'application/json' }
|
|
80
|
+
: {}),
|
|
76
81
|
},
|
|
77
|
-
body: init.body !== undefined ? JSON.stringify(init.body) : undefined,
|
|
82
|
+
body: init.rawBody !== undefined ? init.rawBody : init.body !== undefined ? JSON.stringify(init.body) : undefined,
|
|
78
83
|
signal: AbortSignal.timeout(GOOGLE_WORKSPACE_CONSTANTS.REQUEST_TIMEOUT_MS),
|
|
79
84
|
});
|
|
80
85
|
}
|
|
@@ -92,6 +97,8 @@ export async function googleRequest(deps, url, init = {}) {
|
|
|
92
97
|
const passthrough = res.status === 403 || res.status === 404 || res.status === 429;
|
|
93
98
|
throw new GoogleWorkspaceError(passthrough ? res.status : 502, CODES.GOOGLE_ERROR, message);
|
|
94
99
|
}
|
|
100
|
+
if (wantsText)
|
|
101
|
+
return text;
|
|
95
102
|
if (!text)
|
|
96
103
|
return {};
|
|
97
104
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-api.client.js","sourceRoot":"","sources":["../../../../../../backend/src/services/google/google-api.client.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC;AAmB3E;;;;;;GAMG;AACH,SAAS,kBAAkB,CAAC,IAAY;IACtC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAoB,CAAC;QACnD,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ;YAAE,OAAO,MAAM,CAAC,KAAK,CAAC;QAC1D,OAAO,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/C,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,SAAiE,EAAE;IAC9G,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;IAC1B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE;YAAE,SAAS;QAClD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,KAAK,MAAM,CAAC,IAAI,KAAK;gBAAE,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACzD,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC;
|
|
1
|
+
{"version":3,"file":"google-api.client.js","sourceRoot":"","sources":["../../../../../../backend/src/services/google/google-api.client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SheetsService — Google Sheets over the owner's Workspace grant.
|
|
3
|
+
*
|
|
4
|
+
* Reads any spreadsheet the owner can see (`drive.readonly`), creates new
|
|
5
|
+
* spreadsheets and writes to the ones Crewly created (`drive.file`).
|
|
6
|
+
* Writing to a spreadsheet made elsewhere needs the `spreadsheets` scope
|
|
7
|
+
* the grant does not carry yet; Google answers 403 and the error says so.
|
|
8
|
+
*
|
|
9
|
+
* @module services/google/sheets.service
|
|
10
|
+
*/
|
|
11
|
+
import { type GoogleApiDeps } from './google-api.client.js';
|
|
12
|
+
/** A cell value as the API returns it (strings/numbers/booleans). */
|
|
13
|
+
export type SheetCell = string | number | boolean;
|
|
14
|
+
/** A rectangular block of values. */
|
|
15
|
+
export interface SheetValues {
|
|
16
|
+
spreadsheetId: string;
|
|
17
|
+
range: string;
|
|
18
|
+
rows: SheetCell[][];
|
|
19
|
+
}
|
|
20
|
+
/** Spreadsheet metadata. */
|
|
21
|
+
export interface SpreadsheetInfo {
|
|
22
|
+
id: string;
|
|
23
|
+
title: string;
|
|
24
|
+
sheets: Array<{
|
|
25
|
+
title: string;
|
|
26
|
+
rowCount?: number;
|
|
27
|
+
columnCount?: number;
|
|
28
|
+
}>;
|
|
29
|
+
webViewLink: string;
|
|
30
|
+
}
|
|
31
|
+
/** Create input. */
|
|
32
|
+
export interface SheetCreateInput {
|
|
33
|
+
title: string;
|
|
34
|
+
/** Name of the first sheet tab (default "Sheet1"). */
|
|
35
|
+
sheetTitle?: string;
|
|
36
|
+
/** Initial rows written from A1. */
|
|
37
|
+
rows?: SheetCell[][];
|
|
38
|
+
}
|
|
39
|
+
/** Write input (append or overwrite). */
|
|
40
|
+
export interface SheetWriteInput {
|
|
41
|
+
spreadsheetId: string;
|
|
42
|
+
/** A1 range; for append the table it belongs to, for update the top-left anchor. */
|
|
43
|
+
range?: string;
|
|
44
|
+
rows: SheetCell[][];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Validate rows for a write.
|
|
48
|
+
*
|
|
49
|
+
* @param rows - Candidate rows
|
|
50
|
+
* @returns The rows
|
|
51
|
+
* @throws GoogleWorkspaceError(400, validation) when empty, not rectangular-ish, or too many
|
|
52
|
+
*/
|
|
53
|
+
export declare function requireRows(rows: unknown): SheetCell[][];
|
|
54
|
+
/**
|
|
55
|
+
* Sheets: read, create, append, update.
|
|
56
|
+
*/
|
|
57
|
+
export declare class SheetsService {
|
|
58
|
+
private readonly deps;
|
|
59
|
+
private readonly base;
|
|
60
|
+
/**
|
|
61
|
+
* @param deps - Token provider and optional fetch override
|
|
62
|
+
*/
|
|
63
|
+
constructor(deps: GoogleApiDeps);
|
|
64
|
+
/**
|
|
65
|
+
* `spreadsheets.get` (properties only) — title and the sheet tabs.
|
|
66
|
+
*
|
|
67
|
+
* @param id - Spreadsheet id
|
|
68
|
+
* @returns Metadata
|
|
69
|
+
*/
|
|
70
|
+
info(id: string): Promise<SpreadsheetInfo>;
|
|
71
|
+
/**
|
|
72
|
+
* `spreadsheets.values.get`.
|
|
73
|
+
*
|
|
74
|
+
* @param id - Spreadsheet id
|
|
75
|
+
* @param range - A1 range (default `A1:Z1000` on the first sheet)
|
|
76
|
+
* @returns The values (rows may be ragged)
|
|
77
|
+
*/
|
|
78
|
+
read(id: string, range?: string): Promise<SheetValues>;
|
|
79
|
+
/**
|
|
80
|
+
* `spreadsheets.create`, then `values.update` from A1 when rows are given.
|
|
81
|
+
*
|
|
82
|
+
* @param input - Title, first-sheet name, initial rows
|
|
83
|
+
* @returns The new spreadsheet
|
|
84
|
+
* @throws GoogleWorkspaceError(400, validation) without a title
|
|
85
|
+
*/
|
|
86
|
+
create(input: SheetCreateInput): Promise<SpreadsheetInfo>;
|
|
87
|
+
/**
|
|
88
|
+
* `spreadsheets.values.append` — rows go below the last row of the
|
|
89
|
+
* table that contains `range` (default: the first sheet).
|
|
90
|
+
*
|
|
91
|
+
* @param input - Spreadsheet, range, rows
|
|
92
|
+
* @returns Updated range and counts
|
|
93
|
+
*/
|
|
94
|
+
append(input: SheetWriteInput): Promise<{
|
|
95
|
+
spreadsheetId: string;
|
|
96
|
+
updatedRange: string;
|
|
97
|
+
updatedRows: number;
|
|
98
|
+
}>;
|
|
99
|
+
/**
|
|
100
|
+
* `spreadsheets.values.update` — overwrite starting at `range`.
|
|
101
|
+
*
|
|
102
|
+
* @param input - Spreadsheet, anchor range, rows
|
|
103
|
+
* @returns Updated range and counts
|
|
104
|
+
*/
|
|
105
|
+
update(input: SheetWriteInput): Promise<{
|
|
106
|
+
spreadsheetId: string;
|
|
107
|
+
updatedRange: string;
|
|
108
|
+
updatedRows: number;
|
|
109
|
+
}>;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Quote a sheet name for an A1 range when it needs it.
|
|
113
|
+
*
|
|
114
|
+
* @param name - Sheet title
|
|
115
|
+
* @returns `'My Sheet'` or `Sheet1`
|
|
116
|
+
*/
|
|
117
|
+
export declare function quoteSheet(name: string): string;
|
|
118
|
+
//# sourceMappingURL=sheets.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sheets.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/google/sheets.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAiC,KAAK,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAG3F,qEAAqE;AACrE,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAElD,qCAAqC;AACrC,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC;CACrB;AAED,4BAA4B;AAC5B,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1E,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,oBAAoB;AACpB,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,CAAC;CACtB;AAED,yCAAyC;AACzC,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,oFAAoF;IACpF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC;CACrB;AASD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,EAAE,EAAE,CAexD;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA8C;IAEnE;;OAEG;gBACS,IAAI,EAAE,aAAa;IAI/B;;;;;OAKG;IACG,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAWhD;;;;;;OAMG;IACG,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAa5D;;;;;;OAMG;IACG,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAe/D;;;;;;OAMG;IACG,MAAM,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAenH;;;;;OAKG;IACG,MAAM,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;CAapH;AAgBD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C"}
|