@miso.ai/server-wordpress 0.6.3-beta.0 → 0.6.3-beta.10
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.
- package/cli/entities.js +94 -28
- package/cli/index.js +5 -1
- package/cli/profile.js +13 -3
- package/package.json +2 -2
- package/src/client.js +1 -1
- package/src/entities/entity-index.js +3 -2
- package/src/entities/index.js +28 -1
- package/src/entities/presence.js +105 -0
- package/src/entities/transform-default.js +4 -3
- package/src/helpers.js +44 -7
- package/src/source/base.js +6 -5
- package/src/source/paged.js +2 -2
- package/src/version.js +1 -1
- package/src/axios.js +0 -6
package/cli/entities.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Transform } from 'stream';
|
|
2
|
+
import split2 from 'split2';
|
|
1
3
|
import { stream, parseDuration } from '@miso.ai/server-commons';
|
|
2
4
|
import { WordPressClient } from '../src/index.js';
|
|
3
5
|
import { normalizeOptions, normalizeTransform, parseDate } from './utils.js';
|
|
@@ -34,6 +36,11 @@ export function buildForEntities(yargs) {
|
|
|
34
36
|
alias: 'include',
|
|
35
37
|
describe: 'Specify post ids'
|
|
36
38
|
})
|
|
39
|
+
.option('fields', {
|
|
40
|
+
describe: 'Specify which record fields are retrieved',
|
|
41
|
+
type: 'array',
|
|
42
|
+
coerce: yargs.coerceToArray,
|
|
43
|
+
})
|
|
37
44
|
.option('resolve', {
|
|
38
45
|
alias: 'r',
|
|
39
46
|
describe: 'Attach resolved entities (author, catagories) linked with the subjects',
|
|
@@ -60,9 +67,23 @@ function build(yargs) {
|
|
|
60
67
|
});
|
|
61
68
|
}
|
|
62
69
|
|
|
63
|
-
async function run({ count, terms, update, name, ...options }) {
|
|
70
|
+
async function run({ subcmd, count, terms, update, name, ...options }) {
|
|
64
71
|
options = normalizeOptions(options);
|
|
65
72
|
const client = new WordPressClient(options);
|
|
73
|
+
switch (subcmd) {
|
|
74
|
+
case 'ids':
|
|
75
|
+
await runIds(client, name, { update, ...options });
|
|
76
|
+
return;
|
|
77
|
+
case 'count':
|
|
78
|
+
await runCount(client, name, options);
|
|
79
|
+
return;
|
|
80
|
+
case 'absence':
|
|
81
|
+
await runPresence(client, name, { present: false });
|
|
82
|
+
return;
|
|
83
|
+
case 'presence':
|
|
84
|
+
await runPresence(client, name, { present: true });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
66
87
|
if (count) {
|
|
67
88
|
await runCount(client, name, options);
|
|
68
89
|
} else if (terms) {
|
|
@@ -95,46 +116,91 @@ export async function runGet(client, name, { transform, ...options }) {
|
|
|
95
116
|
);
|
|
96
117
|
}
|
|
97
118
|
|
|
98
|
-
export async function
|
|
119
|
+
export async function runIds(client, name, { update, transform, resolve, fields, ...options }) {
|
|
120
|
+
if (update) {
|
|
121
|
+
await stream.pipeline(
|
|
122
|
+
await buildUpdateStream(client, name, update, { ...options, fields: ['id', 'modified_gmt'] }),
|
|
123
|
+
new Transform({
|
|
124
|
+
objectMode: true,
|
|
125
|
+
transform({ id }, _, callback) {
|
|
126
|
+
callback(null, id);
|
|
127
|
+
},
|
|
128
|
+
}),
|
|
129
|
+
new stream.OutputStream(),
|
|
130
|
+
);
|
|
131
|
+
} else {
|
|
132
|
+
await stream.pipeline(
|
|
133
|
+
await client.entities(name).ids(options),
|
|
134
|
+
new stream.OutputStream(),
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export async function runUpdate(client, name, update, options) {
|
|
140
|
+
await stream.pipeline(
|
|
141
|
+
await buildUpdateStream(client, name, update, options),
|
|
142
|
+
new stream.OutputStream(),
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export async function runPresence(client, name, options) {
|
|
147
|
+
await stream.pipeline(
|
|
148
|
+
process.stdin,
|
|
149
|
+
split2(),
|
|
150
|
+
client.entities(name).presence(options),
|
|
151
|
+
new stream.OutputStream({
|
|
152
|
+
objectMode: false,
|
|
153
|
+
}),
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async function buildUpdateStream(client, name, update, {
|
|
99
158
|
date, after, before, orderBy, order, // strip off date filters and order criteria
|
|
100
159
|
transform,
|
|
101
160
|
...options
|
|
102
161
|
}) {
|
|
162
|
+
// TODO: move the logic into client itself
|
|
103
163
|
transform = await normalizeTransform(transform);
|
|
104
164
|
const now = Date.now();
|
|
105
165
|
update = parseDuration(update);
|
|
106
166
|
const threshold = now - update;
|
|
107
167
|
const entities = client.entities(name);
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
168
|
+
return stream.concat(
|
|
169
|
+
...await Promise.all([
|
|
170
|
+
// get recent published
|
|
171
|
+
entities.stream({
|
|
172
|
+
...options,
|
|
173
|
+
transform,
|
|
174
|
+
after: threshold,
|
|
175
|
+
}),
|
|
176
|
+
// get recent modified, excluding ones already fetched
|
|
177
|
+
entities.stream({
|
|
178
|
+
...options,
|
|
179
|
+
transform,
|
|
180
|
+
orderBy: 'modified',
|
|
181
|
+
modifiedAfter: threshold,
|
|
182
|
+
before: threshold,
|
|
183
|
+
}),
|
|
184
|
+
/*
|
|
185
|
+
entities.stream({
|
|
186
|
+
...options,
|
|
187
|
+
transform,
|
|
188
|
+
orderBy: 'modified',
|
|
189
|
+
before: threshold,
|
|
190
|
+
pageSize: 20,
|
|
191
|
+
strategy: {
|
|
192
|
+
highWatermark: 100,
|
|
193
|
+
eagerLoad: true,
|
|
194
|
+
terminate: entity => parseDate(entity.modified_gmt) < threshold,
|
|
195
|
+
},
|
|
196
|
+
})
|
|
197
|
+
*/
|
|
198
|
+
])
|
|
133
199
|
);
|
|
134
200
|
}
|
|
135
201
|
|
|
136
202
|
export default {
|
|
137
|
-
command: ['$0 <name>'],
|
|
203
|
+
command: ['$0 <name> [subcmd]'],
|
|
138
204
|
desc: 'List entities from WordPress REST API',
|
|
139
205
|
builder: build,
|
|
140
206
|
handler: run,
|
package/cli/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { yargs } from '@miso.ai/server-commons';
|
|
3
3
|
import version from '../src/version.js';
|
|
4
|
-
import profile from './profile.js';
|
|
4
|
+
import { profile, init } from './profile.js';
|
|
5
5
|
import taxonomies from './taxonomies.js';
|
|
6
6
|
import entities from './entities.js';
|
|
7
7
|
|
|
@@ -16,11 +16,15 @@ yargs.build(yargs => {
|
|
|
16
16
|
alias: 'p',
|
|
17
17
|
describe: 'Site profile file location',
|
|
18
18
|
})
|
|
19
|
+
.option('auth', {
|
|
20
|
+
describe: 'Authentication string',
|
|
21
|
+
})
|
|
19
22
|
.option('debug', {
|
|
20
23
|
type: 'boolean',
|
|
21
24
|
default: false,
|
|
22
25
|
})
|
|
23
26
|
.hide('debug')
|
|
27
|
+
.command(init)
|
|
24
28
|
.command(profile)
|
|
25
29
|
.command(taxonomies)
|
|
26
30
|
.command(entities)
|
package/cli/profile.js
CHANGED
|
@@ -11,7 +11,7 @@ function build(yargs) {
|
|
|
11
11
|
});
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
async function
|
|
14
|
+
async function runProfile({ generate, ...options }) {
|
|
15
15
|
if (generate) {
|
|
16
16
|
await runGenerate(options);
|
|
17
17
|
} else {
|
|
@@ -38,9 +38,19 @@ async function runView(options) {
|
|
|
38
38
|
console.log(JSON.stringify(client.profile, undefined, 2));
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
async function runInit(options) {
|
|
42
|
+
await runGenerate(options);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const profile = {
|
|
42
46
|
command: 'profile',
|
|
43
47
|
desc: 'WordPress site profile management',
|
|
44
48
|
builder: build,
|
|
45
|
-
handler:
|
|
49
|
+
handler: runProfile,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const init = {
|
|
53
|
+
command: 'init <site>',
|
|
54
|
+
desc: 'Initialize WordPress site profile',
|
|
55
|
+
handler: runInit,
|
|
46
56
|
};
|
package/package.json
CHANGED
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
"simonpai <simon.pai@askmiso.com>"
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@miso.ai/server-commons": "0.6.3-beta.
|
|
20
|
+
"@miso.ai/server-commons": "0.6.3-beta.10",
|
|
21
21
|
"axios": "^0.27.2",
|
|
22
22
|
"axios-retry": "^3.3.1"
|
|
23
23
|
},
|
|
24
|
-
"version": "0.6.3-beta.
|
|
24
|
+
"version": "0.6.3-beta.10"
|
|
25
25
|
}
|
package/src/client.js
CHANGED
|
@@ -2,7 +2,7 @@ import { asArray, Resolution } from '@miso.ai/server-commons';
|
|
|
2
2
|
|
|
3
3
|
export default class EntityIndex {
|
|
4
4
|
|
|
5
|
-
constructor(entities, { process, value } = {}) {
|
|
5
|
+
constructor(entities, { process, value, fields } = {}) {
|
|
6
6
|
this._entities = entities;
|
|
7
7
|
if (process) {
|
|
8
8
|
this._process = process;
|
|
@@ -10,6 +10,7 @@ export default class EntityIndex {
|
|
|
10
10
|
if (value) {
|
|
11
11
|
this._value = (en => en && value(en)); // null-safe
|
|
12
12
|
}
|
|
13
|
+
this._fields = fields;
|
|
13
14
|
this.name = entities.name;
|
|
14
15
|
this._index = new Map();
|
|
15
16
|
this._notFound = new Set();
|
|
@@ -66,7 +67,7 @@ export default class EntityIndex {
|
|
|
66
67
|
if (idsToFetch.length > 0) {
|
|
67
68
|
(async () => {
|
|
68
69
|
const idsFetchSet = new Set(idsToFetch);
|
|
69
|
-
const stream = await this._entities.stream({ ids: idsToFetch });
|
|
70
|
+
const stream = await this._entities.stream({ ids: idsToFetch, fields: this._fields });
|
|
70
71
|
for await (const entity of stream) {
|
|
71
72
|
const { id } = entity;
|
|
72
73
|
this._index.set(id, this._process(entity));
|
package/src/entities/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { Transform } from 'stream';
|
|
1
2
|
import { asArray, stream } from '@miso.ai/server-commons';
|
|
2
3
|
import EntityIndex from './entity-index.js';
|
|
3
4
|
import EntityTransformStream from './transform.js';
|
|
5
|
+
import EntityPresenceStream from './presence.js';
|
|
4
6
|
import defaultTransform from './transform-default.js';
|
|
5
7
|
import legacyTransform from './transform-legacy.js';
|
|
6
8
|
|
|
@@ -14,6 +16,7 @@ export default class Entities {
|
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
async stream({ resolve = false, transform, ...options } = {}) {
|
|
19
|
+
// TODO: when after/before is used and fields are specified, we need to retain only fields that user wants
|
|
17
20
|
if (!resolve && !transform) {
|
|
18
21
|
return this._client._helpers.stream(this.name, options);
|
|
19
22
|
}
|
|
@@ -24,12 +27,17 @@ export default class Entities {
|
|
|
24
27
|
// we need taxonomy fetched so we know whether it's hierarchical
|
|
25
28
|
const taxonomies = await client._helpers.findAssociatedTaxonomies(this.name);
|
|
26
29
|
|
|
30
|
+
// TODO: omit specific indicies by config
|
|
27
31
|
// prepare entity indicies
|
|
32
|
+
const { resources = {} } = client._profile || {};
|
|
33
|
+
const ignored = new Set(resources.ignore || []);
|
|
34
|
+
|
|
28
35
|
const indicies = [
|
|
29
36
|
client.users.index,
|
|
30
37
|
client.media.index,
|
|
31
38
|
...taxonomies.map(({ rest_base }) => client.entities(rest_base).index),
|
|
32
|
-
];
|
|
39
|
+
].filter(index => !ignored.has(index.name));
|
|
40
|
+
|
|
33
41
|
await Promise.all(indicies.map(index => index.ready()));
|
|
34
42
|
for (const index of indicies) {
|
|
35
43
|
if (index.hierarchical) {
|
|
@@ -53,6 +61,21 @@ export default class Entities {
|
|
|
53
61
|
.pipe(transformStream);
|
|
54
62
|
}
|
|
55
63
|
|
|
64
|
+
async ids(options = {}) {
|
|
65
|
+
const { before, after, u } = options;
|
|
66
|
+
const fields = ['id'];
|
|
67
|
+
if (before || after) {
|
|
68
|
+
fields.push('modified_gmt');
|
|
69
|
+
}
|
|
70
|
+
return (await this._client._helpers.stream(this.name, { ...options, fields }))
|
|
71
|
+
.pipe(new Transform({
|
|
72
|
+
objectMode: true,
|
|
73
|
+
transform({ id }, _, callback) {
|
|
74
|
+
callback(null, id);
|
|
75
|
+
},
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
|
|
56
79
|
async getAll(options) {
|
|
57
80
|
return stream.collect(await this.stream(options));
|
|
58
81
|
}
|
|
@@ -65,6 +88,10 @@ export default class Entities {
|
|
|
65
88
|
return this._client._helpers.terms(this.name, options);
|
|
66
89
|
}
|
|
67
90
|
|
|
91
|
+
presence(options) {
|
|
92
|
+
return new EntityPresenceStream(this._client, this.name, options);
|
|
93
|
+
}
|
|
94
|
+
|
|
68
95
|
get index() {
|
|
69
96
|
return this._index;
|
|
70
97
|
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { Transform } from 'stream';
|
|
2
|
+
|
|
3
|
+
export default class EntityPresenceStream extends Transform {
|
|
4
|
+
|
|
5
|
+
constructor(client, name, {
|
|
6
|
+
present = true,
|
|
7
|
+
fetchSize = 20,
|
|
8
|
+
preserveOrder = true,
|
|
9
|
+
} = {}) {
|
|
10
|
+
super();
|
|
11
|
+
this._client = client;
|
|
12
|
+
this._name = name;
|
|
13
|
+
this._options = {
|
|
14
|
+
present,
|
|
15
|
+
fetchSize,
|
|
16
|
+
preserveOrder,
|
|
17
|
+
}
|
|
18
|
+
this._inputs = [];
|
|
19
|
+
this._pendingSet = new Set();
|
|
20
|
+
this._requests = [];
|
|
21
|
+
this._map = new Map();
|
|
22
|
+
this._done = false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async _transform(id, _, next) {
|
|
26
|
+
id = `${id}`; // buffer -> string
|
|
27
|
+
if (id) {
|
|
28
|
+
this._inputs.push(id);
|
|
29
|
+
this._outputAll();
|
|
30
|
+
this._requestAll();
|
|
31
|
+
}
|
|
32
|
+
next();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
_flush(done) {
|
|
36
|
+
this._done = done;
|
|
37
|
+
this._outputAll();
|
|
38
|
+
if (this._inputs.length > 0) {
|
|
39
|
+
this._requestAll(true);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
_outputAll() {
|
|
44
|
+
// TODO: implement when preserveOrder = false
|
|
45
|
+
let i = 0;
|
|
46
|
+
for (const len = this._inputs.length; i < len; i++) {
|
|
47
|
+
const id = this._inputs[i];
|
|
48
|
+
const entry = this._map.get(id);
|
|
49
|
+
if (!entry || entry.value === undefined) {
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
if (this._options.present === entry.value) {
|
|
53
|
+
this.push(id);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (i > 0) {
|
|
57
|
+
this._inputs = this._inputs.slice(i);
|
|
58
|
+
}
|
|
59
|
+
if (this._done && this._inputs.length === 0) {
|
|
60
|
+
this._done();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
_requestAll(flush = false) {
|
|
65
|
+
for (const id of this._inputs) {
|
|
66
|
+
this._fetchAll();
|
|
67
|
+
if (!this._map.has(id)) {
|
|
68
|
+
this._map.set(id, { status: 'pending' });
|
|
69
|
+
this._pendingSet.add(id);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
this._fetchAll(flush);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async _fetchAll(flush = false) {
|
|
76
|
+
if (!flush && this._pendingSet.size < this._options.fetchSize) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const ids = Array.from(this._pendingSet);
|
|
80
|
+
for (const id of ids) {
|
|
81
|
+
this._map.get(id).status = 'fetching';
|
|
82
|
+
}
|
|
83
|
+
this._pendingSet = new Set();
|
|
84
|
+
|
|
85
|
+
const presences = await this._fetch(ids);
|
|
86
|
+
|
|
87
|
+
for (const id of ids) {
|
|
88
|
+
const entry = this._map.get(id);
|
|
89
|
+
entry.status = 'ready';
|
|
90
|
+
entry.value = presences.has(id);
|
|
91
|
+
}
|
|
92
|
+
this._outputAll();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async _fetch(ids) {
|
|
96
|
+
const url = await this._client._helpers.url.build(this._name, { include: ids, fields: ['id'] });
|
|
97
|
+
const { data } = await this._client._helpers.axios.get(url);
|
|
98
|
+
const presences = new Set();
|
|
99
|
+
for (const { id } of data) {
|
|
100
|
+
presences.add(`${id}`);
|
|
101
|
+
}
|
|
102
|
+
return presences;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
}
|
|
@@ -14,14 +14,14 @@ export default function transform({
|
|
|
14
14
|
modified_gmt,
|
|
15
15
|
guid: {
|
|
16
16
|
rendered: guid,
|
|
17
|
-
},
|
|
17
|
+
} = {},
|
|
18
18
|
slug,
|
|
19
19
|
title: {
|
|
20
20
|
rendered: title,
|
|
21
|
-
},
|
|
21
|
+
} = {},
|
|
22
22
|
content: {
|
|
23
23
|
rendered: html,
|
|
24
|
-
},
|
|
24
|
+
} = {},
|
|
25
25
|
link: url,
|
|
26
26
|
status,
|
|
27
27
|
sticky,
|
|
@@ -42,6 +42,7 @@ export default function transform({
|
|
|
42
42
|
product_id,
|
|
43
43
|
type,
|
|
44
44
|
created_at,
|
|
45
|
+
published_at: created_at,
|
|
45
46
|
updated_at,
|
|
46
47
|
title,
|
|
47
48
|
cover_image,
|
package/src/helpers.js
CHANGED
|
@@ -1,21 +1,49 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import axiosRetry from 'axios-retry';
|
|
1
3
|
import { asNumber, splitObj, stream } from '@miso.ai/server-commons';
|
|
2
|
-
import axios from './axios.js';
|
|
3
4
|
import DataSource from './source/index.js';
|
|
5
|
+
import version from './version.js';
|
|
4
6
|
|
|
5
7
|
const MS_PER_HOUR = 1000 * 60 * 60;
|
|
6
8
|
|
|
7
9
|
const STREAM_OPTIONS = ['offset', 'limit', 'strategy', 'filter', 'transform', 'onLoad'];
|
|
8
10
|
|
|
11
|
+
function createAxios(client) {
|
|
12
|
+
const { auth } = client._options || {};
|
|
13
|
+
const headers = {
|
|
14
|
+
'User-Agent': `MisoWordPressTool/${version}`,
|
|
15
|
+
};
|
|
16
|
+
if (auth) {
|
|
17
|
+
if (typeof auth === 'object' && auth.username && auth.password) {
|
|
18
|
+
auth = `${auth.username}:${auth.password}`;
|
|
19
|
+
}
|
|
20
|
+
if (typeof auth !== 'string') {
|
|
21
|
+
throw new TypeError(`Invalid auth: must me a string or an object.`);
|
|
22
|
+
}
|
|
23
|
+
headers['Authorization'] = 'Basic ' + Buffer.from(auth).toString('base64');
|
|
24
|
+
}
|
|
25
|
+
const instance = axios.create({
|
|
26
|
+
headers,
|
|
27
|
+
});
|
|
28
|
+
axiosRetry(instance, { retries: 5, retryDelay: count => count * 300 });
|
|
29
|
+
return instance;
|
|
30
|
+
}
|
|
31
|
+
|
|
9
32
|
export default class Helpers {
|
|
10
33
|
|
|
11
34
|
constructor(client) {
|
|
12
35
|
this._start = Date.now();
|
|
13
36
|
this._client = client;
|
|
37
|
+
this._axios = createAxios(client);
|
|
14
38
|
this.url = new Url(this);
|
|
15
39
|
this._samples = {};
|
|
16
40
|
this.debug = this.debug.bind(this);
|
|
17
41
|
}
|
|
18
42
|
|
|
43
|
+
get axios() {
|
|
44
|
+
return this._axios;
|
|
45
|
+
}
|
|
46
|
+
|
|
19
47
|
async stream(resource, options) {
|
|
20
48
|
const [streamOptions, sourceOptions] = splitObj(options, STREAM_OPTIONS);
|
|
21
49
|
const source = new DataSource(this, resource, sourceOptions);
|
|
@@ -32,7 +60,7 @@ export default class Helpers {
|
|
|
32
60
|
|
|
33
61
|
async _fetchSample(resource) {
|
|
34
62
|
const url = await this.url.build(resource, { page: 0, pageSize: 1 });
|
|
35
|
-
const { data, headers } = await axios.get(url);
|
|
63
|
+
const { data, headers } = await this.axios.get(url);
|
|
36
64
|
if (!data.length) {
|
|
37
65
|
throw new Error(`No record of ${resource} avaliable`);
|
|
38
66
|
}
|
|
@@ -71,7 +99,7 @@ export default class Helpers {
|
|
|
71
99
|
|
|
72
100
|
async _fetchTaxonomies() {
|
|
73
101
|
const url = await this.url.build('taxonomies');
|
|
74
|
-
const { data } = await axios.get(url);
|
|
102
|
+
const { data } = await this.axios.get(url);
|
|
75
103
|
this.debug(`Fetched taxonomies.`);
|
|
76
104
|
return Object.values(data);
|
|
77
105
|
}
|
|
@@ -82,7 +110,7 @@ export default class Helpers {
|
|
|
82
110
|
|
|
83
111
|
async count(resource, { offset: _, ...options } = {}) {
|
|
84
112
|
const url = await this.url.build(resource, { ...options, page: 0, pageSize: 1 });
|
|
85
|
-
const { headers } = await axios.get(url);
|
|
113
|
+
const { headers } = await this.axios.get(url);
|
|
86
114
|
return asNumber(headers['x-wp-total']);
|
|
87
115
|
}
|
|
88
116
|
|
|
@@ -92,7 +120,7 @@ export default class Helpers {
|
|
|
92
120
|
|
|
93
121
|
async countUrl(url) {
|
|
94
122
|
url = await this.url.append(url, { page: 0, pageSize: 1 });
|
|
95
|
-
const { headers } = await axios.get(url);
|
|
123
|
+
const { headers } = await this.axios.get(url);
|
|
96
124
|
return asNumber(headers['x-wp-total']);
|
|
97
125
|
}
|
|
98
126
|
|
|
@@ -134,16 +162,19 @@ class Url {
|
|
|
134
162
|
// modifiedAfter, modifiedBefore is supported since WordPress 5.7
|
|
135
163
|
// https://make.wordpress.org/core/2021/02/23/rest-api-changes-in-wordpress-5-7/
|
|
136
164
|
async append(url, options = {}) {
|
|
137
|
-
const { after, before, order, orderBy, page, pageSize, offset, include, exclude } = options;
|
|
165
|
+
const { after, before, modifiedAfter, modifiedBefore, order, orderBy, page, pageSize, offset, include, exclude } = options;
|
|
166
|
+
let { fields } = options;
|
|
138
167
|
const params = [];
|
|
139
168
|
|
|
140
169
|
// TODO: support single id
|
|
141
170
|
|
|
142
171
|
// The date is compared against site's local time, not UTC, so we have to work on timezone offset
|
|
143
|
-
if (has(after) || has(before)) {
|
|
172
|
+
if (has(after) || has(before) || has(modifiedAfter) || has(modifiedBefore)) {
|
|
144
173
|
const utcOffset = await this._helpers.utcOffsetInMs();
|
|
145
174
|
has(after) && params.push(`after=${toISOString(after, utcOffset)}`);
|
|
146
175
|
has(before) && params.push(`before=${toISOString(before, utcOffset)}`);
|
|
176
|
+
has(modifiedAfter) && params.push(`modified_after=${toISOString(modifiedAfter, utcOffset)}`);
|
|
177
|
+
has(modifiedBefore) && params.push(`modified_before=${toISOString(modifiedBefore, utcOffset)}`);
|
|
147
178
|
}
|
|
148
179
|
|
|
149
180
|
has(order) && params.push(`order=${order}`);
|
|
@@ -153,6 +184,12 @@ class Url {
|
|
|
153
184
|
has(offset) && params.push(`offset=${offset}`);
|
|
154
185
|
has(include) && include.length && params.push(`include=${joinIds(include)}`);
|
|
155
186
|
has(exclude) && exclude.length && params.push(`exclude=${joinIds(exclude)}`);
|
|
187
|
+
if (has(fields) && fields.length) {
|
|
188
|
+
if (has(before) && !fields.includes('modified_gmt')) {
|
|
189
|
+
fields = [...fields, 'modified_gmt'];
|
|
190
|
+
}
|
|
191
|
+
params.push(`_fields=${fields.join(',')}`);
|
|
192
|
+
}
|
|
156
193
|
|
|
157
194
|
const head = params.length === 0 ? '' : url.indexOf('?') < 0 ? '?' : '&';
|
|
158
195
|
return `${url}${head}${params.join('&')}`;
|
package/src/source/base.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import axios from '../axios.js';
|
|
2
|
-
|
|
3
1
|
export default class WordPressDataSource {
|
|
4
2
|
|
|
5
3
|
constructor(helpers, resource, options = {}) {
|
|
@@ -32,14 +30,17 @@ export default class WordPressDataSource {
|
|
|
32
30
|
this._debug(`[WordPressDataSource] request ${url}`);
|
|
33
31
|
const response = await this._axiosGet(url);
|
|
34
32
|
this._debug(`[WordPressDataSource] response ${response.status} ${url}`);
|
|
35
|
-
return this._process(response);
|
|
33
|
+
return this._process(response, { url });
|
|
36
34
|
}
|
|
37
35
|
|
|
38
|
-
_process({ status, data }) {
|
|
36
|
+
_process({ status, data }, { url }) {
|
|
39
37
|
if (status >= 400 && status < 500 && data.code === 'rest_post_invalid_page_number') {
|
|
40
38
|
// out of bound, so there is no more data
|
|
41
39
|
return { data: [], terminate: true };
|
|
42
40
|
}
|
|
41
|
+
if (!Array.isArray(data)) {
|
|
42
|
+
throw new Error(`Unexpected response from WordPress API for ${url}. Expected an array of objects: ${data}`);
|
|
43
|
+
}
|
|
43
44
|
if (!this._options.preserveLinks) {
|
|
44
45
|
data = data.map(this._helpers.removeLinks);
|
|
45
46
|
}
|
|
@@ -58,7 +59,7 @@ export default class WordPressDataSource {
|
|
|
58
59
|
|
|
59
60
|
async _axiosGet(url) {
|
|
60
61
|
try {
|
|
61
|
-
return await axios.get(url);
|
|
62
|
+
return await this._helpers.axios.get(url);
|
|
62
63
|
} catch(error) {
|
|
63
64
|
if (error.response) {
|
|
64
65
|
return error.response;
|
package/src/source/paged.js
CHANGED
|
@@ -50,8 +50,8 @@ export default class PagedWordPressDataSource extends WordPressDataSource {
|
|
|
50
50
|
return total;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
_process({ status, data, headers }) {
|
|
54
|
-
const result = super._process({ status, data, headers });
|
|
53
|
+
_process({ status, data, headers }, meta) {
|
|
54
|
+
const result = super._process({ status, data, headers }, meta);
|
|
55
55
|
const total = asNumber(headers['x-wp-total']);
|
|
56
56
|
if (total !== undefined) {
|
|
57
57
|
result.total = total;
|
package/src/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export default '0.6.3-beta.
|
|
1
|
+
export default '0.6.3-beta.10';
|