druxt 0.10.0 → 0.14.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,108 @@
1
1
  # druxt
2
2
 
3
+ ## 0.14.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 85fff42: Added debug mode and Axios request logging.
8
+
9
+ ```
10
+ export default {
11
+ druxt: {
12
+ // Enable debug log messages.
13
+ debug: true,
14
+ }
15
+ }
16
+ ```
17
+
18
+ - 39e2e2e: Added ability to render readable JSON with the DruxtDebug component
19
+
20
+ ```jsx
21
+ <DruxtDebug :json="{ data: [{ one: true, two: false }] }" />
22
+ ```
23
+
24
+ - 9c33d82: Made summary prop optional on DruxtDebug component
25
+ - 45bc0b9: Added Druxt version to Nuxt badge
26
+
27
+ ## 0.13.0
28
+
29
+ ### Minor Changes
30
+
31
+ - 77ab204: Added ability to proxy the API
32
+
33
+ ```js
34
+ export default {
35
+ druxt: {
36
+ proxy: {
37
+ api: true
38
+ }
39
+ }
40
+ };
41
+ ```
42
+
43
+ Creates two proxy entries:
44
+
45
+ - The JSON:API: `${ENDPOINT}` -> `${BASEURL}${ENDPOINT}`
46
+ - The Decoupled Router:`/router/translate-path` -> `${BASEURL}/router/translate-path`
47
+
48
+ - 77ab204: Added ability to proxy the Drupal file system
49
+
50
+ ```js
51
+ export default {
52
+ druxt: {
53
+ proxy: {
54
+ files: "default"
55
+ }
56
+ }
57
+ };
58
+ ```
59
+
60
+ Creates a proxy entry:
61
+
62
+ - `/sites/${PATH}/files` -> `${BASEURL}/site/${PATH}/files`
63
+
64
+ - c4457e1: Changed template injected module components to not use a DruxtWrapper component by default.
65
+ - e7b1533: Refactored DruxtModule fetch hooks
66
+
67
+ ## 0.12.0
68
+
69
+ ### Minor Changes
70
+
71
+ - 897dcbc: Added createResource method to DruxtClient
72
+
73
+ ```js
74
+ this.$druxt.createResource({ type, attributes: {}, relationships: {} });
75
+ ```
76
+
77
+ - 897dcbc: Added updateResource method to DruxtClient
78
+
79
+ ```js
80
+ await this.$druxt.updateResource({
81
+ type,
82
+ id,
83
+ attributes: {},
84
+ relationships: {}
85
+ });
86
+ ```
87
+
88
+ - 4504a2f: Added getRelated() method
89
+
90
+ ```js
91
+ await this.$druxt.getRelated(type, id, related);
92
+ ```
93
+
94
+ - e3e634c: Enabled Components auto-discovery by default
95
+
96
+ ## 0.11.0
97
+
98
+ ### Minor Changes
99
+
100
+ - dae345e: Added Druxt modules settings to `$druxt.settings`
101
+
102
+ ### Patch Changes
103
+
104
+ - 75ff8a9: Fixed issue with Axios settings and Storybook
105
+
3
106
  ## 0.10.0
4
107
 
5
108
  ### Minor Changes
@@ -1,6 +1,9 @@
1
1
  <template>
2
2
  <details v-if="$nuxt.context.isDev">
3
3
  <summary v-text="title" />
4
+ <pre v-if="json"><!--
5
+ --><code>{{ JSON.stringify(json, null, ' ') }}</code><!--
6
+ --></pre>
4
7
  <slot />
5
8
  </details>
6
9
 
@@ -10,19 +13,36 @@
10
13
  <script>
11
14
 
12
15
  /**
13
- * Debug component for use by Druxt modules.
16
+ * Renders Debug data only when Nuxt is in development mode.
17
+ *
18
+ * @example @lang vue
19
+ * <DruxtDebug :json="entity" />
14
20
  */
15
21
  export default {
16
22
  /** */
17
23
  props: {
18
24
  /**
19
- * Text to display in summary.
25
+ * JSON data to format for readability.
26
+ *
27
+ * @type {*}
28
+ * @example @lang vue
29
+ * <DruxtDebug :json="{ data: [{ one: true, two: false }] }" />
30
+ */
31
+ json: {
32
+ type: [Array, Boolean, Object, Number, String],
33
+ default: undefined
34
+ },
35
+
36
+ /**
37
+ * Text to use for debug summary.
20
38
  *
21
39
  * @type {string}
40
+ * @example @lang vue
41
+ * <DruxtDebug summary="Foo bar" />
22
42
  */
23
43
  summary: {
24
44
  type: String,
25
- required: true,
45
+ default: 'Debug',
26
46
  },
27
47
  },
28
48
 
@@ -43,7 +63,9 @@ export default {
43
63
  *
44
64
  * @return {string}
45
65
  */
46
- title: ({ module, summary }) => `[${module.$options._componentTag}] ${summary}`,
66
+ title: ({ module, summary }) => module.$options._componentTag
67
+ ? `[${module.$options._componentTag}] ${summary}`
68
+ : summary,
47
69
  },
48
70
  };
49
71
  </script>
@@ -38,12 +38,25 @@ export default {
38
38
  default: null,
39
39
  },
40
40
 
41
+ /**
42
+ * The wrapper component configuration.
43
+ *
44
+ * Used to set the wrapper component, class, style and propsData.
45
+ *
46
+ * @example
47
+ * <DruxtModule
48
+ * :wrapper="{
49
+ * component: 'MyWrapper',
50
+ * class: 'wrapper',
51
+ * propsData: { foo: 'bar' }
52
+ * }"
53
+ * />
54
+ *
55
+ * @type {(Boolean|Object)}
56
+ */
41
57
  wrapper: {
42
- type: Object,
43
- default: () => ({
44
- component: 'div',
45
- propsData: {},
46
- })
58
+ type: [Boolean, Object],
59
+ default: () => undefined
47
60
  },
48
61
  },
49
62
 
@@ -92,19 +105,44 @@ export default {
92
105
  return false
93
106
  }
94
107
 
108
+ // Fetch configuration.
109
+ if ((this.$options.druxt || {}).fetchConfig) {
110
+ await this.$options.druxt.fetchConfig.call(this)
111
+ }
112
+
95
113
  // Build wrapper component object.
96
- const options = this.getModuleComponents()
114
+ let options = []
115
+ const hasDefaultTemplate = !!(this.$vnode.data.scopedSlots || {}).default
116
+ // Load wrapper components if:
117
+ if (
118
+ // No default template and wrapper isn't false OR
119
+ (!hasDefaultTemplate && this.wrapper !== false) ||
120
+ // Default tempalte and wrapper is set
121
+ (hasDefaultTemplate && this.wrapper)
122
+ ) {
123
+ options = this.getModuleComponents()
124
+ }
97
125
  let component = {
98
126
  is: (((options.filter(o => o.global) || [])[0] || {}).name || 'DruxtWrapper'),
99
127
  options: options.map(o => o.name) || [],
100
128
  }
101
129
 
102
- // Get scoped slots.
103
- component.slots = Object.keys(this.getScopedSlots())
104
-
105
130
  // Get wrapper data.
106
131
  const wrapperData = await this.getWrapperData(component.is)
132
+
133
+ // Build module settings.
107
134
  component.settings = wrapperData.druxt || {}
135
+ if ((this.$options.druxt || {}).settings) {
136
+ component.settings = this.$options.druxt.settings(this, component.settings)
137
+ }
138
+
139
+ // Fetch resource.
140
+ if ((this.$options.druxt || {}).fetchData) {
141
+ await this.$options.druxt.fetchData.call(this, component.settings)
142
+ }
143
+
144
+ // Get scoped slots.
145
+ component.slots = Object.keys(this.getScopedSlots())
108
146
 
109
147
  // Build wrapper component propsData.
110
148
  component = { ...component, ...this.getModulePropsData(wrapperData.props) }
@@ -140,12 +178,14 @@ export default {
140
178
  * @returns {Components}
141
179
  */
142
180
  getModuleComponents() {
181
+ // Ensure that the Druxt module component has `druxt.componentOptions`.
143
182
  if (!(this.$options.druxt || {}).componentOptions) {
144
183
  return []
145
184
  }
146
-
147
185
  const options = this.$options.druxt.componentOptions.call(this, this)
148
- if (!options || !options.length) {
186
+
187
+ // Ensure that there available component options are returned.
188
+ if (!(options || []).length) {
149
189
  return []
150
190
  }
151
191
 
@@ -290,20 +330,27 @@ export default {
290
330
  const self = this
291
331
 
292
332
  const wrapperData = {
293
- class: this.wrapper.class || undefined,
294
- style: this.wrapper.style || undefined,
295
- props: this.wrapper.propsData,
333
+ class: (this.wrapper || {}).class || undefined,
334
+ style: (this.wrapper || {}).style || undefined,
335
+ props: (this.wrapper || {}).propsData || undefined,
296
336
  }
297
337
 
298
338
  // Return only wrapper if fetch state is still pending.
299
339
  if (this.$fetchState.pending) {
300
- return h(this.wrapper.component, wrapperData)
340
+ return h((this.wrapper || {}).component || 'div', wrapperData)
301
341
  }
302
342
 
303
- // Return wrapped component.
343
+ // Prepare attributes.
304
344
  const attrs = { ...this.component.$attrs, ...this.$attrs }
305
345
  delete attrs['data-fetch-key']
306
- return h(this.wrapper.component, wrapperData, [
346
+
347
+ // Unwrap default template based component if required.
348
+ if ((this.$scopedSlots.default && !this.wrapper) || this.wrapper === false) {
349
+ this.component.is = 'DruxtWrapper'
350
+ }
351
+
352
+ // Return component.
353
+ return h((this.wrapper || {}).component || 'div', wrapperData, [
307
354
  h(this.component.is, {
308
355
  attrs,
309
356
  on: {
package/dist/druxt.esm.js CHANGED
@@ -2,46 +2,169 @@ import chalk from 'chalk';
2
2
  import { join, resolve } from 'path';
3
3
  import axios from 'axios';
4
4
  import { stringify } from 'querystring';
5
+ import consola from 'consola';
5
6
  import merge from 'deepmerge';
6
7
  import md5 from 'md5';
7
8
  import Vue from 'vue';
8
9
  import { DrupalJsonApiParams } from 'drupal-jsonapi-params';
9
10
 
11
+ var name = "druxt";
12
+ var version = "0.14.0";
13
+ var description = "The Fully Decoupled Drupal Framework for Nuxt.js.";
14
+ var keywords = [
15
+ "cms",
16
+ "decoupled",
17
+ "drupal",
18
+ "druxt",
19
+ "headless",
20
+ "jsonapi",
21
+ "json:api",
22
+ "nuxt",
23
+ "module",
24
+ "vue"
25
+ ];
26
+ var homepage = "https://druxtjs.org";
27
+ var bugs = {
28
+ url: "https://github.com/druxt/druxt.js/issues"
29
+ };
30
+ var repository = {
31
+ type: "git",
32
+ url: "git+https://github.com/druxt/druxt.js"
33
+ };
34
+ var license = "MIT";
35
+ var exports = {
36
+ ".": {
37
+ require: "./dist/druxt.ssr.js",
38
+ "import": "./dist/druxt.esm.js"
39
+ },
40
+ "./components/*": "./dist/components/*"
41
+ };
42
+ var main = "dist/druxt.ssr.js";
43
+ var module = "dist/druxt.esm.js";
44
+ var files = [
45
+ "dist",
46
+ "templates"
47
+ ];
48
+ var dependencies = {
49
+ "@nuxtjs/proxy": "^2.1.0",
50
+ axios: "^0.21.1",
51
+ chalk: "^4.1.2",
52
+ deepmerge: "^4.2.2",
53
+ "drupal-jsonapi-params": "^1.2.1",
54
+ md5: "^2.3.0",
55
+ querystring: "^0.2.0",
56
+ scule: "^0.2.0"
57
+ };
58
+ var peerDependencies = {
59
+ consola: "*"
60
+ };
61
+ var optionalDependencies = {
62
+ "core-js": "^3.16.1",
63
+ vue: "^2.6.14",
64
+ vuex: "^3.6.2"
65
+ };
66
+ var publishConfig = {
67
+ access: "public"
68
+ };
69
+ var meta = {
70
+ name: name,
71
+ version: version,
72
+ description: description,
73
+ keywords: keywords,
74
+ homepage: homepage,
75
+ bugs: bugs,
76
+ repository: repository,
77
+ license: license,
78
+ exports: exports,
79
+ main: main,
80
+ module: module,
81
+ files: files,
82
+ dependencies: dependencies,
83
+ peerDependencies: peerDependencies,
84
+ optionalDependencies: optionalDependencies,
85
+ publishConfig: publishConfig
86
+ };
87
+
10
88
  const DruxtNuxtModule = function(moduleOptions = {}) {
89
+ var _a;
11
90
  const options = {
12
91
  endpoint: "/jsonapi",
13
92
  ...moduleOptions,
14
93
  ...(this.options || {}).druxt
15
94
  };
95
+ if (options.proxy) {
96
+ const proxies = {};
97
+ if ((options.proxy || {}).api) {
98
+ proxies[options.endpoint] = options.baseUrl;
99
+ proxies["/router/translate-path"] = options.baseUrl;
100
+ }
101
+ if ((options.proxy || {}).files) {
102
+ const filesPath = typeof options.proxy.files === "string" ? options.proxy.files : "default";
103
+ proxies[`/sites/${filesPath}/files`] = options.baseUrl;
104
+ }
105
+ if (this.options.proxy) {
106
+ if (Array.isArray(this.options.proxy)) {
107
+ this.options.proxy = [
108
+ ...Object.keys(proxies).map((path) => `${options.baseUrl}${path}`),
109
+ ...this.options.proxy
110
+ ];
111
+ } else {
112
+ this.options.proxy = {
113
+ ...proxies,
114
+ ...this.options.proxy
115
+ };
116
+ }
117
+ } else {
118
+ this.options.proxy = proxies;
119
+ }
120
+ this.addModule("@nuxtjs/proxy");
121
+ }
16
122
  this.nuxt.hook("components:dirs", (dirs) => {
17
123
  dirs.push({ path: join(__dirname, "components") });
18
124
  });
19
125
  this.addPlugin({
20
- src: resolve(__dirname, "../nuxt/plugin.js"),
126
+ src: resolve(__dirname, "../templates/plugin.js"),
21
127
  fileName: "druxt.js",
22
128
  options
23
129
  });
24
130
  this.addPlugin({
25
- src: resolve(__dirname, "../nuxt/store.js"),
131
+ src: resolve(__dirname, "../templates/store.js"),
26
132
  fileName: "store/druxt.js",
27
133
  options
28
134
  });
29
135
  this.options.store = true;
30
- this.options.cli.badgeMessages.push(`${chalk.bold("Druxt API:")} ${chalk.blue.underline(options.baseUrl + options.endpoint)}`);
136
+ this.options.components = (_a = this.options.components) != null ? _a : true;
137
+ this.options.cli.badgeMessages.push(`${chalk.blue.bold("Druxt")} @ v${meta.version}`);
138
+ this.options.cli.badgeMessages.push(`${chalk.bold("API:")} ${chalk.blue.underline(options.baseUrl + options.endpoint)}`);
31
139
  };
32
- DruxtNuxtModule.meta = require("../package.json");
140
+ DruxtNuxtModule.meta = meta;
33
141
 
34
142
  class DruxtClient {
35
143
  constructor(baseUrl, options = {}) {
144
+ this.log = consola.create({ defaults: {
145
+ tag: "DruxtClient"
146
+ } });
36
147
  if (!baseUrl) {
37
148
  throw new Error("The 'baseUrl' parameter is required.");
38
149
  }
39
- let axiosSettings = { baseURL: baseUrl };
150
+ let axiosSettings = {};
151
+ if (baseUrl && !(options.proxy || {}).api) {
152
+ axiosSettings.baseURL = baseUrl;
153
+ }
40
154
  if (typeof options.axios === "object") {
41
155
  axiosSettings = Object.assign(axiosSettings, options.axios);
42
- delete options.axios;
43
156
  }
44
157
  this.axios = axios.create(axiosSettings);
158
+ if (options.debug) {
159
+ const log = this.log;
160
+ this.axios.interceptors.request.use((config) => {
161
+ log.info(config.url);
162
+ return config;
163
+ }, (error) => {
164
+ log.error(error);
165
+ return Promise.reject(error);
166
+ });
167
+ }
45
168
  this.options = {
46
169
  endpoint: "/jsonapi",
47
170
  jsonapiResourceConfig: "jsonapi_resource_config--jsonapi_resource_config",
@@ -89,6 +212,26 @@ class DruxtClient {
89
212
  }
90
213
  }
91
214
  }
215
+ async createResource(resource) {
216
+ if (resource.id) {
217
+ return this.updateResource(resource);
218
+ }
219
+ const { href } = await this.getIndex(resource.type);
220
+ if (!href) {
221
+ return false;
222
+ }
223
+ let response;
224
+ try {
225
+ response = await this.axios.post(href, { data: resource }, {
226
+ headers: {
227
+ "Content-Type": "application/vnd.api+json"
228
+ }
229
+ });
230
+ } catch (err) {
231
+ response = (err.response || {}).data || err.message;
232
+ }
233
+ return response;
234
+ }
92
235
  async getCollection(type, query) {
93
236
  const { href } = await this.getIndex(type);
94
237
  if (!href) {
@@ -117,10 +260,14 @@ class DruxtClient {
117
260
  if (this.index && resource) {
118
261
  return this.index[resource] ? this.index[resource] : false;
119
262
  }
120
- const index = await this.axios.get(this.options.endpoint);
121
- this.index = index.data.links;
122
- if (this.index[this.options.jsonapiResourceConfig]) {
123
- const resources = await this.axios.get(this.index[this.options.jsonapiResourceConfig].href);
263
+ let index = ((await this.axios.get(this.options.endpoint) || {}).data || {}).links;
264
+ const baseUrl = this.options.baseUrl;
265
+ index = Object.fromEntries(Object.entries(index).map(([key, value]) => {
266
+ value.href = value.href.replace(baseUrl, "");
267
+ return [key, value];
268
+ }));
269
+ if (index[this.options.jsonapiResourceConfig]) {
270
+ const resources = await this.axios.get(index[this.options.jsonapiResourceConfig].href);
124
271
  for (const resourceType in resources.data.data) {
125
272
  const resource2 = resources.data.data[resourceType];
126
273
  const internal = resource2.attributes.drupal_internal__id.split("--");
@@ -131,17 +278,35 @@ class DruxtClient {
131
278
  resourceFields: resource2.attributes.resourceFields
132
279
  };
133
280
  const id = [item.entityType, item.bundle].join("--");
134
- this.index[id] = {
281
+ index[id] = {
135
282
  ...item,
136
- ...this.index[id]
283
+ ...index[id]
137
284
  };
138
285
  }
139
286
  }
287
+ this.index = index;
140
288
  if (resource) {
141
- return this.index[resource] ? this.index[resource] : false;
289
+ const response = this.index[resource] ? this.index[resource] : false;
290
+ return response;
142
291
  }
143
292
  return this.index;
144
293
  }
294
+ async getRelated(type, id, related, query) {
295
+ if (!id || !type || !related) {
296
+ return false;
297
+ }
298
+ let { href } = await this.getIndex(type);
299
+ if (!href) {
300
+ href = this.options.endpoint + "/" + type.replace("--", "/");
301
+ }
302
+ const url = this.buildQueryUrl(`${href}/${id}/${related}`, query);
303
+ try {
304
+ const related2 = await this.axios.get(url);
305
+ return related2.data;
306
+ } catch (e) {
307
+ return false;
308
+ }
309
+ }
145
310
  async getResource(type, id, query) {
146
311
  if (!id || !type) {
147
312
  return false;
@@ -158,6 +323,24 @@ class DruxtClient {
158
323
  return false;
159
324
  }
160
325
  }
326
+ async updateResource(resource) {
327
+ const { href } = await this.getIndex(resource.type);
328
+ if (!href) {
329
+ return false;
330
+ }
331
+ const url = [href, resource.id].join("/");
332
+ let response;
333
+ try {
334
+ response = await this.axios.patch(url, { data: resource }, {
335
+ headers: {
336
+ "Content-Type": "application/vnd.api+json"
337
+ }
338
+ });
339
+ } catch (err) {
340
+ response = (err.response || {}).data || err.message;
341
+ }
342
+ return response;
343
+ }
161
344
  }
162
345
 
163
346
  const getDrupalJsonApiParams = (query) => {
package/dist/druxt.ssr.js CHANGED
@@ -6,6 +6,7 @@ const chalk = require('chalk');
6
6
  const path = require('path');
7
7
  const axios = require('axios');
8
8
  const querystring = require('querystring');
9
+ const consola = require('consola');
9
10
  const merge = require('deepmerge');
10
11
  const md5 = require('md5');
11
12
  const Vue = require('vue');
@@ -15,45 +16,168 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
15
16
 
16
17
  const chalk__default = /*#__PURE__*/_interopDefaultLegacy(chalk);
17
18
  const axios__default = /*#__PURE__*/_interopDefaultLegacy(axios);
19
+ const consola__default = /*#__PURE__*/_interopDefaultLegacy(consola);
18
20
  const merge__default = /*#__PURE__*/_interopDefaultLegacy(merge);
19
21
  const md5__default = /*#__PURE__*/_interopDefaultLegacy(md5);
20
22
  const Vue__default = /*#__PURE__*/_interopDefaultLegacy(Vue);
21
23
 
24
+ var name = "druxt";
25
+ var version = "0.14.0";
26
+ var description = "The Fully Decoupled Drupal Framework for Nuxt.js.";
27
+ var keywords = [
28
+ "cms",
29
+ "decoupled",
30
+ "drupal",
31
+ "druxt",
32
+ "headless",
33
+ "jsonapi",
34
+ "json:api",
35
+ "nuxt",
36
+ "module",
37
+ "vue"
38
+ ];
39
+ var homepage = "https://druxtjs.org";
40
+ var bugs = {
41
+ url: "https://github.com/druxt/druxt.js/issues"
42
+ };
43
+ var repository = {
44
+ type: "git",
45
+ url: "git+https://github.com/druxt/druxt.js"
46
+ };
47
+ var license = "MIT";
48
+ var exports$1 = {
49
+ ".": {
50
+ require: "./dist/druxt.ssr.js",
51
+ "import": "./dist/druxt.esm.js"
52
+ },
53
+ "./components/*": "./dist/components/*"
54
+ };
55
+ var main = "dist/druxt.ssr.js";
56
+ var module$1 = "dist/druxt.esm.js";
57
+ var files = [
58
+ "dist",
59
+ "templates"
60
+ ];
61
+ var dependencies = {
62
+ "@nuxtjs/proxy": "^2.1.0",
63
+ axios: "^0.21.1",
64
+ chalk: "^4.1.2",
65
+ deepmerge: "^4.2.2",
66
+ "drupal-jsonapi-params": "^1.2.1",
67
+ md5: "^2.3.0",
68
+ querystring: "^0.2.0",
69
+ scule: "^0.2.0"
70
+ };
71
+ var peerDependencies = {
72
+ consola: "*"
73
+ };
74
+ var optionalDependencies = {
75
+ "core-js": "^3.16.1",
76
+ vue: "^2.6.14",
77
+ vuex: "^3.6.2"
78
+ };
79
+ var publishConfig = {
80
+ access: "public"
81
+ };
82
+ const meta = {
83
+ name: name,
84
+ version: version,
85
+ description: description,
86
+ keywords: keywords,
87
+ homepage: homepage,
88
+ bugs: bugs,
89
+ repository: repository,
90
+ license: license,
91
+ exports: exports$1,
92
+ main: main,
93
+ module: module$1,
94
+ files: files,
95
+ dependencies: dependencies,
96
+ peerDependencies: peerDependencies,
97
+ optionalDependencies: optionalDependencies,
98
+ publishConfig: publishConfig
99
+ };
100
+
22
101
  const DruxtNuxtModule = function(moduleOptions = {}) {
102
+ var _a;
23
103
  const options = {
24
104
  endpoint: "/jsonapi",
25
105
  ...moduleOptions,
26
106
  ...(this.options || {}).druxt
27
107
  };
108
+ if (options.proxy) {
109
+ const proxies = {};
110
+ if ((options.proxy || {}).api) {
111
+ proxies[options.endpoint] = options.baseUrl;
112
+ proxies["/router/translate-path"] = options.baseUrl;
113
+ }
114
+ if ((options.proxy || {}).files) {
115
+ const filesPath = typeof options.proxy.files === "string" ? options.proxy.files : "default";
116
+ proxies[`/sites/${filesPath}/files`] = options.baseUrl;
117
+ }
118
+ if (this.options.proxy) {
119
+ if (Array.isArray(this.options.proxy)) {
120
+ this.options.proxy = [
121
+ ...Object.keys(proxies).map((path) => `${options.baseUrl}${path}`),
122
+ ...this.options.proxy
123
+ ];
124
+ } else {
125
+ this.options.proxy = {
126
+ ...proxies,
127
+ ...this.options.proxy
128
+ };
129
+ }
130
+ } else {
131
+ this.options.proxy = proxies;
132
+ }
133
+ this.addModule("@nuxtjs/proxy");
134
+ }
28
135
  this.nuxt.hook("components:dirs", (dirs) => {
29
136
  dirs.push({ path: path.join(__dirname, "components") });
30
137
  });
31
138
  this.addPlugin({
32
- src: path.resolve(__dirname, "../nuxt/plugin.js"),
139
+ src: path.resolve(__dirname, "../templates/plugin.js"),
33
140
  fileName: "druxt.js",
34
141
  options
35
142
  });
36
143
  this.addPlugin({
37
- src: path.resolve(__dirname, "../nuxt/store.js"),
144
+ src: path.resolve(__dirname, "../templates/store.js"),
38
145
  fileName: "store/druxt.js",
39
146
  options
40
147
  });
41
148
  this.options.store = true;
42
- this.options.cli.badgeMessages.push(`${chalk__default['default'].bold("Druxt API:")} ${chalk__default['default'].blue.underline(options.baseUrl + options.endpoint)}`);
149
+ this.options.components = (_a = this.options.components) != null ? _a : true;
150
+ this.options.cli.badgeMessages.push(`${chalk__default['default'].blue.bold("Druxt")} @ v${meta.version}`);
151
+ this.options.cli.badgeMessages.push(`${chalk__default['default'].bold("API:")} ${chalk__default['default'].blue.underline(options.baseUrl + options.endpoint)}`);
43
152
  };
44
- DruxtNuxtModule.meta = require("../package.json");
153
+ DruxtNuxtModule.meta = meta;
45
154
 
46
155
  class DruxtClient {
47
156
  constructor(baseUrl, options = {}) {
157
+ this.log = consola__default['default'].create({ defaults: {
158
+ tag: "DruxtClient"
159
+ } });
48
160
  if (!baseUrl) {
49
161
  throw new Error("The 'baseUrl' parameter is required.");
50
162
  }
51
- let axiosSettings = { baseURL: baseUrl };
163
+ let axiosSettings = {};
164
+ if (baseUrl && !(options.proxy || {}).api) {
165
+ axiosSettings.baseURL = baseUrl;
166
+ }
52
167
  if (typeof options.axios === "object") {
53
168
  axiosSettings = Object.assign(axiosSettings, options.axios);
54
- delete options.axios;
55
169
  }
56
170
  this.axios = axios__default['default'].create(axiosSettings);
171
+ if (options.debug) {
172
+ const log = this.log;
173
+ this.axios.interceptors.request.use((config) => {
174
+ log.info(config.url);
175
+ return config;
176
+ }, (error) => {
177
+ log.error(error);
178
+ return Promise.reject(error);
179
+ });
180
+ }
57
181
  this.options = {
58
182
  endpoint: "/jsonapi",
59
183
  jsonapiResourceConfig: "jsonapi_resource_config--jsonapi_resource_config",
@@ -101,6 +225,26 @@ class DruxtClient {
101
225
  }
102
226
  }
103
227
  }
228
+ async createResource(resource) {
229
+ if (resource.id) {
230
+ return this.updateResource(resource);
231
+ }
232
+ const { href } = await this.getIndex(resource.type);
233
+ if (!href) {
234
+ return false;
235
+ }
236
+ let response;
237
+ try {
238
+ response = await this.axios.post(href, { data: resource }, {
239
+ headers: {
240
+ "Content-Type": "application/vnd.api+json"
241
+ }
242
+ });
243
+ } catch (err) {
244
+ response = (err.response || {}).data || err.message;
245
+ }
246
+ return response;
247
+ }
104
248
  async getCollection(type, query) {
105
249
  const { href } = await this.getIndex(type);
106
250
  if (!href) {
@@ -129,10 +273,14 @@ class DruxtClient {
129
273
  if (this.index && resource) {
130
274
  return this.index[resource] ? this.index[resource] : false;
131
275
  }
132
- const index = await this.axios.get(this.options.endpoint);
133
- this.index = index.data.links;
134
- if (this.index[this.options.jsonapiResourceConfig]) {
135
- const resources = await this.axios.get(this.index[this.options.jsonapiResourceConfig].href);
276
+ let index = ((await this.axios.get(this.options.endpoint) || {}).data || {}).links;
277
+ const baseUrl = this.options.baseUrl;
278
+ index = Object.fromEntries(Object.entries(index).map(([key, value]) => {
279
+ value.href = value.href.replace(baseUrl, "");
280
+ return [key, value];
281
+ }));
282
+ if (index[this.options.jsonapiResourceConfig]) {
283
+ const resources = await this.axios.get(index[this.options.jsonapiResourceConfig].href);
136
284
  for (const resourceType in resources.data.data) {
137
285
  const resource2 = resources.data.data[resourceType];
138
286
  const internal = resource2.attributes.drupal_internal__id.split("--");
@@ -143,17 +291,35 @@ class DruxtClient {
143
291
  resourceFields: resource2.attributes.resourceFields
144
292
  };
145
293
  const id = [item.entityType, item.bundle].join("--");
146
- this.index[id] = {
294
+ index[id] = {
147
295
  ...item,
148
- ...this.index[id]
296
+ ...index[id]
149
297
  };
150
298
  }
151
299
  }
300
+ this.index = index;
152
301
  if (resource) {
153
- return this.index[resource] ? this.index[resource] : false;
302
+ const response = this.index[resource] ? this.index[resource] : false;
303
+ return response;
154
304
  }
155
305
  return this.index;
156
306
  }
307
+ async getRelated(type, id, related, query) {
308
+ if (!id || !type || !related) {
309
+ return false;
310
+ }
311
+ let { href } = await this.getIndex(type);
312
+ if (!href) {
313
+ href = this.options.endpoint + "/" + type.replace("--", "/");
314
+ }
315
+ const url = this.buildQueryUrl(`${href}/${id}/${related}`, query);
316
+ try {
317
+ const related2 = await this.axios.get(url);
318
+ return related2.data;
319
+ } catch (e) {
320
+ return false;
321
+ }
322
+ }
157
323
  async getResource(type, id, query) {
158
324
  if (!id || !type) {
159
325
  return false;
@@ -170,6 +336,24 @@ class DruxtClient {
170
336
  return false;
171
337
  }
172
338
  }
339
+ async updateResource(resource) {
340
+ const { href } = await this.getIndex(resource.type);
341
+ if (!href) {
342
+ return false;
343
+ }
344
+ const url = [href, resource.id].join("/");
345
+ let response;
346
+ try {
347
+ response = await this.axios.patch(url, { data: resource }, {
348
+ headers: {
349
+ "Content-Type": "application/vnd.api+json"
350
+ }
351
+ });
352
+ } catch (err) {
353
+ response = (err.response || {}).data || err.message;
354
+ }
355
+ return response;
356
+ }
173
357
  }
174
358
 
175
359
  const getDrupalJsonApiParams = (query) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "druxt",
3
- "version": "0.10.0",
3
+ "version": "0.14.0",
4
4
  "description": "The Fully Decoupled Drupal Framework for Nuxt.js.",
5
5
  "keywords": [
6
6
  "cms",
@@ -23,11 +23,6 @@
23
23
  "url": "git+https://github.com/druxt/druxt.js"
24
24
  },
25
25
  "license": "MIT",
26
- "author": {
27
- "name": "Stuart Clark",
28
- "email": "stuart@realityloop.com",
29
- "url": "https://realityloop.com"
30
- },
31
26
  "exports": {
32
27
  ".": {
33
28
  "require": "./dist/druxt.ssr.js",
@@ -39,9 +34,10 @@
39
34
  "module": "dist/druxt.esm.js",
40
35
  "files": [
41
36
  "dist",
42
- "nuxt"
37
+ "templates"
43
38
  ],
44
39
  "dependencies": {
40
+ "@nuxtjs/proxy": "^2.1.0",
45
41
  "axios": "^0.21.1",
46
42
  "chalk": "^4.1.2",
47
43
  "deepmerge": "^4.2.2",
@@ -50,6 +46,9 @@
50
46
  "querystring": "^0.2.0",
51
47
  "scule": "^0.2.0"
52
48
  },
49
+ "peerDependencies": {
50
+ "consola": "*"
51
+ },
53
52
  "optionalDependencies": {
54
53
  "core-js": "^3.16.1",
55
54
  "vue": "^2.6.14",
@@ -0,0 +1,14 @@
1
+ import { DruxtClient } from 'druxt'
2
+
3
+ export default (context, inject) => {
4
+ const options = <%= JSON.stringify(options) %>
5
+
6
+ // Disable the proxy for server side requests.
7
+ if (!process.client && (options.proxy || {}).api) {
8
+ options.proxy.api = false
9
+ }
10
+
11
+ const druxt = new DruxtClient(options.baseUrl, options)
12
+ druxt.settings = options
13
+ inject('druxt', druxt)
14
+ }
File without changes
package/nuxt/plugin.js DELETED
@@ -1,18 +0,0 @@
1
- import { DruxtClient } from 'druxt'
2
-
3
- export default (context, inject) => {
4
- const baseUrl = '<%= options.baseUrl %>'
5
- const options = {}
6
-
7
- <% if (options.endpoint) { %>
8
- options.endpoint = '<%= options.endpoint %>'
9
- <% } %>
10
-
11
- <% if (typeof options.axios === 'object') { %>
12
- // Axios settings.
13
- options.axios = <%= JSON.stringify(options.axios) %>
14
- <% } %>
15
-
16
- const druxt = new DruxtClient(baseUrl, options)
17
- inject('druxt', druxt)
18
- }