decoupled-cli 2.0.2 → 2.1.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.
@@ -1,114 +1,289 @@
1
1
  {
2
2
  "model": [
3
3
  {
4
- "bundle": "event",
5
- "description": "Content type for managing events, conferences, and gatherings",
6
- "label": "Event",
4
+ "bundle": "article",
5
+ "description": "Blog articles and news posts with rich media and categorization",
6
+ "label": "Article",
7
7
  "body": true,
8
8
  "fields": [
9
9
  {
10
- "id": "event_date",
11
- "label": "Event Date",
12
- "type": "datetime"
13
- },
14
- {
15
- "id": "location",
16
- "label": "Location",
17
- "type": "string"
10
+ "id": "summary",
11
+ "label": "Summary",
12
+ "type": "string",
13
+ "description": "Short text field (max 255 chars) for article preview"
18
14
  },
19
15
  {
20
16
  "id": "featured_image",
21
17
  "label": "Featured Image",
22
- "type": "image"
18
+ "type": "image",
19
+ "description": "Single image upload for article hero"
23
20
  },
24
21
  {
25
- "id": "event_details",
26
- "label": "Event Details",
27
- "type": "paragraph(event_detail)[]"
22
+ "id": "published_date",
23
+ "label": "Published Date",
24
+ "type": "datetime",
25
+ "description": "Date and time field for publication scheduling"
26
+ },
27
+ {
28
+ "id": "author",
29
+ "label": "Author Name",
30
+ "type": "string"
28
31
  },
29
32
  {
30
33
  "id": "tags",
31
34
  "label": "Tags",
32
- "type": "term(tags)[]"
35
+ "type": "term(tags)[]",
36
+ "description": "Multiple taxonomy term references"
33
37
  },
34
38
  {
35
39
  "id": "featured",
36
- "label": "Featured",
37
- "type": "bool"
40
+ "label": "Featured Article",
41
+ "type": "bool",
42
+ "description": "Boolean flag for promoting articles"
43
+ },
44
+ {
45
+ "id": "key_points",
46
+ "label": "Key Points",
47
+ "type": "string[]",
48
+ "description": "Multiple string values - best for simple lists without HTML"
49
+ },
50
+ {
51
+ "id": "gallery",
52
+ "label": "Image Gallery",
53
+ "type": "image[]",
54
+ "description": "Multiple image uploads"
55
+ },
56
+ {
57
+ "id": "content_blocks",
58
+ "label": "Content Blocks",
59
+ "type": "paragraph(content_block)[]",
60
+ "description": "Multiple paragraph entity references for structured content"
38
61
  }
39
62
  ]
40
63
  },
41
64
  {
42
65
  "entity": "paragraph",
43
- "bundle": "event_detail",
44
- "description": "Reusable content blocks for event information and details",
45
- "label": "Event Detail",
66
+ "bundle": "content_block",
67
+ "description": "Reusable content blocks with images and formatted text",
68
+ "label": "Content Block",
46
69
  "fields": [
47
70
  {
48
- "id": "detail_title",
49
- "label": "Detail Title",
50
- "type": "string!"
71
+ "id": "block_title",
72
+ "label": "Block Title",
73
+ "type": "string!",
74
+ "description": "Required field (note the ! suffix)"
51
75
  },
52
76
  {
53
- "id": "detail_content",
54
- "label": "Detail Content",
55
- "type": "text"
77
+ "id": "block_content",
78
+ "label": "Block Content",
79
+ "type": "text",
80
+ "description": "Long text with HTML formatting"
56
81
  },
57
82
  {
58
- "id": "detail_image",
59
- "label": "Detail Image",
83
+ "id": "block_image",
84
+ "label": "Block Image",
60
85
  "type": "image"
61
86
  }
62
87
  ]
88
+ },
89
+ {
90
+ "bundle": "product",
91
+ "description": "E-commerce products with pricing, inventory, and specifications",
92
+ "label": "Product",
93
+ "body": true,
94
+ "fields": [
95
+ {
96
+ "id": "price",
97
+ "label": "Price",
98
+ "type": "string",
99
+ "description": "Product price as formatted string (e.g. '$299.99')"
100
+ },
101
+ {
102
+ "id": "sku",
103
+ "label": "SKU",
104
+ "type": "string",
105
+ "description": "Product identifier"
106
+ },
107
+ {
108
+ "id": "in_stock",
109
+ "label": "In Stock",
110
+ "type": "bool"
111
+ },
112
+ {
113
+ "id": "product_images",
114
+ "label": "Product Images",
115
+ "type": "image[]",
116
+ "description": "Multiple product photos"
117
+ },
118
+ {
119
+ "id": "features",
120
+ "label": "Key Features",
121
+ "type": "string[]",
122
+ "description": "List of product features (plain text, no HTML)"
123
+ },
124
+ {
125
+ "id": "specifications",
126
+ "label": "Specifications",
127
+ "type": "string[]",
128
+ "description": "Technical specifications"
129
+ },
130
+ {
131
+ "id": "category",
132
+ "label": "Product Category",
133
+ "type": "term(product_category)[]"
134
+ }
135
+ ]
63
136
  }
64
137
  ],
65
138
  "content": [
66
139
  {
67
- "id": "detail1",
68
- "type": "paragraph.event_detail",
140
+ "id": "block1",
141
+ "type": "paragraph.content_block",
69
142
  "values": {
70
- "detail_title": "Schedule",
71
- "detail_content": "The event will run from 9:00 AM to 5:00 PM with lunch break at noon.",
72
- "detail_image": {
73
- "uri": "/modules/custom/dcloud_import/resources/placeholder.png",
74
- "alt": "Event schedule timeline showing sessions and breaks",
75
- "title": "Conference Schedule"
143
+ "block_title": "Introduction",
144
+ "block_content": "<p>This is an <strong>example content block</strong> with formatted text.</p>",
145
+ "block_image": {
146
+ "uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png",
147
+ "alt": "Content block illustration",
148
+ "title": "Block Image"
76
149
  }
77
150
  }
78
151
  },
79
152
  {
80
- "id": "detail2",
81
- "type": "paragraph.event_detail",
153
+ "id": "article1",
154
+ "type": "node.article",
155
+ "path": "/articles/getting-started-with-drupal",
82
156
  "values": {
83
- "detail_title": "Speakers",
84
- "detail_content": "Join us for presentations by industry experts and thought leaders."
157
+ "title": "Getting Started with Decoupled Drupal",
158
+ "summary": "Learn how to build modern web applications with Drupal as a headless CMS",
159
+ "body": "<p>Decoupled Drupal enables you to use Drupal as a powerful content management backend while building your frontend with modern JavaScript frameworks.</p><p>This architecture provides flexibility, performance, and an excellent developer experience.</p>",
160
+ "published_date": "2024-03-15T09:00:00",
161
+ "author": "Jane Smith",
162
+ "featured": true,
163
+ "key_points": [
164
+ "Use Drupal for content management",
165
+ "Build frontend with Next.js, React, or Vue",
166
+ "Connect via GraphQL or REST API",
167
+ "Deploy frontend and backend independently"
168
+ ],
169
+ "featured_image": {
170
+ "uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png",
171
+ "alt": "Decoupled Drupal architecture diagram",
172
+ "title": "Architecture Overview"
173
+ },
174
+ "gallery": [
175
+ {
176
+ "uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png",
177
+ "alt": "Screenshot of content management interface",
178
+ "title": "CMS Interface"
179
+ },
180
+ {
181
+ "uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png",
182
+ "alt": "Frontend application example",
183
+ "title": "Frontend App"
184
+ }
185
+ ],
186
+ "tags": [
187
+ "drupal",
188
+ "headless-cms",
189
+ "web-development"
190
+ ],
191
+ "content_blocks": [
192
+ "@block1"
193
+ ]
85
194
  }
86
195
  },
87
196
  {
88
- "id": "event1",
89
- "type": "node.event",
90
- "path": "/events/web-dev-conference-2024",
197
+ "id": "product1",
198
+ "type": "node.product",
199
+ "path": "/products/wireless-charger-pro",
91
200
  "values": {
92
- "title": "Web Development Conference 2024",
93
- "body": "<p>Join us for a full day of learning about modern web development...</p>",
94
- "event_date": "2024-03-15T09:00:00",
95
- "location": "Convention Center Downtown",
96
- "featured_image": {
97
- "uri": "/modules/custom/dcloud_import/resources/placeholder.png",
98
- "alt": "Web Development Conference 2024 promotional image",
99
- "title": "Conference Hero Image"
100
- },
101
- "tags": [
102
- "web-development",
103
- "conference",
104
- "technology"
201
+ "title": "Wireless Charger Pro",
202
+ "body": "<p>Experience the future of charging with our premium wireless charging pad. Sleek design meets powerful performance.</p>",
203
+ "price": "$79.99",
204
+ "sku": "WCP-2024-BLK",
205
+ "in_stock": true,
206
+ "features": [
207
+ "Fast 15W wireless charging",
208
+ "Qi-compatible with all devices",
209
+ "Non-slip rubberized surface",
210
+ "LED charging indicator",
211
+ "Overheat protection"
105
212
  ],
106
- "featured": true,
107
- "event_details": [
108
- "@detail1",
109
- "@detail2"
213
+ "specifications": [
214
+ "Input: USB-C 5V/3A",
215
+ "Output: 15W max",
216
+ "Size: 4 x 4 x 0.5 inches",
217
+ "Weight: 3.2 oz",
218
+ "Color: Matte Black"
219
+ ],
220
+ "product_images": [
221
+ {
222
+ "uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png",
223
+ "alt": "Wireless Charger Pro front view",
224
+ "title": "Product Front"
225
+ },
226
+ {
227
+ "uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png",
228
+ "alt": "Wireless Charger Pro with phone charging",
229
+ "title": "In Use"
230
+ }
231
+ ],
232
+ "category": [
233
+ "electronics",
234
+ "accessories"
110
235
  ]
111
236
  }
112
237
  }
113
- ]
238
+ ],
239
+ "_comments": {
240
+ "field_types": {
241
+ "string": "Short text (max 255 chars), plain text only",
242
+ "text": "Long text with HTML formatting support",
243
+ "string[]": "Multiple string values - best for simple lists like features, tags, specifications",
244
+ "text[]": "Multiple text values with HTML - use sparingly, prefer string[] for lists",
245
+ "image": "Single image upload with uri, alt, title properties",
246
+ "image[]": "Multiple image uploads",
247
+ "datetime": "Date and time in ISO 8601 format (YYYY-MM-DDTHH:mm:ss)",
248
+ "bool": "Boolean true/false value",
249
+ "term(vocabulary)[]": "Taxonomy term references, creates/assigns terms automatically",
250
+ "paragraph(bundle)[]": "References to paragraph entities for structured content",
251
+ "string!": "Required field (note the ! suffix)"
252
+ },
253
+ "image_format": {
254
+ "description": "Images require full URLs with Drupal domain, not relative paths",
255
+ "example": {
256
+ "uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png",
257
+ "alt": "Descriptive alt text for accessibility",
258
+ "title": "Image title"
259
+ },
260
+ "note": "Replace ${DRUPAL_BASE_URL} with actual Drupal URL from .env.local"
261
+ },
262
+ "content_references": {
263
+ "description": "Reference other content items using @id syntax",
264
+ "example": "\"content_blocks\": [\"@block1\", \"@block2\"]",
265
+ "note": "Referenced content must be defined earlier in the content array"
266
+ },
267
+ "field_naming": {
268
+ "important": "In DC import JSON, use field 'id' directly (e.g., 'price'), NOT 'field_price'",
269
+ "note": "Drupal automatically prefixes with 'field_' internally",
270
+ "graphql": "GraphQL field names may transform to camelCase (e.g., in_stock → inStock)"
271
+ },
272
+ "best_practices": [
273
+ "Use string[] for simple lists (features, specifications) - avoids HTML rendering complexity",
274
+ "Use text[] only when you need rich HTML formatting within each list item",
275
+ "Always include sample content for immediate testing",
276
+ "Use descriptive field IDs that are clear and consistent",
277
+ "Include alt text for all images for accessibility",
278
+ "Set body: true to include standard body field",
279
+ "Use path aliases following /content-type/slug pattern"
280
+ ],
281
+ "common_patterns": {
282
+ "e-commerce": "price (string), sku (string), in_stock (bool), product_images (image[]), features (string[])",
283
+ "blog": "summary (string), author (string), published_date (datetime), tags (term[]), featured (bool)",
284
+ "events": "event_date (datetime), location (string), registration_url (string), speakers (string[])",
285
+ "team": "position (string), profile_image (image), bio (text), social_links (string[])",
286
+ "portfolio": "project_url (string), technologies (string[]), project_images (image[]), client (string)"
287
+ }
288
+ }
114
289
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "decoupled-cli",
3
- "version": "2.0.2",
4
- "description": "Command-line interface for DrupalCloud API management",
3
+ "version": "2.1.0",
4
+ "description": "Command-line interface for Decoupled Drupal API management",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
7
  "decoupled-cli": "bin/decoupled-cli"
@@ -21,7 +21,7 @@
21
21
  "drupal",
22
22
  "cloud"
23
23
  ],
24
- "author": "DrupalCloud",
24
+ "author": "Decoupled Drupal",
25
25
  "license": "MIT",
26
26
  "dependencies": {
27
27
  "@types/node-fetch": "^2.6.13",
@@ -1,3 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare const tokensCommand: Command;
3
- //# sourceMappingURL=tokens.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/commands/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,aAAa,SACS,CAAC"}
@@ -1,90 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.tokensCommand = void 0;
7
- const commander_1 = require("commander");
8
- const chalk_1 = __importDefault(require("chalk"));
9
- const cli_table3_1 = __importDefault(require("cli-table3"));
10
- const api_1 = require("../lib/api");
11
- exports.tokensCommand = new commander_1.Command('tokens')
12
- .description('Manage API tokens');
13
- exports.tokensCommand
14
- .command('list')
15
- .description('List all tokens')
16
- .option('--detailed', 'show detailed information')
17
- .option('--json', 'output as JSON')
18
- .action(async (options) => {
19
- try {
20
- const client = await (0, api_1.createApiClient)();
21
- const tokens = await client.getTokens();
22
- if (options.json) {
23
- console.log(JSON.stringify(tokens, null, 2));
24
- }
25
- else {
26
- console.log(chalk_1.default.bold('\nšŸ”‘ API Tokens'));
27
- console.log('─────────────');
28
- if (tokens.tokens && tokens.tokens.length > 0) {
29
- const table = new cli_table3_1.default({
30
- head: [
31
- chalk_1.default.cyan('ID'),
32
- chalk_1.default.cyan('Name'),
33
- chalk_1.default.cyan('Status'),
34
- chalk_1.default.cyan('Expires'),
35
- chalk_1.default.cyan('Created')
36
- ],
37
- style: {
38
- head: [],
39
- border: []
40
- }
41
- });
42
- tokens.tokens.forEach((token) => {
43
- const statusColor = token.isActive ? chalk_1.default.green : chalk_1.default.red;
44
- const status = token.isActive ? 'Active' : 'Inactive';
45
- const expires = token.expiresAt ? new Date(token.expiresAt).toLocaleDateString() : 'Never';
46
- const created = new Date(token.createdAt).toLocaleDateString();
47
- table.push([
48
- token.id.toString(),
49
- token.name,
50
- statusColor(status),
51
- expires,
52
- created
53
- ]);
54
- });
55
- console.log(table.toString());
56
- }
57
- else {
58
- console.log(chalk_1.default.gray('No tokens found. Note: Token-based authentication cannot list tokens for security reasons.'));
59
- }
60
- }
61
- }
62
- catch (error) {
63
- if (error instanceof Error && (error.message.includes('Token-based authentication cannot manage tokens') ||
64
- error.message.includes('Insufficient permissions for this operation'))) {
65
- console.log(chalk_1.default.yellow('āš ļø Token-based authentication cannot list tokens for security reasons.'));
66
- console.log(chalk_1.default.gray('Use session-based authentication in the web interface to manage tokens.'));
67
- }
68
- else {
69
- console.error(chalk_1.default.red('āŒ Failed to list tokens:'), error instanceof Error ? error.message : String(error));
70
- process.exit(1);
71
- }
72
- }
73
- });
74
- exports.tokensCommand
75
- .command('create <name>')
76
- .description('Create a new token')
77
- .option('--preset <preset>', 'permission preset (read-only, spaces-manager, full-access)')
78
- .option('--permissions <permissions>', 'custom permissions (comma-separated)')
79
- .option('--expires <date>', 'expiration date (YYYY-MM-DD)')
80
- .action(async (name, options) => {
81
- try {
82
- console.log(chalk_1.default.yellow('āš ļø Token creation is only available through session-based authentication.'));
83
- console.log(chalk_1.default.gray('Please use the web interface to create new tokens for security reasons.'));
84
- }
85
- catch (error) {
86
- console.error(chalk_1.default.red('āŒ Failed to create token:'), error instanceof Error ? error.message : String(error));
87
- process.exit(1);
88
- }
89
- });
90
- //# sourceMappingURL=tokens.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/commands/tokens.ts"],"names":[],"mappings":"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"}