Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default {
key: "apify-get-dataset-items",
name: "Get Dataset Items",
description: "Returns data stored in a dataset. [See the documentation](https://docs.apify.com/api/v2/dataset-items-get)",
version: "0.0.5",
version: "0.0.6",
annotations: {
destructiveHint: false,
openWorldHint: true,
Expand Down
89 changes: 89 additions & 0 deletions components/apify/actions/get-kvs-record/get-kvs-record.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import axios from "axios";
import apify from "../../apify.app.mjs";

export default {
key: "apify-get-kvs-record",
name: "Get Key-Value Store Record",
description: "Gets a record from a key-value store. [See the documentation](https://docs.apify.com/api/v2/key-value-store-record-get)",
version: "0.0.1",
type: "action",
annotations: {
destructiveHint: false,
openWorldHint: true,
readOnlyHint: true,
},
props: {
apify,
keyValueStoreId: {
propDefinition: [
apify,
"keyValueStoreId",
() => ({
unnamed: false,
}),
],
},
key: {
type: "string",
label: "Record Key",
description: "If the record is a valid JSON object, the output will include all parsed attributes as individual fields. If the record is any other file type (such as PDFs, images, or plain text), the output will instead be a file reference.",
},
},
async run({ $ }) {
const token = this.apify.getAuthToken();

// HEAD request to get size and content-type
const recordUrl = `https://api.apify.com/v2/key-value-stores/${this.keyValueStoreId}/records/${encodeURIComponent(this.key)}`;
const headResp = await axios({
url: recordUrl,
method: "HEAD",
headers: {
Authorization: `Bearer ${token}`,
},
validateStatus: () => true,
});

if (headResp.status === 404) {
$.export("$summary", "Record not found");
return {};
}
if (headResp.status >= 400) {
throw new Error(`Error retrieving record: ${headResp.statusText}`);
}

const contentType = headResp.headers["content-type"];
const contentLength = parseInt(headResp.headers["content-length"] || "0");

const PARSEABLE_MIMES = [
"application/json",
"text/plain",
];
const MAX_INLINE_SIZE = 10 * 1000 * 1000;

// If parseable and small enough, get data via Apify client
if (PARSEABLE_MIMES.some((pattern) => contentType.includes(pattern))
&& contentLength < MAX_INLINE_SIZE) {
const record = await this.apify.getKVSRecord(this.keyValueStoreId, this.key);
const data = record?.value;

if (typeof data === "object" && !Array.isArray(data) && data !== null) {
$.export("$summary", "Retrieved JSON record");
return data;
} else {
$.export("$summary", "Retrieved text record");
return {
value: data ?? null,
};
}
} else {
// For large/binary files, return signed URL via Apify client
const signedUrl = await this.apify.getKVSRecordUrl(this.keyValueStoreId, this.key);

$.export("$summary", "Retrieved file pointer");
return {
contentType,
value: signedUrl,
};
}
},
};
50 changes: 33 additions & 17 deletions components/apify/actions/run-actor/run-actor.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default {
key: "apify-run-actor",
name: "Run Actor",
description: "Performs an execution of a selected Actor in Apify. [See the documentation](https://docs.apify.com/api/v2#/reference/actors/run-collection/run-actor)",
version: "0.0.6",
version: "0.0.7",
annotations: {
destructiveHint: false,
openWorldHint: true,
Expand Down Expand Up @@ -137,14 +137,18 @@ export default {
const newData = {};
const { properties } = await this.getSchema(this.actorId, this.buildTag);

// Iterate over properties from the schema because newData might contain additional fields
for (const [
key,
value,
] of Object.entries(data)) {
const editor = properties[key]?.editor || "hidden";
newData[key] = Array.isArray(value)
? value.map((item) => this.setValue(editor, item))
: value;
] of Object.entries(properties)) {
const propValue = data[key];
if (propValue === undefined) continue;

const editor = value.editor || "hidden";
newData[key] = Array.isArray(propValue)
? propValue.map((item) => this.setValue(editor, item))
: this.setValue(editor, propValue);
}
return newData;
},
Expand All @@ -170,6 +174,10 @@ export default {
return {
glob: item,
};
case "json":
case "schemaBased":
if (typeof item === "string") return JSON.parse(item);
return item;
default:
return item;
}
Expand Down Expand Up @@ -204,23 +212,27 @@ export default {
if (value.unit) {
props[key].description += ` Unit: ${value.unit}.`;
}
} else if (props[key].type === "boolean") {
// Default all boolean properties to false
props[key].default = false;
}

const options = this.prepareOptions(value);
if (options) props[key].options = options;
if (options) props[key].options = options.filter((option) => option.value !== "" && option.label !== "");

const defaultValue = value.prefill ?? value.default;
// We're using prefill here as a suggestion for the user. Using default value would be
// redundant as the default value is inserted by the Apify platform.
// More info: https://docs.apify.com/platform/actors/development/actor-definition/input-schema/specification/v1#prefill-vs-default-vs-required
const defaultValue = value.prefill;

if (defaultValue !== undefined) {
if (props[key].type !== "object") {
props[key].default = defaultValue;
props[key].default = defaultValue;

if (props[key].type === "string[]" && value.editor === "requestListSources") {
if (props[key].type === "string[]") {
if (value.editor === "requestListSources") {
props[key].default = defaultValue.map((request) => request.url);
}

if (value.editor === "json" || value.editor === "schemaBased") {
props[key].default = defaultValue.map((item) => JSON.stringify(item));
}
}

props[key].description += ` Default: \`${JSON.stringify(defaultValue)}\``;
Expand Down Expand Up @@ -297,9 +309,13 @@ export default {
}

// Prepare input
const rawInput = this.properties
? parseObject(this.properties)
: data;
// Use data (dynamic props from schema) if it has any keys,
// otherwise fall back to this.properties (fallback object prop)
const rawInput = Object.keys(data).length > 0
? data
: (this.properties
? parseObject(this.properties)
: {});
const input = await this.prepareData(rawInput);

// Build params safely
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default {
key: "apify-run-task-synchronously",
name: "Run Task Synchronously",
description: "Run a specific task and return its dataset items. [See the documentation](https://docs.apify.com/api/v2/actor-task-run-sync-get-dataset-items-get)",
version: "0.0.5",
version: "0.0.6",
annotations: {
destructiveHint: true,
openWorldHint: true,
Expand Down
Loading
Loading