druxt 0.13.0 → 0.17.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.
@@ -0,0 +1,48 @@
1
+ import DruxtDebug from './DruxtDebug.vue'
2
+
3
+ export default {
4
+ title: 'Druxt/DruxtDebug',
5
+ component: DruxtDebug
6
+ }
7
+
8
+ const Template = (args) => ({
9
+ components: { DruxtDebug },
10
+ props: Object.keys(args),
11
+ template: `<DruxtDebug v-bind="$props">Debug information.</DruxtDebug>`
12
+ })
13
+
14
+ export const Default = Template.bind({})
15
+ Default.storyName = 'Default slot'
16
+
17
+ export const Json = Template.bind({})
18
+ Json.args = {
19
+ json: {
20
+ type: '',
21
+ id: '',
22
+ links: {},
23
+ attributes: {},
24
+ relationships: {},
25
+ },
26
+ open: true,
27
+ }
28
+ Json.parameters = {
29
+ docs: {
30
+ storyDescription: 'The **json** prop takes any data and runs it through a basic JSON formatter for improved readability.',
31
+ source: {
32
+ code: '<DruxtDebug :json="entity" open>Debug information</DruxtDebug>'
33
+ },
34
+ },
35
+ }
36
+
37
+ export const Summary = Template.bind({})
38
+ Summary.args = {
39
+ summary: 'A brief debug message'
40
+ }
41
+ Summary.parameters = {
42
+ docs: {
43
+ storyDescription: 'The **summary** prop can be used to provide a quick explanation of the debug component.',
44
+ source: {
45
+ code: `<DruxtDebug summary="${Summary.args.sumary}">Debug information</DruxtDebug>`
46
+ },
47
+ },
48
+ }
@@ -1,6 +1,10 @@
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>
7
+ <!-- @slot Debug content -->
4
8
  <slot />
5
9
  </details>
6
10
 
@@ -10,19 +14,40 @@
10
14
  <script>
11
15
 
12
16
  /**
13
- * Debug component for use by Druxt modules.
17
+ * The DruxtDebug component can be used to render debug information that is
18
+ * visible only when Nuxt is run in development mode.
19
+ *
20
+ * You can render your debug information through the default slot, or via the
21
+ * **json** prop to format your data, or a combination of the two.
22
+ *
23
+ * @example @lang vue
24
+ * <DruxtDebug :json="entity">Debug information</DruxtDebug>
14
25
  */
15
26
  export default {
16
27
  /** */
17
28
  props: {
18
29
  /**
19
- * Text to display in summary.
30
+ * JSON data to format for readability.
31
+ *
32
+ * @type {*}
33
+ * @example @lang vue
34
+ * <DruxtDebug :json="{ data: [{ one: true, two: false }] }" />
35
+ */
36
+ json: {
37
+ type: [Array, Boolean, Object, Number, String],
38
+ default: undefined
39
+ },
40
+
41
+ /**
42
+ * Text to use for debug summary.
20
43
  *
21
44
  * @type {string}
45
+ * @example @lang vue
46
+ * <DruxtDebug summary="Foo bar" />
22
47
  */
23
48
  summary: {
24
49
  type: String,
25
- required: true,
50
+ default: 'Debug',
26
51
  },
27
52
  },
28
53
 
@@ -43,7 +68,9 @@ export default {
43
68
  *
44
69
  * @return {string}
45
70
  */
46
- title: ({ module, summary }) => `[${module.$options._componentTag}] ${summary}`,
71
+ title: ({ module, summary }) => module.$options._componentTag
72
+ ? `[${module.$options._componentTag}] ${summary}`
73
+ : summary,
47
74
  },
48
75
  };
49
76
  </script>
@@ -0,0 +1,126 @@
1
+ import { Canvas, Meta, Story } from '@storybook/addon-docs'
2
+
3
+ <Meta title="Druxt/DruxtModule" />
4
+
5
+ # DruxtModule
6
+
7
+ The DruxtModule component is the core component to be extended by core and
8
+ custom modules.
9
+
10
+ ```js
11
+ import DruxtModule from 'druxt/dist/components/DruxtModule.vue'
12
+ export default {
13
+ extends: DruxtModule
14
+ }
15
+ ```
16
+
17
+ ---
18
+
19
+ ## Fetch config
20
+
21
+ All modules have a two part fetch system available to them; **fetchConfig** and
22
+ **fetchData**.
23
+
24
+ ```js
25
+ async fetchConfig() {
26
+ // Load configuration data here.
27
+ this.config = await this.getResource({...})
28
+ },
29
+ ```
30
+
31
+ Fetch config is used to load information from Drupal to determine the default
32
+ behaviour of that component, as well as to determine the available component
33
+
34
+ ---
35
+
36
+ ## Component options
37
+
38
+ The Druxt Wrapper system looks for available Vue components using a specific
39
+ naming convention, determined by the Druxt module **componentOptions**.
40
+
41
+ This allows for targetted theming of components based on the props or
42
+ configuration data.
43
+
44
+ ```js
45
+ componentOptions: (context) => ([[context.attributes.foo, 'default']]),
46
+ ```
47
+
48
+ ---
49
+
50
+ ## Fetch data
51
+
52
+ After the Component options are determined, the first available component is
53
+ determined, and any exported Druxt settings are loaded and used to fetch the
54
+ main module data.
55
+
56
+ ```js
57
+ async fetchData(settings) {
58
+ // Load data using the settings determine based on the configuration data.
59
+ this.resource = await this.getResource({
60
+ type: this.config.attributes.foo,
61
+ id: this.id,
62
+ query: this.getQuery(settings)
63
+ })
64
+ },
65
+ ```
66
+
67
+ ---
68
+
69
+ ## Props data
70
+
71
+ The **propsData** callback returns the props data for the render Wrapper
72
+ component, making props data available to the frontend developer.
73
+
74
+ ```js
75
+ propsData: (context) => ({ foo: context.config.attributes.foo })
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Slots
81
+
82
+ The **slots** method builds the slots that are made available to the Wrapper
83
+ component. It is expected to return an object of scoped slot functions.
84
+
85
+ ```
86
+ slots(h) {
87
+ return {
88
+ default: () => h('div', ['Hello world']),
89
+ }
90
+ }
91
+ ```
92
+
93
+ ---
94
+
95
+ ### Custom module boilerplate
96
+
97
+ Paste this into a Vue component as a starting point for a custom or contrib
98
+ Druxt module.
99
+
100
+ ```vue
101
+ <script>
102
+ import DruxtModule from 'druxt/dist/components/DruxtModule.vue'
103
+ export default {
104
+ name: 'MyModule',
105
+ extends: DruxtModule
106
+ druxt: {
107
+ async fetchConfig() {
108
+ // Load configuration data here.
109
+ },
110
+ async fetchData(settings) {
111
+ // Load data using the settings determine based on the configuration data.
112
+ },
113
+ // Build nested arrays of component options based on the context.
114
+ componentOptions: (context) => ([['default']]),
115
+ // Map props data from the context.
116
+ propsData: (context) => ({ ...context }),
117
+ // Build slots render arrays.
118
+ slots(h) {
119
+ return {
120
+ default: () => h('div', ['Hello world'])
121
+ }
122
+ }
123
+ }
124
+ }
125
+ </script>
126
+ ```
@@ -6,7 +6,11 @@ import Vue from 'vue'
6
6
  import DruxtWrapper from './DruxtWrapper.vue'
7
7
 
8
8
  /**
9
- * Base component for core and custom Druxt modules.
9
+ * The DruxtModule component is used to make a Druxt module, simply import and
10
+ * extend the component to get started.
11
+ *
12
+ * The component provides access to the Druxt Wrapper theming and fetch system
13
+ * via the druxt settings object.
10
14
  *
11
15
  * @example @lang js
12
16
  * import DruxtModule from 'druxt/dist/components/DruxtModule.vue'
@@ -14,11 +18,18 @@ import DruxtWrapper from './DruxtWrapper.vue'
14
18
  * name: 'DruxtTestModule',
15
19
  * extends: DruxtModule,
16
20
  * druxt: {
17
- * componentOptions: () => ([['wrapper']]),
18
- * propsData: (ctx) => ({
19
- * bar: ctx.bar,
20
- * foo: ctx.foo,
21
+ * async fetchConfig() {},
22
+ * async fetchData(settings) {},
23
+ * componentOptions: (context) => ([[context.foo, context.bar, 'default']]),
24
+ * propsData: (context) => ({
25
+ * foo: context.foo,
26
+ * bar: context.bar,
21
27
  * }),
28
+ * slots(h) {
29
+ * return {
30
+ * default: (attrs) => h('DruxtDebug', ['Hello world'])
31
+ * }
32
+ * }
22
33
  * }
23
34
  * }
24
35
  */
@@ -107,12 +118,16 @@ export default {
107
118
 
108
119
  // Fetch configuration.
109
120
  if ((this.$options.druxt || {}).fetchConfig) {
110
- await this.$options.druxt.fetchConfig.call(this)
121
+ try {
122
+ await this.$options.druxt.fetchConfig.call(this)
123
+ } catch(err) {
124
+ return this.error(err)
125
+ }
111
126
  }
112
127
 
113
128
  // Build wrapper component object.
114
129
  let options = []
115
- const hasDefaultTemplate = !!(this.$vnode.data.scopedSlots || {}).default
130
+ const hasDefaultTemplate = !!(((this.$vnode || {}).data || {}).scopedSlots || {}).default
116
131
  // Load wrapper components if:
117
132
  if (
118
133
  // No default template and wrapper isn't false OR
@@ -138,7 +153,11 @@ export default {
138
153
 
139
154
  // Fetch resource.
140
155
  if ((this.$options.druxt || {}).fetchData) {
141
- await this.$options.druxt.fetchData.call(this, component.settings)
156
+ try {
157
+ await this.$options.druxt.fetchData.call(this, component.settings)
158
+ } catch(err) {
159
+ return this.error(err, { component })
160
+ }
142
161
  }
143
162
 
144
163
  // Get scoped slots.
@@ -153,7 +172,7 @@ export default {
153
172
 
154
173
  watch: {
155
174
  model() {
156
- if (this.component.props.value !== this.model) {
175
+ if (this.component.props && this.component.props.value !== this.model) {
157
176
  this.component.props.value = this.model
158
177
 
159
178
  // Only emit 'input' if using the default 'DruxtWrapper' component.
@@ -172,6 +191,31 @@ export default {
172
191
 
173
192
  /** */
174
193
  methods: {
194
+ /**
195
+ * Sets the component to render a DruxtDebug error message.
196
+ */
197
+ error(err, context = {}) {
198
+ // Build error details.
199
+ const { url } = err.druxt || {}
200
+ const title = (err.response || {}).statusText || ((((err.response || {}).data || {}).errors || [])[0] || {}).title
201
+ const summary = (err.response || {}).status
202
+ ? [(err.response || {}).status, title].filter((s) => s).join(': ')
203
+ : err.message
204
+
205
+ // Set the component to a Debug component with error details.
206
+ this.component = {
207
+ ...context.component || {},
208
+ is: 'DruxtDebug',
209
+ props: {
210
+ json: {
211
+ url,
212
+ errors: ((err.response || {}).data || {}).errors
213
+ },
214
+ summary
215
+ }
216
+ }
217
+ },
218
+
175
219
  /**
176
220
  * Get list of module wrapper components.
177
221
  *
@@ -193,7 +237,7 @@ export default {
193
237
  let components = []
194
238
  for (const set of options.filter(set => Array.isArray(set))) {
195
239
  const variants = []
196
- components = [...components, ...set.map(item => {
240
+ components = [...components, ...set.filter((o) => o).map(item => {
197
241
  // Build array of name parts.
198
242
  const parts = variants.length ? [...variants[0].parts] : []
199
243
  parts.push(pascalCase(splitByCase(item)))
@@ -265,6 +309,18 @@ export default {
265
309
  */
266
310
  getScopedSlots() {
267
311
  const h = this.$createElement
312
+
313
+ // Get an array of unmet required props.
314
+ const required = Object.entries(this.$options.props)
315
+ .filter(([k, o]) => o.required && !this[k])
316
+ .map(([k]) => k)
317
+ // Return debug error if any missing props are found.
318
+ if (required.length) {
319
+ return {
320
+ default: () => h('DruxtDebug', { props: { summary: `Missing required props: ${required.join(', ')}.` } })
321
+ }
322
+ }
323
+
268
324
  const scopedSlots = typeof (this.$options.druxt || {}).slots === 'function'
269
325
  ? this.$options.druxt.slots.call(this, h)
270
326
  : {}
@@ -336,7 +392,7 @@ export default {
336
392
  }
337
393
 
338
394
  // Return only wrapper if fetch state is still pending.
339
- if (this.$fetchState.pending) {
395
+ if (this.$fetchState.pending && this.component.is === 'DruxtWrapper') {
340
396
  return h((this.wrapper || {}).component || 'div', wrapperData)
341
397
  }
342
398
 
package/dist/druxt.esm.js CHANGED
@@ -2,11 +2,94 @@ 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.17.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
+ "stories",
47
+ "templates"
48
+ ];
49
+ var dependencies = {
50
+ "@nuxtjs/proxy": "^2.1.0",
51
+ axios: "^0.21.1",
52
+ chalk: "^4.1.2",
53
+ deepmerge: "^4.2.2",
54
+ "drupal-jsonapi-params": "^1.2.1",
55
+ md5: "^2.3.0",
56
+ querystring: "^0.2.0",
57
+ scule: "^0.2.0"
58
+ };
59
+ var devDependencies = {
60
+ "@storybook/addon-docs": "^6.4.13"
61
+ };
62
+ var peerDependencies = {
63
+ consola: "*"
64
+ };
65
+ var optionalDependencies = {
66
+ "core-js": "^3.16.1",
67
+ vue: "^2.6.14",
68
+ vuex: "^3.6.2"
69
+ };
70
+ var publishConfig = {
71
+ access: "public"
72
+ };
73
+ var meta = {
74
+ name: name,
75
+ version: version,
76
+ description: description,
77
+ keywords: keywords,
78
+ homepage: homepage,
79
+ bugs: bugs,
80
+ repository: repository,
81
+ license: license,
82
+ exports: exports,
83
+ main: main,
84
+ module: module,
85
+ files: files,
86
+ dependencies: dependencies,
87
+ devDependencies: devDependencies,
88
+ peerDependencies: peerDependencies,
89
+ optionalDependencies: optionalDependencies,
90
+ publishConfig: publishConfig
91
+ };
92
+
10
93
  const DruxtNuxtModule = function(moduleOptions = {}) {
11
94
  var _a;
12
95
  const options = {
@@ -49,6 +132,15 @@ const DruxtNuxtModule = function(moduleOptions = {}) {
49
132
  fileName: "druxt.js",
50
133
  options
51
134
  });
135
+ const extendPlugins = this.options.extendPlugins;
136
+ this.options.extendPlugins = (plugins) => {
137
+ plugins = typeof extendPlugins === "function" ? extendPlugins(plugins) : plugins;
138
+ const index = plugins.findIndex(({ src }) => src === `${this.options.buildDir}/druxt.js`);
139
+ const plugin = plugins[index];
140
+ plugins.splice(index, 1);
141
+ plugins.unshift(plugin);
142
+ return plugins;
143
+ };
52
144
  this.addPlugin({
53
145
  src: resolve(__dirname, "../templates/store.js"),
54
146
  fileName: "store/druxt.js",
@@ -56,12 +148,20 @@ const DruxtNuxtModule = function(moduleOptions = {}) {
56
148
  });
57
149
  this.options.store = true;
58
150
  this.options.components = (_a = this.options.components) != null ? _a : true;
59
- this.options.cli.badgeMessages.push(`${chalk.bold("Druxt API:")} ${chalk.blue.underline(options.baseUrl + options.endpoint)}`);
151
+ this.options.cli.badgeMessages.push(`${chalk.blue.bold("Druxt")} @ v${meta.version}`);
152
+ this.options.cli.badgeMessages.push(`${chalk.bold("API:")} ${chalk.blue.underline(options.baseUrl + options.endpoint)}`);
153
+ this.nuxt.hook("storybook:config", async ({ stories }) => {
154
+ stories.push("druxt/stories/*.stories.mdx");
155
+ stories.push("druxt/dist/components/*.stories.mdx");
156
+ stories.push("druxt/dist/components/*.stories.mjs");
157
+ });
60
158
  };
61
- DruxtNuxtModule.meta = require("../package.json");
62
159
 
63
160
  class DruxtClient {
64
161
  constructor(baseUrl, options = {}) {
162
+ this.log = consola.create({ defaults: {
163
+ tag: "DruxtClient"
164
+ } });
65
165
  if (!baseUrl) {
66
166
  throw new Error("The 'baseUrl' parameter is required.");
67
167
  }
@@ -73,6 +173,16 @@ class DruxtClient {
73
173
  axiosSettings = Object.assign(axiosSettings, options.axios);
74
174
  }
75
175
  this.axios = axios.create(axiosSettings);
176
+ if (options.debug) {
177
+ const log = this.log;
178
+ this.axios.interceptors.request.use((config) => {
179
+ log.info(config.url);
180
+ return config;
181
+ }, (error) => {
182
+ log.error(error);
183
+ return Promise.reject(error);
184
+ });
185
+ }
76
186
  this.options = {
77
187
  endpoint: "/jsonapi",
78
188
  jsonapiResourceConfig: "jsonapi_resource_config--jsonapi_resource_config",
@@ -114,9 +224,16 @@ class DruxtClient {
114
224
  }
115
225
  }
116
226
  if (Object.keys(permissions).length) {
117
- throw new TypeError(`${res.data.meta.omitted.detail}
118
-
119
- Required permissions: ${Object.keys(permissions).join(", ")}.`);
227
+ const err = {
228
+ response: {
229
+ statusText: res.data.meta.omitted.detail,
230
+ data: {
231
+ errors: [{ detail: `Required permissions:
232
+ - ${Object.keys(permissions).join("\n - ")}` }]
233
+ }
234
+ }
235
+ };
236
+ throw err;
120
237
  }
121
238
  }
122
239
  }
@@ -136,19 +253,49 @@ class DruxtClient {
136
253
  }
137
254
  });
138
255
  } catch (err) {
139
- response = (err.response || {}).data || err.message;
256
+ this.error(err, { url: href });
140
257
  }
141
258
  return response;
142
259
  }
260
+ error(err, context = {}) {
261
+ let { url } = context;
262
+ if (!url && ((err.response || {}).config || {}).url) {
263
+ url = err.response.config.url;
264
+ }
265
+ const title = [
266
+ (err.response || {}).status,
267
+ (err.response || {}).statusText || err.message
268
+ ].filter((s) => s).join(": ");
269
+ const meta = { url: url && [this.options.baseUrl, url].join("") };
270
+ let message = [title];
271
+ if (Object.values(meta).filter((o) => o).length) {
272
+ message.push(Object.entries(meta).filter(([, v]) => v).map(([key, value]) => `${key.toUpperCase()}: ${value}`).join("\n"));
273
+ }
274
+ if (((((err.response || {}).data || {}).errors || [])[0] || {}).detail) {
275
+ message.push(err.response.data.errors[0].detail);
276
+ }
277
+ const error = Error(message.join("\n\n"));
278
+ error.response = err.response;
279
+ error.druxt = context;
280
+ throw error;
281
+ }
282
+ async get(url, options) {
283
+ try {
284
+ const res = await this.axios.get(url, options);
285
+ this.checkPermissions(res);
286
+ return res;
287
+ } catch (err) {
288
+ this.error(err, { url });
289
+ }
290
+ }
143
291
  async getCollection(type, query) {
144
292
  const { href } = await this.getIndex(type);
145
293
  if (!href) {
146
294
  return false;
147
295
  }
148
296
  const url = this.buildQueryUrl(href, query);
149
- const res = await this.axios.get(url);
150
- this.checkPermissions(res);
151
- return res.data;
297
+ const { data } = await this.get(url);
298
+ return data;
152
299
  }
153
300
  async getCollectionAll(type, query) {
154
301
  const collections = [];
@@ -168,16 +315,27 @@ class DruxtClient {
168
315
  if (this.index && resource) {
169
316
  return this.index[resource] ? this.index[resource] : false;
170
317
  }
171
- let index = ((await this.axios.get(this.options.endpoint) || {}).data || {}).links;
318
+ const url = this.options.endpoint;
319
+ const { data } = await this.get(url);
320
+ let index = data.links;
321
+ if (typeof index !== "object") {
322
+ const err = { response: { statusText: "Invalid JSON:API endpoint" } };
323
+ this.error(err, { url });
324
+ }
172
325
  const baseUrl = this.options.baseUrl;
173
326
  index = Object.fromEntries(Object.entries(index).map(([key, value]) => {
174
327
  value.href = value.href.replace(baseUrl, "");
175
328
  return [key, value];
176
329
  }));
177
330
  if (index[this.options.jsonapiResourceConfig]) {
178
- const resources = await this.axios.get(index[this.options.jsonapiResourceConfig].href);
179
- for (const resourceType in resources.data.data) {
180
- const resource2 = resources.data.data[resourceType];
331
+ let resources = [];
332
+ try {
333
+ resources = (await this.get(index[this.options.jsonapiResourceConfig].href)).data.data;
334
+ } catch (err) {
335
+ this.log.warn(err.message);
336
+ }
337
+ for (const resourceType in resources) {
338
+ const resource2 = resources[resourceType];
181
339
  const internal = resource2.attributes.drupal_internal__id.split("--");
182
340
  const item = {
183
341
  resourceType: resource2.attributes.resourceType,
@@ -193,11 +351,7 @@ class DruxtClient {
193
351
  }
194
352
  }
195
353
  this.index = index;
196
- if (resource) {
197
- const response = this.index[resource] ? this.index[resource] : false;
198
- return response;
199
- }
200
- return this.index;
354
+ return resource ? this.index[resource] || false : this.index;
201
355
  }
202
356
  async getRelated(type, id, related, query) {
203
357
  if (!id || !type || !related) {
@@ -208,12 +362,8 @@ class DruxtClient {
208
362
  href = this.options.endpoint + "/" + type.replace("--", "/");
209
363
  }
210
364
  const url = this.buildQueryUrl(`${href}/${id}/${related}`, query);
211
- try {
212
- const related2 = await this.axios.get(url);
213
- return related2.data;
214
- } catch (e) {
215
- return false;
216
- }
365
+ const { data } = await this.get(url);
366
+ return data;
217
367
  }
218
368
  async getResource(type, id, query) {
219
369
  if (!id || !type) {
@@ -223,13 +373,9 @@ class DruxtClient {
223
373
  if (!href) {
224
374
  href = this.options.endpoint + "/" + type.replace("--", "/");
225
375
  }
226
- const url = this.buildQueryUrl(`${href}/${id}`, query);
227
- try {
228
- const resource = await this.axios.get(url);
229
- return resource.data;
230
- } catch (e) {
231
- return false;
232
- }
376
+ const url = this.buildQueryUrl([href, id].join("/"), query);
377
+ const { data } = await this.get(url);
378
+ return data;
233
379
  }
234
380
  async updateResource(resource) {
235
381
  const { href } = await this.getIndex(resource.type);
@@ -245,7 +391,7 @@ class DruxtClient {
245
391
  }
246
392
  });
247
393
  } catch (err) {
248
- response = (err.response || {}).data || err.message;
394
+ this.error(err);
249
395
  }
250
396
  return response;
251
397
  }
@@ -256,7 +402,7 @@ const getDrupalJsonApiParams = (query) => {
256
402
  };
257
403
 
258
404
  const dehydrateResources = ({ commit, queryObject, resources }) => {
259
- return resources.map((data) => {
405
+ return (resources || []).map((data) => {
260
406
  const link = decodeURI(((data.links || {}).self || {}).href || "");
261
407
  const href = typeof (queryObject.fields || {})[data.type] === "string" ? [link.split("?")[0], `fields[${data.type}]=${queryObject.fields[data.type]}`].join("?") : link;
262
408
  commit("druxt/addResource", {
@@ -447,5 +593,7 @@ class DruxtClass {
447
593
  }
448
594
  }
449
595
 
596
+ DruxtNuxtModule.meta = require("../package.json");
597
+
450
598
  export default DruxtNuxtModule;
451
599
  export { DruxtClass, DruxtClient, DruxtStore };