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.
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,10 +16,93 @@ 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.17.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
+ "stories",
60
+ "templates"
61
+ ];
62
+ var dependencies = {
63
+ "@nuxtjs/proxy": "^2.1.0",
64
+ axios: "^0.21.1",
65
+ chalk: "^4.1.2",
66
+ deepmerge: "^4.2.2",
67
+ "drupal-jsonapi-params": "^1.2.1",
68
+ md5: "^2.3.0",
69
+ querystring: "^0.2.0",
70
+ scule: "^0.2.0"
71
+ };
72
+ var devDependencies = {
73
+ "@storybook/addon-docs": "^6.4.13"
74
+ };
75
+ var peerDependencies = {
76
+ consola: "*"
77
+ };
78
+ var optionalDependencies = {
79
+ "core-js": "^3.16.1",
80
+ vue: "^2.6.14",
81
+ vuex: "^3.6.2"
82
+ };
83
+ var publishConfig = {
84
+ access: "public"
85
+ };
86
+ const meta = {
87
+ name: name,
88
+ version: version,
89
+ description: description,
90
+ keywords: keywords,
91
+ homepage: homepage,
92
+ bugs: bugs,
93
+ repository: repository,
94
+ license: license,
95
+ exports: exports$1,
96
+ main: main,
97
+ module: module$1,
98
+ files: files,
99
+ dependencies: dependencies,
100
+ devDependencies: devDependencies,
101
+ peerDependencies: peerDependencies,
102
+ optionalDependencies: optionalDependencies,
103
+ publishConfig: publishConfig
104
+ };
105
+
22
106
  const DruxtNuxtModule = function(moduleOptions = {}) {
23
107
  var _a;
24
108
  const options = {
@@ -61,6 +145,15 @@ const DruxtNuxtModule = function(moduleOptions = {}) {
61
145
  fileName: "druxt.js",
62
146
  options
63
147
  });
148
+ const extendPlugins = this.options.extendPlugins;
149
+ this.options.extendPlugins = (plugins) => {
150
+ plugins = typeof extendPlugins === "function" ? extendPlugins(plugins) : plugins;
151
+ const index = plugins.findIndex(({ src }) => src === `${this.options.buildDir}/druxt.js`);
152
+ const plugin = plugins[index];
153
+ plugins.splice(index, 1);
154
+ plugins.unshift(plugin);
155
+ return plugins;
156
+ };
64
157
  this.addPlugin({
65
158
  src: path.resolve(__dirname, "../templates/store.js"),
66
159
  fileName: "store/druxt.js",
@@ -68,12 +161,20 @@ const DruxtNuxtModule = function(moduleOptions = {}) {
68
161
  });
69
162
  this.options.store = true;
70
163
  this.options.components = (_a = this.options.components) != null ? _a : true;
71
- this.options.cli.badgeMessages.push(`${chalk__default['default'].bold("Druxt API:")} ${chalk__default['default'].blue.underline(options.baseUrl + options.endpoint)}`);
164
+ this.options.cli.badgeMessages.push(`${chalk__default['default'].blue.bold("Druxt")} @ v${meta.version}`);
165
+ this.options.cli.badgeMessages.push(`${chalk__default['default'].bold("API:")} ${chalk__default['default'].blue.underline(options.baseUrl + options.endpoint)}`);
166
+ this.nuxt.hook("storybook:config", async ({ stories }) => {
167
+ stories.push("druxt/stories/*.stories.mdx");
168
+ stories.push("druxt/dist/components/*.stories.mdx");
169
+ stories.push("druxt/dist/components/*.stories.mjs");
170
+ });
72
171
  };
73
- DruxtNuxtModule.meta = require("../package.json");
74
172
 
75
173
  class DruxtClient {
76
174
  constructor(baseUrl, options = {}) {
175
+ this.log = consola__default['default'].create({ defaults: {
176
+ tag: "DruxtClient"
177
+ } });
77
178
  if (!baseUrl) {
78
179
  throw new Error("The 'baseUrl' parameter is required.");
79
180
  }
@@ -85,6 +186,16 @@ class DruxtClient {
85
186
  axiosSettings = Object.assign(axiosSettings, options.axios);
86
187
  }
87
188
  this.axios = axios__default['default'].create(axiosSettings);
189
+ if (options.debug) {
190
+ const log = this.log;
191
+ this.axios.interceptors.request.use((config) => {
192
+ log.info(config.url);
193
+ return config;
194
+ }, (error) => {
195
+ log.error(error);
196
+ return Promise.reject(error);
197
+ });
198
+ }
88
199
  this.options = {
89
200
  endpoint: "/jsonapi",
90
201
  jsonapiResourceConfig: "jsonapi_resource_config--jsonapi_resource_config",
@@ -126,9 +237,16 @@ class DruxtClient {
126
237
  }
127
238
  }
128
239
  if (Object.keys(permissions).length) {
129
- throw new TypeError(`${res.data.meta.omitted.detail}
130
-
131
- Required permissions: ${Object.keys(permissions).join(", ")}.`);
240
+ const err = {
241
+ response: {
242
+ statusText: res.data.meta.omitted.detail,
243
+ data: {
244
+ errors: [{ detail: `Required permissions:
245
+ - ${Object.keys(permissions).join("\n - ")}` }]
246
+ }
247
+ }
248
+ };
249
+ throw err;
132
250
  }
133
251
  }
134
252
  }
@@ -148,19 +266,49 @@ class DruxtClient {
148
266
  }
149
267
  });
150
268
  } catch (err) {
151
- response = (err.response || {}).data || err.message;
269
+ this.error(err, { url: href });
152
270
  }
153
271
  return response;
154
272
  }
273
+ error(err, context = {}) {
274
+ let { url } = context;
275
+ if (!url && ((err.response || {}).config || {}).url) {
276
+ url = err.response.config.url;
277
+ }
278
+ const title = [
279
+ (err.response || {}).status,
280
+ (err.response || {}).statusText || err.message
281
+ ].filter((s) => s).join(": ");
282
+ const meta = { url: url && [this.options.baseUrl, url].join("") };
283
+ let message = [title];
284
+ if (Object.values(meta).filter((o) => o).length) {
285
+ message.push(Object.entries(meta).filter(([, v]) => v).map(([key, value]) => `${key.toUpperCase()}: ${value}`).join("\n"));
286
+ }
287
+ if (((((err.response || {}).data || {}).errors || [])[0] || {}).detail) {
288
+ message.push(err.response.data.errors[0].detail);
289
+ }
290
+ const error = Error(message.join("\n\n"));
291
+ error.response = err.response;
292
+ error.druxt = context;
293
+ throw error;
294
+ }
295
+ async get(url, options) {
296
+ try {
297
+ const res = await this.axios.get(url, options);
298
+ this.checkPermissions(res);
299
+ return res;
300
+ } catch (err) {
301
+ this.error(err, { url });
302
+ }
303
+ }
155
304
  async getCollection(type, query) {
156
305
  const { href } = await this.getIndex(type);
157
306
  if (!href) {
158
307
  return false;
159
308
  }
160
309
  const url = this.buildQueryUrl(href, query);
161
- const res = await this.axios.get(url);
162
- this.checkPermissions(res);
163
- return res.data;
310
+ const { data } = await this.get(url);
311
+ return data;
164
312
  }
165
313
  async getCollectionAll(type, query) {
166
314
  const collections = [];
@@ -180,16 +328,27 @@ class DruxtClient {
180
328
  if (this.index && resource) {
181
329
  return this.index[resource] ? this.index[resource] : false;
182
330
  }
183
- let index = ((await this.axios.get(this.options.endpoint) || {}).data || {}).links;
331
+ const url = this.options.endpoint;
332
+ const { data } = await this.get(url);
333
+ let index = data.links;
334
+ if (typeof index !== "object") {
335
+ const err = { response: { statusText: "Invalid JSON:API endpoint" } };
336
+ this.error(err, { url });
337
+ }
184
338
  const baseUrl = this.options.baseUrl;
185
339
  index = Object.fromEntries(Object.entries(index).map(([key, value]) => {
186
340
  value.href = value.href.replace(baseUrl, "");
187
341
  return [key, value];
188
342
  }));
189
343
  if (index[this.options.jsonapiResourceConfig]) {
190
- const resources = await this.axios.get(index[this.options.jsonapiResourceConfig].href);
191
- for (const resourceType in resources.data.data) {
192
- const resource2 = resources.data.data[resourceType];
344
+ let resources = [];
345
+ try {
346
+ resources = (await this.get(index[this.options.jsonapiResourceConfig].href)).data.data;
347
+ } catch (err) {
348
+ this.log.warn(err.message);
349
+ }
350
+ for (const resourceType in resources) {
351
+ const resource2 = resources[resourceType];
193
352
  const internal = resource2.attributes.drupal_internal__id.split("--");
194
353
  const item = {
195
354
  resourceType: resource2.attributes.resourceType,
@@ -205,11 +364,7 @@ class DruxtClient {
205
364
  }
206
365
  }
207
366
  this.index = index;
208
- if (resource) {
209
- const response = this.index[resource] ? this.index[resource] : false;
210
- return response;
211
- }
212
- return this.index;
367
+ return resource ? this.index[resource] || false : this.index;
213
368
  }
214
369
  async getRelated(type, id, related, query) {
215
370
  if (!id || !type || !related) {
@@ -220,12 +375,8 @@ class DruxtClient {
220
375
  href = this.options.endpoint + "/" + type.replace("--", "/");
221
376
  }
222
377
  const url = this.buildQueryUrl(`${href}/${id}/${related}`, query);
223
- try {
224
- const related2 = await this.axios.get(url);
225
- return related2.data;
226
- } catch (e) {
227
- return false;
228
- }
378
+ const { data } = await this.get(url);
379
+ return data;
229
380
  }
230
381
  async getResource(type, id, query) {
231
382
  if (!id || !type) {
@@ -235,13 +386,9 @@ class DruxtClient {
235
386
  if (!href) {
236
387
  href = this.options.endpoint + "/" + type.replace("--", "/");
237
388
  }
238
- const url = this.buildQueryUrl(`${href}/${id}`, query);
239
- try {
240
- const resource = await this.axios.get(url);
241
- return resource.data;
242
- } catch (e) {
243
- return false;
244
- }
389
+ const url = this.buildQueryUrl([href, id].join("/"), query);
390
+ const { data } = await this.get(url);
391
+ return data;
245
392
  }
246
393
  async updateResource(resource) {
247
394
  const { href } = await this.getIndex(resource.type);
@@ -257,7 +404,7 @@ class DruxtClient {
257
404
  }
258
405
  });
259
406
  } catch (err) {
260
- response = (err.response || {}).data || err.message;
407
+ this.error(err);
261
408
  }
262
409
  return response;
263
410
  }
@@ -268,7 +415,7 @@ const getDrupalJsonApiParams = (query) => {
268
415
  };
269
416
 
270
417
  const dehydrateResources = ({ commit, queryObject, resources }) => {
271
- return resources.map((data) => {
418
+ return (resources || []).map((data) => {
272
419
  const link = decodeURI(((data.links || {}).self || {}).href || "");
273
420
  const href = typeof (queryObject.fields || {})[data.type] === "string" ? [link.split("?")[0], `fields[${data.type}]=${queryObject.fields[data.type]}`].join("?") : link;
274
421
  commit("druxt/addResource", {
@@ -459,6 +606,8 @@ class DruxtClass {
459
606
  }
460
607
  }
461
608
 
609
+ DruxtNuxtModule.meta = require("../package.json");
610
+
462
611
  exports.DruxtClass = DruxtClass;
463
612
  exports.DruxtClient = DruxtClient;
464
613
  exports.DruxtStore = DruxtStore;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "druxt",
3
- "version": "0.13.0",
3
+ "version": "0.17.0",
4
4
  "description": "The Fully Decoupled Drupal Framework for Nuxt.js.",
5
5
  "keywords": [
6
6
  "cms",
@@ -34,6 +34,7 @@
34
34
  "module": "dist/druxt.esm.js",
35
35
  "files": [
36
36
  "dist",
37
+ "stories",
37
38
  "templates"
38
39
  ],
39
40
  "dependencies": {
@@ -46,6 +47,12 @@
46
47
  "querystring": "^0.2.0",
47
48
  "scule": "^0.2.0"
48
49
  },
50
+ "devDependencies": {
51
+ "@storybook/addon-docs": "^6.4.13"
52
+ },
53
+ "peerDependencies": {
54
+ "consola": "*"
55
+ },
49
56
  "optionalDependencies": {
50
57
  "core-js": "^3.16.1",
51
58
  "vue": "^2.6.14",
@@ -0,0 +1,74 @@
1
+ import { Meta } from '@storybook/addon-docs'
2
+
3
+ <Meta title="Druxt/README" />
4
+
5
+ # Druxt Storybook
6
+
7
+ > Druxt + @nuxtjs/Storybook
8
+
9
+ The following documentation and stories are provided by
10
+ [DruxtJS](https://druxtjs.org) and the installed Druxt modules.
11
+
12
+ The stories are connected to your Drupal JSON:API via the DruxtClient; this
13
+ allows you to test your Druxt Wrapper components using live data.
14
+
15
+ - For more information, refer to the
16
+ [Druxt Storybook guide](https://druxtjs.org/guide/storybook).
17
+
18
+ ---
19
+
20
+ ## Introduction
21
+
22
+ This is a live Druxt Storybook, with autogenerated stories based on the
23
+ configuration of your Drupal backend.
24
+
25
+ ---
26
+
27
+ ### Autogenerated stories
28
+
29
+ Each Druxt module is able to use configuration from your Drupal backend to craft
30
+ site specific stories.
31
+
32
+ For instance, the DruxtEntity module will create a story for each Entity type,
33
+ Bundle and Display mode, while the Block module will create a story for each
34
+ backend Theme, Region and Block.
35
+
36
+ Search or navigate through the Druxt components and stories in the Storybook
37
+ sidebar.
38
+
39
+ ---
40
+
41
+ ### What is Druxt?
42
+
43
+ > Drupal + Nuxt = Druxt
44
+
45
+ Druxt is a framework for building Fully Decoupled Drupal and Nuxt.js
46
+ applications and sites. It allows you to leverage the content modelling and
47
+ management power of Drupal, and build elegant user experiences with Nuxt.js.
48
+
49
+ - Find out more @ [DruxtJS.org](https://druxtjs.org)
50
+
51
+ ---
52
+
53
+ ### Druxt components
54
+
55
+ Druxt components are provided by Druxt modules to provide targetted decoupled
56
+ Drupal functionality; A **DruxtEntity** component to render Drupal Content
57
+ entities, or a **DruxtMenu** component to render a Drupal menu, etc.
58
+
59
+ - See the core Druxt components @
60
+ [https://druxtjs.org/api/components](https://druxtjs.org/api/components)
61
+
62
+ ---
63
+
64
+ ### Druxt Wrapper theme system
65
+
66
+ Druxt components that extend the **DruxtModule** use slot based wrapper system,
67
+ providing the frontend developer the ability to create theme templates per
68
+ Content type, or Display mode, and many more component options depending on the
69
+ module.
70
+
71
+ The available component options are provided via the `component.options` data
72
+ on the relevant Druxt module component.
73
+
74
+ - For more information, see the [Themeing guide](https://druxtjs.org/guide/theming)