Skip to content

Commit 49290bf

Browse files
committed
working API interface in Node
1 parent 66900ca commit 49290bf

File tree

8 files changed

+322
-2
lines changed

8 files changed

+322
-2
lines changed

daemonist/.gitignore

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
build
2+
3+
# Logs
4+
logs
5+
*.log
6+
npm-debug.log*
7+
yarn-debug.log*
8+
yarn-error.log*
9+
lerna-debug.log*
10+
11+
# Diagnostic reports (https://nodejs.org/api/report.html)
12+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
13+
14+
# Runtime data
15+
pids
16+
*.pid
17+
*.seed
18+
*.pid.lock
19+
20+
# Directory for instrumented libs generated by jscoverage/JSCover
21+
lib-cov
22+
23+
# Coverage directory used by tools like istanbul
24+
coverage
25+
*.lcov
26+
27+
# nyc test coverage
28+
.nyc_output
29+
30+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
31+
.grunt
32+
33+
# Bower dependency directory (https://bower.io/)
34+
bower_components
35+
36+
# node-waf configuration
37+
.lock-wscript
38+
39+
# Compiled binary addons (https://nodejs.org/api/addons.html)
40+
build/Release
41+
42+
# Dependency directories
43+
node_modules/
44+
jspm_packages/
45+
46+
# TypeScript v1 declaration files
47+
typings/
48+
49+
# TypeScript cache
50+
*.tsbuildinfo
51+
52+
# Optional npm cache directory
53+
.npm
54+
55+
# Optional eslint cache
56+
.eslintcache
57+
58+
# Optional REPL history
59+
.node_repl_history
60+
61+
# Output of 'npm pack'
62+
*.tgz
63+
64+
# Yarn Integrity file
65+
.yarn-integrity
66+
67+
# dotenv environment variables file
68+
.env
69+
.env.test
70+
71+
# parcel-bundler cache (https://parceljs.org/)
72+
.cache
73+
74+
# next.js build output
75+
.next
76+
77+
# nuxt.js build output
78+
.nuxt
79+
80+
# vuepress build output
81+
.vuepress/dist
82+
83+
# Serverless directories
84+
.serverless/
85+
86+
# FuseBox cache
87+
.fusebox/
88+
89+
# DynamoDB Local files
90+
.dynamodb/

daemonist/package-lock.json

+18
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

daemonist/package.json

+7-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
"name": "daemonist",
33
"version": "0.1.0",
44
"description": "Makes dynalist dynamic.",
5-
"main": "index.js",
5+
"main": "build/index.js",
66
"scripts": {
7+
"start": "tsc && node build/index.js",
78
"test": "echo \"Error: no test specified\" && exit 1"
89
},
910
"repository": {
@@ -18,5 +19,9 @@
1819
"bugs": {
1920
"url": "https://github.com/tloen/eudaemon/issues"
2021
},
21-
"homepage": "https://github.com/tloen/eudaemon#readme"
22+
"homepage": "https://github.com/tloen/eudaemon#readme",
23+
"dependencies": {
24+
"node-fetch": "^2.6.0",
25+
"typescript": "^3.5.3"
26+
}
2227
}

daemonist/src/api.ts

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { Dynalist } from "./dynalist";
2+
3+
export const ENDPOINTS = {
4+
GET_FILES: "https://dynalist.io/api/v1/file/list",
5+
READ_DOCUMENT: "https://dynalist.io/api/v1/doc/read"
6+
};
7+
8+
type FailCode =
9+
| "Invalid"
10+
| "TooManyRequests"
11+
| "InvalidToken"
12+
| "LockFail"
13+
| "Unauthorized"
14+
| "NotFound"
15+
| "NodeNotFound"
16+
| "NoInbox";
17+
18+
type SuccessCode = "OK";
19+
20+
export interface SuccessfulResponse {
21+
_code: SuccessCode;
22+
}
23+
24+
export interface FailedResponse {
25+
_code: FailCode;
26+
_msg: string;
27+
}
28+
29+
export type APIResponse = SuccessfulResponse | FailedResponse;
30+
31+
export interface GetFilesResponse extends SuccessfulResponse {
32+
root_file_id: string;
33+
files: Dynalist.File[];
34+
}
35+
36+
export interface DocumentReadResponse extends SuccessfulResponse {
37+
title: string;
38+
nodes: Dynalist.Node[];
39+
}
40+
41+
export interface NodeKey {
42+
fileID: string;
43+
nodeID: string;
44+
}

daemonist/src/dynalist.ts

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
export namespace Dynalist {
2+
export type FileType = "document" | "folder";
3+
4+
export interface File {
5+
id: string;
6+
title: string;
7+
type: FileType;
8+
permission: number;
9+
}
10+
11+
export interface Folder extends File {
12+
collapsed: boolean;
13+
children: string[];
14+
}
15+
16+
export enum Color {
17+
None = 0,
18+
Red,
19+
Orange,
20+
Yellow,
21+
Green,
22+
Blue,
23+
Violet
24+
}
25+
26+
export enum HeadingLevel {
27+
P = 0,
28+
H1,
29+
H2,
30+
H3
31+
}
32+
33+
export interface Node {
34+
id: string;
35+
content: string;
36+
note: string;
37+
created: number;
38+
modified: number;
39+
children: string[];
40+
41+
checked?: boolean;
42+
checkbox?: boolean;
43+
color?: Color;
44+
heading?: HeadingLevel;
45+
collapsed?: boolean;
46+
}
47+
48+
export interface Document {
49+
id: string;
50+
title: string;
51+
nodes: Node[];
52+
}
53+
}

daemonist/src/index.ts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { DynalistAPI } from "./session";
2+
3+
const api = new DynalistAPI("<|key|>");
4+
5+
// api.getFileTree().then(console.log);
6+
api.readDocument("HP3Ov2goSBuIPEzMA2T3jRkk").then(console.log);

daemonist/src/session.ts

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import {
2+
GetFilesResponse,
3+
ENDPOINTS,
4+
DocumentReadResponse,
5+
SuccessfulResponse
6+
} from "./api";
7+
import { Dynalist } from "./dynalist";
8+
import fetch from "node-fetch";
9+
10+
interface FetchRequest {
11+
url: string;
12+
params?: any;
13+
}
14+
15+
export class DynalistAPI {
16+
private token: string;
17+
// private fileTree: Dynalist.File[] | undefined;
18+
// private cache; // TODO
19+
20+
constructor(token: string) {
21+
this.token = token;
22+
}
23+
24+
// Limit: 60 times per minute
25+
public async readAllDocuments(): Promise<Dynalist.Document[]> {
26+
return this.getFileTree()
27+
.then(
28+
(files): Promise<DocumentReadResponse[]> => {
29+
const requests = files.map(
30+
(file): FetchRequest => ({
31+
url: ENDPOINTS.READ_DOCUMENT,
32+
params: {
33+
file_id: file.id
34+
}
35+
})
36+
);
37+
return this.batchPostFetch<DocumentReadResponse>(requests, 1500);
38+
}
39+
)
40+
.then(responses =>
41+
responses.map(response => {
42+
return {
43+
id: "abc",
44+
title: response.title,
45+
nodes: response.nodes
46+
};
47+
})
48+
);
49+
}
50+
51+
public readDocument(documentId: string): Promise<Dynalist.Document> {
52+
return this.postFetch(ENDPOINTS.READ_DOCUMENT, {
53+
file_id: documentId
54+
}).then((body: DocumentReadResponse) => ({
55+
id: documentId,
56+
nodes: body.nodes,
57+
title: body.title
58+
}));
59+
}
60+
61+
public getFileTree(): Promise<Dynalist.File[]> {
62+
return this.postFetch<GetFilesResponse>(ENDPOINTS.GET_FILES).then(
63+
body => body.files
64+
);
65+
}
66+
67+
private async batchPostFetch<T extends SuccessfulResponse>(
68+
requests: FetchRequest[],
69+
waitMilliseconds: number
70+
): Promise<T[]> {
71+
const results: T[] = [];
72+
for (const request of requests) {
73+
results.push(await this.postFetch<T>(request.url, request.params));
74+
await new Promise(_ => setTimeout(_, waitMilliseconds));
75+
}
76+
return results;
77+
}
78+
79+
private postFetch<T extends SuccessfulResponse>(
80+
url: string,
81+
params?: any
82+
): Promise<T> {
83+
return fetch(url, {
84+
headers: {
85+
"Content-Type": "application/json"
86+
},
87+
body: JSON.stringify({ token: this.token, ...params }),
88+
method: "POST"
89+
})
90+
.then(response => response.json())
91+
.then(body => {
92+
if (body._code !== "Ok") return Promise.reject(body._msg);
93+
else return body as T;
94+
});
95+
}
96+
}

daemonist/tsconfig.json

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"compilerOptions": {
3+
"lib": ["es2015", "es6", "dom"],
4+
"outDir": "./build",
5+
"target": "es5"
6+
},
7+
"include": ["src/**/*"]
8+
}

0 commit comments

Comments
 (0)