runline 0.12.0 → 0.13.0

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.
@@ -1,10 +1,65 @@
1
+ import * as t from "typebox";
1
2
  import { googleAccessToken } from "../../_shared/googleAuth.js";
3
+ import { RawGoogleObject } from "../../_shared/googleSchemas.js";
2
4
  export const SCOPES = [
3
5
  "https://www.googleapis.com/auth/documents",
4
6
  "https://www.googleapis.com/auth/drive.file",
5
7
  ];
6
8
  export const DOCS_BASE = "https://docs.googleapis.com/v1";
7
9
  export const DRIVE_BASE = "https://www.googleapis.com/drive/v3";
10
+ export const STRICT_OBJECT = { additionalProperties: false };
11
+ export const DocumentInput = {
12
+ document: t.String({ minLength: 1, description: "Document ID or URL" }),
13
+ };
14
+ export const SegmentInput = {
15
+ segmentId: t.Optional(t.String({ description: 'Segment ID, or "body" for the main body' })),
16
+ tabId: t.Optional(t.String({ minLength: 1 })),
17
+ };
18
+ export const RangeInput = {
19
+ startIndex: t.Integer({ minimum: 0 }),
20
+ endIndex: t.Integer({ minimum: 0 }),
21
+ ...SegmentInput,
22
+ };
23
+ export const TableLocationInput = {
24
+ tableStartIndex: t.Integer({ minimum: 0 }),
25
+ rowIndex: t.Integer({ minimum: 0 }),
26
+ columnIndex: t.Integer({ minimum: 0 }),
27
+ ...SegmentInput,
28
+ };
29
+ export const LocationInput = {
30
+ locationKind: t.Optional(t.Union([t.Literal("location"), t.Literal("endOfSegmentLocation")])),
31
+ index: t.Optional(t.Integer({ minimum: 0 })),
32
+ ...SegmentInput,
33
+ };
34
+ export const LOCATION_REQUIREMENT = [
35
+ {
36
+ required: ["index"],
37
+ not: {
38
+ required: ["locationKind"],
39
+ properties: { locationKind: { const: "endOfSegmentLocation" } },
40
+ },
41
+ },
42
+ {
43
+ required: ["locationKind"],
44
+ properties: { locationKind: { const: "endOfSegmentLocation" } },
45
+ not: { required: ["index"] },
46
+ },
47
+ ];
48
+ export const HexColor = t.String({
49
+ pattern: "^#?(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$",
50
+ });
51
+ export const PositivePoints = t.Number({ minimum: 0 });
52
+ export const WriteControl = t.Object({
53
+ requiredRevisionId: t.Optional(t.String({ minLength: 1 })),
54
+ targetRevisionId: t.Optional(t.String({ minLength: 1 })),
55
+ }, {
56
+ additionalProperties: false,
57
+ oneOf: [
58
+ { required: ["requiredRevisionId"] },
59
+ { required: ["targetRevisionId"] },
60
+ ],
61
+ });
62
+ export { RawGoogleObject };
8
63
  export async function accessToken(ctx) {
9
64
  return googleAccessToken(ctx, "googleDocs", SCOPES);
10
65
  }
@@ -1,4 +1,5 @@
1
- import { buildLocation, compact, extractDocumentId, location, runBatchUpdate, } from "./shared.js";
1
+ import * as t from "typebox";
2
+ import { buildLocation, compact, DocumentInput, extractDocumentId, LOCATION_REQUIREMENT, LocationInput, location, PositivePoints, RangeInput, runBatchUpdate, SegmentInput, STRICT_OBJECT, } from "./shared.js";
2
3
  function range(p) {
3
4
  return compact({
4
5
  segmentId: p.segmentId && p.segmentId !== "body" ? p.segmentId : "",
@@ -14,13 +15,7 @@ export function registerStructureActions(rl) {
14
15
  rl.registerAction("document.insertPageBreak", {
15
16
  access: "write",
16
17
  description: "Insert a page break at an index or at the end of a segment.",
17
- inputSchema: {
18
- document: { type: "string", required: true },
19
- locationKind: { type: "string", required: false },
20
- index: { type: "number", required: false },
21
- segmentId: { type: "string", required: false },
22
- tabId: { type: "string", required: false },
23
- },
18
+ inputSchema: t.Object({ ...DocumentInput, ...LocationInput }, { ...STRICT_OBJECT, anyOf: LOCATION_REQUIREMENT }),
24
19
  async execute(input, ctx) {
25
20
  const p = (input ?? {});
26
21
  const documentId = extractDocumentId(p.document);
@@ -33,14 +28,11 @@ export function registerStructureActions(rl) {
33
28
  rl.registerAction("document.createNamedRange", {
34
29
  access: "write",
35
30
  description: "Create a named range over a span of text (useful for later programmatic edits).",
36
- inputSchema: {
37
- document: { type: "string", required: true },
38
- name: { type: "string", required: true },
39
- startIndex: { type: "number", required: true },
40
- endIndex: { type: "number", required: true },
41
- segmentId: { type: "string", required: false },
42
- tabId: { type: "string", required: false },
43
- },
31
+ inputSchema: t.Object({
32
+ ...DocumentInput,
33
+ name: t.String({ minLength: 1 }),
34
+ ...RangeInput,
35
+ }, STRICT_OBJECT),
44
36
  async execute(input, ctx) {
45
37
  const p = (input ?? {});
46
38
  const documentId = extractDocumentId(p.document);
@@ -55,16 +47,15 @@ export function registerStructureActions(rl) {
55
47
  rl.registerAction("document.deleteNamedRange", {
56
48
  access: "write",
57
49
  description: "Delete named range(s). Pass one of `namedRangeId` or `name`; the latter deletes every range sharing that name.",
58
- inputSchema: {
59
- document: { type: "string", required: true },
60
- namedRangeId: { type: "string", required: false },
61
- name: { type: "string", required: false },
62
- tabIds: {
63
- type: "array",
64
- required: false,
65
- description: "Optional tab IDs for tabsCriteria.",
66
- },
67
- },
50
+ inputSchema: t.Object({
51
+ ...DocumentInput,
52
+ namedRangeId: t.Optional(t.String({ minLength: 1 })),
53
+ name: t.Optional(t.String({ minLength: 1 })),
54
+ tabIds: t.Optional(t.Array(t.String({ minLength: 1 }), { minItems: 1 })),
55
+ }, {
56
+ ...STRICT_OBJECT,
57
+ oneOf: [{ required: ["namedRangeId"] }, { required: ["name"] }],
58
+ }),
68
59
  async execute(input, ctx) {
69
60
  const p = (input ?? {});
70
61
  const documentId = extractDocumentId(p.document);
@@ -82,13 +73,7 @@ export function registerStructureActions(rl) {
82
73
  rl.registerAction("document.createHeader", {
83
74
  access: "write",
84
75
  description: "Create a DEFAULT header attached to a SectionBreak.",
85
- inputSchema: {
86
- document: { type: "string", required: true },
87
- locationKind: { type: "string", required: false },
88
- index: { type: "number", required: false },
89
- segmentId: { type: "string", required: false },
90
- tabId: { type: "string", required: false },
91
- },
76
+ inputSchema: t.Object({ ...DocumentInput, ...LocationInput }, { ...STRICT_OBJECT, anyOf: LOCATION_REQUIREMENT }),
92
77
  async execute(input, ctx) {
93
78
  const p = (input ?? {});
94
79
  const documentId = extractDocumentId(p.document);
@@ -112,10 +97,11 @@ export function registerStructureActions(rl) {
112
97
  rl.registerAction("document.deleteHeader", {
113
98
  access: "write",
114
99
  description: "Delete a header by ID.",
115
- inputSchema: {
116
- document: { type: "string", required: true },
117
- headerId: { type: "string", required: true },
118
- },
100
+ inputSchema: t.Object({
101
+ ...DocumentInput,
102
+ headerId: t.String({ minLength: 1 }),
103
+ tabId: t.Optional(t.String({ minLength: 1 })),
104
+ }, STRICT_OBJECT),
119
105
  async execute(input, ctx) {
120
106
  const p = (input ?? {});
121
107
  const documentId = extractDocumentId(p.document);
@@ -127,13 +113,7 @@ export function registerStructureActions(rl) {
127
113
  rl.registerAction("document.createFooter", {
128
114
  access: "write",
129
115
  description: "Create a DEFAULT footer attached to a SectionBreak.",
130
- inputSchema: {
131
- document: { type: "string", required: true },
132
- locationKind: { type: "string", required: false },
133
- index: { type: "number", required: false },
134
- segmentId: { type: "string", required: false },
135
- tabId: { type: "string", required: false },
136
- },
116
+ inputSchema: t.Object({ ...DocumentInput, ...LocationInput }, { ...STRICT_OBJECT, anyOf: LOCATION_REQUIREMENT }),
137
117
  async execute(input, ctx) {
138
118
  const p = (input ?? {});
139
119
  const documentId = extractDocumentId(p.document);
@@ -157,10 +137,11 @@ export function registerStructureActions(rl) {
157
137
  rl.registerAction("document.deleteFooter", {
158
138
  access: "write",
159
139
  description: "Delete a footer by ID.",
160
- inputSchema: {
161
- document: { type: "string", required: true },
162
- footerId: { type: "string", required: true },
163
- },
140
+ inputSchema: t.Object({
141
+ ...DocumentInput,
142
+ footerId: t.String({ minLength: 1 }),
143
+ tabId: t.Optional(t.String({ minLength: 1 })),
144
+ }, STRICT_OBJECT),
164
145
  async execute(input, ctx) {
165
146
  const p = (input ?? {});
166
147
  const documentId = extractDocumentId(p.document);
@@ -172,11 +153,11 @@ export function registerStructureActions(rl) {
172
153
  rl.registerAction("document.deletePositionedObject", {
173
154
  access: "write",
174
155
  description: "Delete a positioned object (inline image, floating image, etc.) by its objectId.",
175
- inputSchema: {
176
- document: { type: "string", required: true },
177
- objectId: { type: "string", required: true },
178
- tabId: { type: "string", required: false },
179
- },
156
+ inputSchema: t.Object({
157
+ ...DocumentInput,
158
+ objectId: t.String({ minLength: 1 }),
159
+ tabId: t.Optional(t.String({ minLength: 1 })),
160
+ }, STRICT_OBJECT),
180
161
  async execute(input, ctx) {
181
162
  const p = (input ?? {});
182
163
  const documentId = extractDocumentId(p.document);
@@ -191,17 +172,7 @@ export function registerStructureActions(rl) {
191
172
  rl.registerAction("document.createFootnote", {
192
173
  access: "write",
193
174
  description: "Create a footnote reference at a location or at the end of the document body.",
194
- inputSchema: {
195
- document: { type: "string", required: true },
196
- locationKind: {
197
- type: "string",
198
- required: false,
199
- description: "location (default; requires index) | endOfSegmentLocation",
200
- },
201
- index: { type: "number", required: false },
202
- segmentId: { type: "string", required: false },
203
- tabId: { type: "string", required: false },
204
- },
175
+ inputSchema: t.Object({ ...DocumentInput, ...LocationInput }, { ...STRICT_OBJECT, anyOf: LOCATION_REQUIREMENT }),
205
176
  async execute(input, ctx) {
206
177
  const p = (input ?? {});
207
178
  const documentId = extractDocumentId(p.document);
@@ -214,17 +185,19 @@ export function registerStructureActions(rl) {
214
185
  rl.registerAction("document.replaceNamedRangeContent", {
215
186
  access: "write",
216
187
  description: "Replace the content of a named range by ID or name with text.",
217
- inputSchema: {
218
- document: { type: "string", required: true },
219
- text: { type: "string", required: true },
220
- namedRangeId: { type: "string", required: false },
221
- namedRangeName: { type: "string", required: false },
222
- tabIds: {
223
- type: "array",
224
- required: false,
225
- description: "Optional tab IDs for tabsCriteria.",
226
- },
227
- },
188
+ inputSchema: t.Object({
189
+ ...DocumentInput,
190
+ text: t.String(),
191
+ namedRangeId: t.Optional(t.String({ minLength: 1 })),
192
+ namedRangeName: t.Optional(t.String({ minLength: 1 })),
193
+ tabIds: t.Optional(t.Array(t.String({ minLength: 1 }), { minItems: 1 })),
194
+ }, {
195
+ ...STRICT_OBJECT,
196
+ oneOf: [
197
+ { required: ["namedRangeId"] },
198
+ { required: ["namedRangeName"] },
199
+ ],
200
+ }),
228
201
  async execute(input, ctx) {
229
202
  const p = (input ?? {});
230
203
  const documentId = extractDocumentId(p.document);
@@ -246,32 +219,28 @@ export function registerStructureActions(rl) {
246
219
  rl.registerAction("document.updateSectionStyle", {
247
220
  access: "write",
248
221
  description: "Update section style over a range, such as margins or column properties.",
249
- inputSchema: {
250
- document: { type: "string", required: true },
251
- startIndex: { type: "number", required: true },
252
- endIndex: { type: "number", required: true },
253
- marginTopPt: { type: "number", required: false },
254
- marginBottomPt: { type: "number", required: false },
255
- marginLeftPt: { type: "number", required: false },
256
- marginRightPt: { type: "number", required: false },
257
- columnSeparatorStyle: {
258
- type: "string",
259
- required: false,
260
- description: "NONE | BETWEEN_EACH_COLUMN",
261
- },
262
- contentDirection: {
263
- type: "string",
264
- required: false,
265
- description: "LEFT_TO_RIGHT | RIGHT_TO_LEFT",
266
- },
267
- fields: {
268
- type: "string",
269
- required: false,
270
- description: "Field mask. Defaults to fields implied by supplied properties.",
271
- },
272
- segmentId: { type: "string", required: false },
273
- tabId: { type: "string", required: false },
274
- },
222
+ inputSchema: t.Object({
223
+ ...DocumentInput,
224
+ ...RangeInput,
225
+ marginTopPt: t.Optional(PositivePoints),
226
+ marginBottomPt: t.Optional(PositivePoints),
227
+ marginLeftPt: t.Optional(PositivePoints),
228
+ marginRightPt: t.Optional(PositivePoints),
229
+ columnSeparatorStyle: t.Optional(t.Union([t.Literal("NONE"), t.Literal("BETWEEN_EACH_COLUMN")])),
230
+ contentDirection: t.Optional(t.Union([t.Literal("LEFT_TO_RIGHT"), t.Literal("RIGHT_TO_LEFT")])),
231
+ fields: t.Optional(t.String({ minLength: 1 })),
232
+ }, {
233
+ ...STRICT_OBJECT,
234
+ anyOf: [
235
+ { required: ["marginTopPt"] },
236
+ { required: ["marginBottomPt"] },
237
+ { required: ["marginLeftPt"] },
238
+ { required: ["marginRightPt"] },
239
+ { required: ["columnSeparatorStyle"] },
240
+ { required: ["contentDirection"] },
241
+ { required: ["fields"] },
242
+ ],
243
+ }),
275
244
  async execute(input, ctx) {
276
245
  const p = (input ?? {});
277
246
  const documentId = extractDocumentId(p.document);
@@ -316,17 +285,12 @@ export function registerStructureActions(rl) {
316
285
  rl.registerAction("document.insertSectionBreak", {
317
286
  access: "write",
318
287
  description: "Insert a section break at the given location.",
319
- inputSchema: {
320
- document: { type: "string", required: true },
321
- index: { type: "number", required: true },
322
- sectionType: {
323
- type: "string",
324
- required: false,
325
- description: "CONTINUOUS | NEXT_PAGE. Default CONTINUOUS.",
326
- },
327
- segmentId: { type: "string", required: false },
328
- tabId: { type: "string", required: false },
329
- },
288
+ inputSchema: t.Object({
289
+ ...DocumentInput,
290
+ index: t.Integer({ minimum: 0 }),
291
+ sectionType: t.Optional(t.Union([t.Literal("CONTINUOUS"), t.Literal("NEXT_PAGE")])),
292
+ ...SegmentInput,
293
+ }, STRICT_OBJECT),
330
294
  async execute(input, ctx) {
331
295
  const p = (input ?? {});
332
296
  const documentId = extractDocumentId(p.document);
@@ -343,17 +307,28 @@ export function registerStructureActions(rl) {
343
307
  rl.registerAction("document.updateDocumentStyle", {
344
308
  access: "write",
345
309
  description: "Update document-level style (page size, margins, page numbers, default direction).",
346
- inputSchema: {
347
- document: { type: "string", required: true },
348
- pageMarginTopPt: { type: "number", required: false },
349
- pageMarginBottomPt: { type: "number", required: false },
350
- pageMarginLeftPt: { type: "number", required: false },
351
- pageMarginRightPt: { type: "number", required: false },
352
- pageSizeWidthPt: { type: "number", required: false },
353
- pageSizeHeightPt: { type: "number", required: false },
354
- useCustomHeaderFooterMargins: { type: "boolean", required: false },
355
- tabId: { type: "string", required: false },
356
- },
310
+ inputSchema: t.Object({
311
+ ...DocumentInput,
312
+ pageMarginTopPt: t.Optional(PositivePoints),
313
+ pageMarginBottomPt: t.Optional(PositivePoints),
314
+ pageMarginLeftPt: t.Optional(PositivePoints),
315
+ pageMarginRightPt: t.Optional(PositivePoints),
316
+ pageSizeWidthPt: t.Optional(PositivePoints),
317
+ pageSizeHeightPt: t.Optional(PositivePoints),
318
+ useCustomHeaderFooterMargins: t.Optional(t.Boolean()),
319
+ tabId: t.Optional(t.String({ minLength: 1 })),
320
+ }, {
321
+ ...STRICT_OBJECT,
322
+ anyOf: [
323
+ { required: ["pageMarginTopPt"] },
324
+ { required: ["pageMarginBottomPt"] },
325
+ { required: ["pageMarginLeftPt"] },
326
+ { required: ["pageMarginRightPt"] },
327
+ { required: ["pageSizeWidthPt"] },
328
+ { required: ["pageSizeHeightPt"] },
329
+ { required: ["useCustomHeaderFooterMargins"] },
330
+ ],
331
+ }),
357
332
  async execute(input, ctx) {
358
333
  const p = (input ?? {});
359
334
  const documentId = extractDocumentId(p.document);