@credal/actions 0.2.225 → 0.2.226

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.
@@ -11492,11 +11492,11 @@ export const microsoftCreateDocumentDefinition = {
11492
11492
  },
11493
11493
  name: {
11494
11494
  type: "string",
11495
- description: "The name of the new document (include extension like .docx or .xlsx)",
11495
+ description: "The name of the new document, including the extension. Use .docx for a Word document (the content is converted into a real Word file) or a plain-text extension like .txt or .md. Other Office extensions (.doc, .xlsx, .xls, .pptx, .ppt) are not supported and will be rejected",
11496
11496
  },
11497
11497
  content: {
11498
11498
  type: "string",
11499
- description: "The content to add to the new document",
11499
+ description: "The plain-text content of the document. When the name ends in .docx it is converted into a Word document with one paragraph per line; otherwise it is written as-is",
11500
11500
  },
11501
11501
  folderId: {
11502
11502
  type: "string",
@@ -11556,7 +11556,7 @@ export const microsoftUpdateDocumentDefinition = {
11556
11556
  },
11557
11557
  content: {
11558
11558
  type: "string",
11559
- description: "The new content to update in the document",
11559
+ description: "The new plain-text content for the document (replaces the existing content entirely). If the target file is a .docx it is converted into a Word document with one paragraph per line; other Office formats (.doc, .xlsx, .xls, .pptx, .ppt) cannot be updated",
11560
11560
  },
11561
11561
  },
11562
11562
  },
@@ -4268,8 +4268,12 @@ export const microsoftCreateDocumentParamsSchema = z.object({
4268
4268
  .string()
4269
4269
  .describe("The ID of the drive (document library) to create the document in. Required to target a non-default document library; takes precedence over siteId. Can be resolved from a SharePoint URL with the getSharepointItem action")
4270
4270
  .optional(),
4271
- name: z.string().describe("The name of the new document (include extension like .docx or .xlsx)"),
4272
- content: z.string().describe("The content to add to the new document"),
4271
+ name: z
4272
+ .string()
4273
+ .describe("The name of the new document, including the extension. Use .docx for a Word document (the content is converted into a real Word file) or a plain-text extension like .txt or .md. Other Office extensions (.doc, .xlsx, .xls, .pptx, .ppt) are not supported and will be rejected"),
4274
+ content: z
4275
+ .string()
4276
+ .describe("The plain-text content of the document. When the name ends in .docx it is converted into a Word document with one paragraph per line; otherwise it is written as-is"),
4273
4277
  folderId: z.string().describe("The ID of the folder to create the document in (optional)").optional(),
4274
4278
  });
4275
4279
  export const microsoftCreateDocumentOutputSchema = z.object({
@@ -4289,7 +4293,9 @@ export const microsoftUpdateDocumentParamsSchema = z.object({
4289
4293
  .describe("The ID of the drive (document library) containing the document. Required when the document is in a non-default document library; takes precedence over siteId. Can be resolved from a SharePoint URL with the getSharepointItem action")
4290
4294
  .optional(),
4291
4295
  documentId: z.string().describe("The ID of the document"),
4292
- content: z.string().describe("The new content to update in the document"),
4296
+ content: z
4297
+ .string()
4298
+ .describe("The new plain-text content for the document (replaces the existing content entirely). If the target file is a .docx it is converted into a Word document with one paragraph per line; other Office formats (.doc, .xlsx, .xls, .pptx, .ppt) cannot be updated"),
4293
4299
  });
4294
4300
  export const microsoftUpdateDocumentOutputSchema = z.object({
4295
4301
  success: z.boolean().describe("Whether the document was updated successfully"),
@@ -1,4 +1,4 @@
1
- import { getDrivePath, getGraphClient, validateAndSanitizeFileName } from "./utils.js";
1
+ import { fileNameHasDocxExtension, generateDocxFromPlainText, getDrivePath, getGraphClient, getUnsupportedOfficeExtension, validateAndSanitizeFileName, } from "./utils.js";
2
2
  const createDocument = async ({ params, authParams, }) => {
3
3
  const { folderId, name, content, siteId, driveId } = params;
4
4
  let client = undefined;
@@ -12,10 +12,20 @@ const createDocument = async ({ params, authParams, }) => {
12
12
  };
13
13
  }
14
14
  const sanitizedFileName = validateAndSanitizeFileName(name);
15
+ const unsupportedOfficeExtension = getUnsupportedOfficeExtension(sanitizedFileName);
16
+ if (unsupportedOfficeExtension) {
17
+ return {
18
+ success: false,
19
+ error: `Cannot create "${unsupportedOfficeExtension}" files: this action writes the provided text and can only generate Word documents. Use a .docx extension for a Word document, or a plain-text extension like .txt.`,
20
+ };
21
+ }
15
22
  const endpoint = `${getDrivePath({ driveId, siteId })}/items/${folderId || "root"}:/${sanitizedFileName}:/content`;
16
23
  try {
24
+ // .docx is a ZIP-of-XML container, so the text must be converted into real OOXML
25
+ // bytes; writing it directly would produce a file Word cannot open.
26
+ const body = fileNameHasDocxExtension(sanitizedFileName) ? await generateDocxFromPlainText(content) : content;
17
27
  // Create or update the document
18
- const response = await client.api(endpoint).put(content);
28
+ const response = await client.api(endpoint).put(body);
19
29
  return {
20
30
  success: true,
21
31
  documentId: response.id,
@@ -1,4 +1,4 @@
1
- import { getDrivePath, getGraphClient } from "./utils.js";
1
+ import { fileNameHasDocxExtension, generateDocxFromPlainText, getDrivePath, getGraphClient, getUnsupportedOfficeExtension, } from "./utils.js";
2
2
  const updateDocument = async ({ params, authParams, }) => {
3
3
  const { documentId, content, siteId, driveId } = params;
4
4
  let client = undefined;
@@ -12,8 +12,21 @@ const updateDocument = async ({ params, authParams, }) => {
12
12
  };
13
13
  }
14
14
  try {
15
- const endpoint = `${getDrivePath({ driveId, siteId })}/items/${documentId}/content`;
16
- const response = await client.api(endpoint).put(content);
15
+ const drivePath = getDrivePath({ driveId, siteId });
16
+ // The target's filename decides how the content must be written: .docx is a
17
+ // ZIP-of-XML container, so overwriting it with raw text would corrupt it.
18
+ const itemMetadata = await client.api(`${drivePath}/items/${documentId}?$select=name`).get();
19
+ const fileName = itemMetadata?.name ?? "";
20
+ const unsupportedOfficeExtension = getUnsupportedOfficeExtension(fileName);
21
+ if (unsupportedOfficeExtension) {
22
+ return {
23
+ success: false,
24
+ error: `Cannot update "${unsupportedOfficeExtension}" files: this action writes the provided text and can only generate Word documents. Only .docx and plain-text files can be updated.`,
25
+ };
26
+ }
27
+ const body = fileNameHasDocxExtension(fileName) ? await generateDocxFromPlainText(content) : content;
28
+ const endpoint = `${drivePath}/items/${documentId}/content`;
29
+ const response = await client.api(endpoint).put(body);
17
30
  return {
18
31
  success: true,
19
32
  documentUrl: response.webUrl,
@@ -16,4 +16,12 @@ export declare function getDrivePath({ driveId, siteId }: {
16
16
  * @returns A sanitized filename that is safe to use.
17
17
  */
18
18
  export declare function validateAndSanitizeFileName(fileName: string): string;
19
+ export declare function fileNameHasDocxExtension(fileName: string): boolean;
20
+ export declare function getUnsupportedOfficeExtension(fileName: string): string | undefined;
21
+ /**
22
+ * Builds a valid .docx file from plain text, one paragraph per line. A .docx is a ZIP
23
+ * archive of XML parts, so text bytes written directly under a .docx name produce a
24
+ * corrupted document — the bytes must be generated with an OOXML writer.
25
+ */
26
+ export declare function generateDocxFromPlainText(text: string): Promise<Buffer>;
19
27
  export declare const MICROSOFT_GRAPH_API_URL = "https://graph.microsoft.com/v1.0";
@@ -1,4 +1,5 @@
1
1
  import { Client } from "@microsoft/microsoft-graph-client";
2
+ import { Document, Packer, Paragraph, TextRun } from "docx";
2
3
  export async function getGraphClient(authParams) {
3
4
  if (!authParams.authToken) {
4
5
  throw new Error("Missing required authentication parameters");
@@ -41,4 +42,24 @@ export function validateAndSanitizeFileName(fileName) {
41
42
  }
42
43
  return sanitizedFileName;
43
44
  }
45
+ // Office formats that are binary/ZIP containers. Writing plain text bytes under these
46
+ // extensions produces a file the corresponding Office app cannot open.
47
+ const UNSUPPORTED_OFFICE_EXTENSIONS = [".doc", ".xlsx", ".xls", ".pptx", ".ppt"];
48
+ export function fileNameHasDocxExtension(fileName) {
49
+ return fileName.toLowerCase().endsWith(".docx");
50
+ }
51
+ export function getUnsupportedOfficeExtension(fileName) {
52
+ const lowerCaseFileName = fileName.toLowerCase();
53
+ return UNSUPPORTED_OFFICE_EXTENSIONS.find(extension => lowerCaseFileName.endsWith(extension));
54
+ }
55
+ /**
56
+ * Builds a valid .docx file from plain text, one paragraph per line. A .docx is a ZIP
57
+ * archive of XML parts, so text bytes written directly under a .docx name produce a
58
+ * corrupted document — the bytes must be generated with an OOXML writer.
59
+ */
60
+ export async function generateDocxFromPlainText(text) {
61
+ const paragraphs = text.split(/\r?\n/).map(line => new Paragraph({ children: [new TextRun({ text: line })] }));
62
+ const document = new Document({ sections: [{ properties: {}, children: paragraphs }] });
63
+ return Packer.toBuffer(document);
64
+ }
44
65
  export const MICROSOFT_GRAPH_API_URL = "https://graph.microsoft.com/v1.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@credal/actions",
3
- "version": "0.2.225",
3
+ "version": "0.2.226",
4
4
  "type": "module",
5
5
  "description": "AI Actions by Credal AI",
6
6
  "sideEffects": false,