@jmuchovej/paperpile-notion
Version:
CLI to sync your Paperpile with Notion
186 lines (185 loc) • 6.79 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.batchEntries = exports.BATCH_SIZE = exports.archiveEmptyFilters = exports.buildCache = exports.createCMS = exports.makeURL = exports.makeRelation = exports.makeMultiSelect = exports.makeSelect = exports.makeRichText = exports.makeTitle = void 0;
const tslib_1 = require("tslib");
const notion_api_1 = require("@jitl/notion-api");
const node_path_1 = (0, tslib_1.__importDefault)(require("node:path"));
const lodash_1 = (0, tslib_1.__importDefault)(require("lodash"));
const client_1 = require("@notionhq/client");
const makeTitle = (content) => {
return {
type: "title",
title: [{
type: "text",
// @ts-ignore
text: { content: content.trim() },
}],
};
};
exports.makeTitle = makeTitle;
const makeRichText = (content) => {
if (lodash_1.default.isNil(content) || lodash_1.default.isEmpty(content)) {
return;
}
return {
type: "rich_text",
rich_text: [{
type: "text",
// @ts-ignore
text: { content: content.trim() },
}],
};
};
exports.makeRichText = makeRichText;
const makeSelect = (option) => {
if (lodash_1.default.isNil(option) || lodash_1.default.isEmpty(option)) {
return;
}
// @ts-ignore
return { select: { name: option } };
};
exports.makeSelect = makeSelect;
const makeMultiSelect = (options) => {
if (lodash_1.default.isNil(options))
return;
options = options.filter(a => a);
if (lodash_1.default.isEmpty(options) || !lodash_1.default.isString(options[0]))
return;
const multi_select = options.map((name) => {
return { name: name };
});
// @ts-ignore
return { type: "multi_select", multi_select };
};
exports.makeMultiSelect = makeMultiSelect;
const makeRelation = (relations) => {
if (lodash_1.default.isNil(relations) || lodash_1.default.isEmpty(relations) || !lodash_1.default.isObjectLike(relations[0])) {
return;
}
const relation = relations.map(({ id }) => {
return { id: id };
});
// @ts-ignore
return { type: "relation", relation };
};
exports.makeRelation = makeRelation;
const makeURL = (url) => {
if (lodash_1.default.isNil(url) || lodash_1.default.isEmpty(url)) {
return;
}
// @ts-ignore
return { type: "url", url };
};
exports.makeURL = makeURL;
function schemaArticlesDB(appConfig) {
return {
title: { type: "title", name: "Title" },
ID: { type: "rich_text", name: "ID" },
authors: {
type: appConfig.authorType,
name: appConfig.databases.articles.authorRef,
},
status: { type: "select", name: appConfig.status.colname },
topics: { type: "multi_select", name: appConfig.topics.colname },
fields: { type: "multi_select", name: appConfig.fields.colname },
methods: { type: "multi_select", name: appConfig.methods.colname },
folders: { type: "multi_select", name: appConfig.folders.colname },
venue: { type: "select", name: "Venue" },
url: { type: "url", name: "URL" },
};
}
function schemaAuthorsDB(appConfig) {
return {
name: { type: "title", name: "Name" },
articles: {
type: "relation",
name: appConfig.databases.authors?.articleRef,
},
aliases: { type: "rich_text", name: "Aliases" },
};
}
function getSchema(db, appConfig) {
const schemas = {
"articles": schemaArticlesDB,
"authors": schemaAuthorsDB,
};
return (0, notion_api_1.inferDatabaseSchema)(schemas[db](appConfig));
}
function createCMS(cliConfig, appConfig, notion, db) {
let { databaseID, primaryKey } = appConfig.databases[db];
const schema = getSchema(db, appConfig);
const getFrontmatter = ({ properties }) => properties;
return new notion_api_1.CMS({
database_id: databaseID, notion, schema,
getFrontmatter,
title: undefined,
visible: true,
// slug: undefined, /** NOTE setting this causes some weird errors... */
// @ts-ignore
slug: primaryKey,
cache: {
directory: node_path_1.default.join(cliConfig.cacheDir),
},
assets: {
directory: node_path_1.default.join(cliConfig.cacheDir, "assets"),
downloadExternalAssets: false,
},
});
}
exports.createCMS = createCMS;
const buildCache = async (cms) => {
for await (const page of cms.query()) {
}
};
exports.buildCache = buildCache;
const archiveEmptyFilters = async (CLI, cms, filter) => {
const toArchive = [];
for await (const page of cms.query({ filter })) {
const { content: { id, children }, frontmatter: { title } } = page;
if (children.length == 0) {
toArchive.push({ page_id: id, archived: true });
continue;
}
const Title = (0, notion_api_1.richTextAsPlainText)(title);
CLI.warn(`${Title} should be archived, but has content... Please clear it to enable archiving.`);
}
await (0, exports.batchEntries)(CLI, toArchive, async (entry) => {
await cms.config.notion.pages.update(entry);
});
};
exports.archiveEmptyFilters = archiveEmptyFilters;
exports.BATCH_SIZE = 10;
const batchEntries = async (CLI, entries, toNotion) => {
const failedEntries = [];
const chunks = lodash_1.default.chunk(entries, exports.BATCH_SIZE);
for await (const batch of chunks) {
await Promise.all(lodash_1.default.map(batch, async (entry) => {
try {
return await toNotion(entry);
}
catch (error) {
if (client_1.APIResponseError.isAPIResponseError(error)) {
switch (error.code) {
case client_1.APIErrorCode.ConflictError:
failedEntries.push(entry);
break;
case client_1.APIErrorCode.Unauthorized:
break;
case client_1.APIErrorCode.ValidationError:
console.error("Validation Failed:");
console.log(error.body);
break;
case client_1.APIErrorCode.RateLimited:
CLI.error("We've been rate limited. Please run again in ~20 minutes.");
break;
default:
console.log(error);
break;
}
}
}
}));
}
return failedEntries;
};
exports.batchEntries = batchEntries;
;