@knocklabs/cli 0.3.1 → 1.0.0-rc.1
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/README.md +258 -55
- package/dist/commands/branch/delete.js +4 -1
- package/dist/commands/branch/merge.js +82 -0
- package/dist/commands/channel/list.js +73 -0
- package/dist/commands/environment/list.js +73 -0
- package/dist/commands/guide/new.js +276 -0
- package/dist/commands/guide/pull.js +5 -6
- package/dist/commands/guide/push.js +1 -1
- package/dist/commands/guide/validate.js +1 -1
- package/dist/commands/init.js +108 -0
- package/dist/commands/layout/new.js +228 -0
- package/dist/commands/layout/pull.js +5 -6
- package/dist/commands/layout/push.js +1 -1
- package/dist/commands/layout/validate.js +1 -1
- package/dist/commands/message-type/new.js +228 -0
- package/dist/commands/message-type/pull.js +5 -6
- package/dist/commands/message-type/push.js +1 -1
- package/dist/commands/message-type/validate.js +1 -1
- package/dist/commands/partial/new.js +274 -0
- package/dist/commands/partial/pull.js +5 -6
- package/dist/commands/partial/push.js +1 -1
- package/dist/commands/partial/validate.js +1 -1
- package/dist/commands/pull.js +7 -2
- package/dist/commands/push.js +6 -4
- package/dist/commands/translation/pull.js +1 -1
- package/dist/commands/translation/push.js +1 -1
- package/dist/commands/translation/validate.js +1 -1
- package/dist/commands/workflow/new.js +179 -54
- package/dist/commands/workflow/pull.js +6 -8
- package/dist/commands/workflow/push.js +1 -1
- package/dist/commands/workflow/validate.js +1 -1
- package/dist/lib/api-v1.js +23 -2
- package/dist/lib/auth.js +1 -1
- package/dist/lib/base-command.js +18 -15
- package/dist/lib/helpers/project-config.js +158 -0
- package/dist/lib/helpers/request.js +1 -2
- package/dist/lib/helpers/string.js +4 -4
- package/dist/lib/helpers/typegen.js +1 -1
- package/dist/lib/marshal/email-layout/generator.js +152 -0
- package/dist/lib/marshal/email-layout/helpers.js +6 -9
- package/dist/lib/marshal/email-layout/index.js +1 -0
- package/dist/lib/marshal/email-layout/writer.js +15 -3
- package/dist/lib/marshal/guide/generator.js +163 -0
- package/dist/lib/marshal/guide/helpers.js +6 -10
- package/dist/lib/marshal/guide/index.js +1 -0
- package/dist/lib/marshal/guide/writer.js +5 -9
- package/dist/lib/marshal/message-type/generator.js +139 -0
- package/dist/lib/marshal/message-type/helpers.js +6 -10
- package/dist/lib/marshal/message-type/index.js +1 -0
- package/dist/lib/marshal/message-type/writer.js +5 -1
- package/dist/lib/marshal/partial/generator.js +159 -0
- package/dist/lib/marshal/partial/helpers.js +6 -10
- package/dist/lib/marshal/partial/index.js +1 -0
- package/dist/lib/marshal/partial/writer.js +3 -0
- package/dist/lib/marshal/translation/helpers.js +6 -10
- package/dist/lib/marshal/translation/processor.isomorphic.js +4 -4
- package/dist/lib/marshal/translation/writer.js +2 -2
- package/dist/lib/marshal/workflow/generator.js +175 -19
- package/dist/lib/marshal/workflow/helpers.js +7 -10
- package/dist/lib/run-context/loader.js +5 -0
- package/dist/lib/templates.js +131 -0
- package/oclif.manifest.json +1075 -471
- package/package.json +10 -8
|
@@ -9,9 +9,18 @@ function _export(target, all) {
|
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
11
|
_export(exports, {
|
|
12
|
+
get StepTagChoices () {
|
|
13
|
+
return StepTagChoices;
|
|
14
|
+
},
|
|
12
15
|
get generateWorkflowDir () {
|
|
13
16
|
return generateWorkflowDir;
|
|
14
17
|
},
|
|
18
|
+
get generateWorkflowFromTemplate () {
|
|
19
|
+
return generateWorkflowFromTemplate;
|
|
20
|
+
},
|
|
21
|
+
get getAvailableStepTypes () {
|
|
22
|
+
return getAvailableStepTypes;
|
|
23
|
+
},
|
|
15
24
|
get parseStepsInput () {
|
|
16
25
|
return parseStepsInput;
|
|
17
26
|
},
|
|
@@ -22,7 +31,9 @@ _export(exports, {
|
|
|
22
31
|
const _nodepath = /*#__PURE__*/ _interop_require_wildcard(require("node:path"));
|
|
23
32
|
const _lodash = require("lodash");
|
|
24
33
|
const _constisomorphic = require("../shared/const.isomorphic");
|
|
34
|
+
const _templates = /*#__PURE__*/ _interop_require_wildcard(require("../../templates"));
|
|
25
35
|
const _processorisomorphic = require("./processor.isomorphic");
|
|
36
|
+
const _reader = require("./reader");
|
|
26
37
|
const _types = require("./types");
|
|
27
38
|
const _writer = require("./writer");
|
|
28
39
|
function _getRequireWildcardCache(nodeInterop) {
|
|
@@ -115,13 +126,14 @@ const scaffoldHttpFetchStep = (refSuffix)=>{
|
|
|
115
126
|
{}
|
|
116
127
|
];
|
|
117
128
|
};
|
|
118
|
-
const scaffoldEmailChannelStep = (refSuffix)=>{
|
|
129
|
+
const scaffoldEmailChannelStep = (refSuffix, channels)=>{
|
|
119
130
|
const stepRef = `email_${refSuffix}`;
|
|
120
131
|
const templateFilePath = newTemplateFilePath(stepRef, "html_body", "html");
|
|
132
|
+
const firstChannel = channels[0];
|
|
121
133
|
const scaffoldedStep = {
|
|
122
134
|
ref: stepRef,
|
|
123
135
|
type: _types.StepType.Channel,
|
|
124
|
-
channel_key: "<EMAIL CHANNEL KEY>",
|
|
136
|
+
channel_key: firstChannel ? firstChannel.key : "<EMAIL CHANNEL KEY>",
|
|
125
137
|
template: {
|
|
126
138
|
settings: {
|
|
127
139
|
layout_key: "default"
|
|
@@ -138,13 +150,14 @@ const scaffoldEmailChannelStep = (refSuffix)=>{
|
|
|
138
150
|
bundleFragment
|
|
139
151
|
];
|
|
140
152
|
};
|
|
141
|
-
const scaffoldInAppFeedChannelStep = (refSuffix)=>{
|
|
153
|
+
const scaffoldInAppFeedChannelStep = (refSuffix, channels)=>{
|
|
142
154
|
const stepRef = `in_app_feed_${refSuffix}`;
|
|
143
155
|
const templateFilePath = newTemplateFilePath(stepRef, "markdown_body", "md");
|
|
156
|
+
const firstChannel = channels[0];
|
|
144
157
|
const scaffoldedStep = {
|
|
145
158
|
ref: stepRef,
|
|
146
159
|
type: _types.StepType.Channel,
|
|
147
|
-
channel_key: "<IN-APP-FEED CHANNEL KEY>",
|
|
160
|
+
channel_key: firstChannel ? firstChannel.key : "<IN-APP-FEED CHANNEL KEY>",
|
|
148
161
|
template: {
|
|
149
162
|
action_url: "{{ vars.app_url }}",
|
|
150
163
|
["markdown_body" + _constisomorphic.FILEPATH_MARKER]: templateFilePath
|
|
@@ -158,13 +171,14 @@ const scaffoldInAppFeedChannelStep = (refSuffix)=>{
|
|
|
158
171
|
bundleFragment
|
|
159
172
|
];
|
|
160
173
|
};
|
|
161
|
-
const scaffoldSmsChannelStep = (refSuffix)=>{
|
|
174
|
+
const scaffoldSmsChannelStep = (refSuffix, channels)=>{
|
|
162
175
|
const stepRef = `sms_${refSuffix}`;
|
|
163
176
|
const templateFilePath = newTemplateFilePath(stepRef, "text_body", "txt");
|
|
177
|
+
const firstChannel = channels[0];
|
|
164
178
|
const scaffoldedStep = {
|
|
165
179
|
ref: stepRef,
|
|
166
180
|
type: _types.StepType.Channel,
|
|
167
|
-
channel_key: "<SMS CHANNEL KEY>",
|
|
181
|
+
channel_key: firstChannel ? firstChannel.key : "<SMS CHANNEL KEY>",
|
|
168
182
|
template: {
|
|
169
183
|
["text_body" + _constisomorphic.FILEPATH_MARKER]: templateFilePath
|
|
170
184
|
}
|
|
@@ -177,13 +191,14 @@ const scaffoldSmsChannelStep = (refSuffix)=>{
|
|
|
177
191
|
bundleFragment
|
|
178
192
|
];
|
|
179
193
|
};
|
|
180
|
-
const scaffoldPushChannelStep = (refSuffix)=>{
|
|
194
|
+
const scaffoldPushChannelStep = (refSuffix, channels)=>{
|
|
181
195
|
const stepRef = `push_${refSuffix}`;
|
|
182
196
|
const templateFilePath = newTemplateFilePath(stepRef, "text_body", "txt");
|
|
197
|
+
const firstChannel = channels[0];
|
|
183
198
|
const scaffoldedStep = {
|
|
184
199
|
ref: stepRef,
|
|
185
200
|
type: _types.StepType.Channel,
|
|
186
|
-
channel_key: "<PUSH CHANNEL KEY>",
|
|
201
|
+
channel_key: firstChannel ? firstChannel.key : "<PUSH CHANNEL KEY>",
|
|
187
202
|
template: {
|
|
188
203
|
settings: {
|
|
189
204
|
delivery_type: "content"
|
|
@@ -199,13 +214,14 @@ const scaffoldPushChannelStep = (refSuffix)=>{
|
|
|
199
214
|
bundleFragment
|
|
200
215
|
];
|
|
201
216
|
};
|
|
202
|
-
const scaffoldChatChannelStep = (refSuffix)=>{
|
|
217
|
+
const scaffoldChatChannelStep = (refSuffix, channels)=>{
|
|
203
218
|
const stepRef = `chat_${refSuffix}`;
|
|
204
219
|
const templateFilePath = newTemplateFilePath(stepRef, "markdown_body", "md");
|
|
220
|
+
const firstChannel = channels[0];
|
|
205
221
|
const scaffoldedStep = {
|
|
206
222
|
ref: stepRef,
|
|
207
223
|
type: _types.StepType.Channel,
|
|
208
|
-
channel_key: "<CHAT CHANNEL KEY>",
|
|
224
|
+
channel_key: firstChannel ? firstChannel.key : "<CHAT CHANNEL KEY>",
|
|
209
225
|
template: {
|
|
210
226
|
["markdown_body" + _constisomorphic.FILEPATH_MARKER]: templateFilePath
|
|
211
227
|
}
|
|
@@ -223,11 +239,21 @@ const STEP_TAGS = [
|
|
|
223
239
|
"batch",
|
|
224
240
|
"fetch",
|
|
225
241
|
"email",
|
|
226
|
-
"in-app",
|
|
242
|
+
"in-app-feed",
|
|
227
243
|
"sms",
|
|
228
244
|
"push",
|
|
229
245
|
"chat"
|
|
230
246
|
];
|
|
247
|
+
const StepTagChoices = {
|
|
248
|
+
delay: "Delay step",
|
|
249
|
+
batch: "Batch step",
|
|
250
|
+
fetch: "HTTP Fetch step",
|
|
251
|
+
email: "Email channel step",
|
|
252
|
+
"in-app-feed": "In-app feed channel step",
|
|
253
|
+
sms: "SMS channel step",
|
|
254
|
+
push: "Push channel step",
|
|
255
|
+
chat: "Chat channel step"
|
|
256
|
+
};
|
|
231
257
|
const stepScaffoldFuncs = {
|
|
232
258
|
// Function steps
|
|
233
259
|
delay: scaffoldDelayStep,
|
|
@@ -235,18 +261,18 @@ const stepScaffoldFuncs = {
|
|
|
235
261
|
fetch: scaffoldHttpFetchStep,
|
|
236
262
|
// Channel steps
|
|
237
263
|
email: scaffoldEmailChannelStep,
|
|
238
|
-
"in-app": scaffoldInAppFeedChannelStep,
|
|
264
|
+
"in-app-feed": scaffoldInAppFeedChannelStep,
|
|
239
265
|
sms: scaffoldSmsChannelStep,
|
|
240
266
|
push: scaffoldPushChannelStep,
|
|
241
267
|
chat: scaffoldChatChannelStep
|
|
242
268
|
};
|
|
243
|
-
const parseStepsInput = (input)=>{
|
|
269
|
+
const parseStepsInput = (input, availableStepTypes)=>{
|
|
244
270
|
const tags = input.split(",").filter((x)=>x);
|
|
245
|
-
const invalidTags = tags.filter((tag)=>!
|
|
271
|
+
const invalidTags = tags.filter((tag)=>!availableStepTypes.includes(tag));
|
|
246
272
|
if (invalidTags.length > 0) {
|
|
247
273
|
return [
|
|
248
274
|
undefined,
|
|
249
|
-
|
|
275
|
+
`Invalid step type: ${invalidTags.join(", ")}`
|
|
250
276
|
];
|
|
251
277
|
}
|
|
252
278
|
return [
|
|
@@ -254,7 +280,26 @@ const parseStepsInput = (input)=>{
|
|
|
254
280
|
undefined
|
|
255
281
|
];
|
|
256
282
|
};
|
|
257
|
-
const
|
|
283
|
+
const getAvailableStepTypes = (channelTypes)=>{
|
|
284
|
+
// Return a list of step
|
|
285
|
+
return STEP_TAGS.filter((stepTag)=>{
|
|
286
|
+
switch(stepTag){
|
|
287
|
+
case "email":
|
|
288
|
+
return channelTypes.includes("email");
|
|
289
|
+
case "in-app-feed":
|
|
290
|
+
return channelTypes.includes("in_app_feed");
|
|
291
|
+
case "sms":
|
|
292
|
+
return channelTypes.includes("sms");
|
|
293
|
+
case "push":
|
|
294
|
+
return channelTypes.includes("push");
|
|
295
|
+
case "chat":
|
|
296
|
+
return channelTypes.includes("chat");
|
|
297
|
+
default:
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
};
|
|
302
|
+
const scaffoldWorkflowDirBundle = (attrs, channelsByType)=>{
|
|
258
303
|
// A map of 1-based counters to track the number of each step tag seen, used
|
|
259
304
|
// for formatting step refs.
|
|
260
305
|
const stepCountByTag = (0, _lodash.assign)({}, ...STEP_TAGS.map((tag)=>({
|
|
@@ -263,7 +308,17 @@ const scaffoldWorkflowDirBundle = (attrs)=>{
|
|
|
263
308
|
// Scaffold workflow steps data based on given step tags.
|
|
264
309
|
const [scaffoldedSteps = [], bundleFragments = []] = (0, _lodash.zip)(...(attrs.steps || []).map((tag)=>{
|
|
265
310
|
const stepCount = ++stepCountByTag[tag];
|
|
266
|
-
|
|
311
|
+
switch(tag){
|
|
312
|
+
case "email":
|
|
313
|
+
case "sms":
|
|
314
|
+
case "push":
|
|
315
|
+
case "chat":
|
|
316
|
+
return stepScaffoldFuncs[tag](stepCount, (0, _lodash.get)(channelsByType, tag, []));
|
|
317
|
+
case "in-app-feed":
|
|
318
|
+
return stepScaffoldFuncs[tag](stepCount, (0, _lodash.get)(channelsByType, "in_app_feed", []));
|
|
319
|
+
default:
|
|
320
|
+
return stepScaffoldFuncs[tag](stepCount);
|
|
321
|
+
}
|
|
267
322
|
}));
|
|
268
323
|
// Build a workflow directory bundle with scaffolded steps data, plus other
|
|
269
324
|
// workflow attributes.
|
|
@@ -275,7 +330,108 @@ const scaffoldWorkflowDirBundle = (attrs)=>{
|
|
|
275
330
|
[_processorisomorphic.WORKFLOW_JSON]: workflowJson
|
|
276
331
|
}, ...bundleFragments);
|
|
277
332
|
};
|
|
278
|
-
const generateWorkflowDir = async (workflowDirCtx, attrs)=>{
|
|
279
|
-
const bundle = scaffoldWorkflowDirBundle(attrs);
|
|
333
|
+
const generateWorkflowDir = async (workflowDirCtx, attrs, channelsByType)=>{
|
|
334
|
+
const bundle = scaffoldWorkflowDirBundle(attrs, channelsByType);
|
|
280
335
|
return (0, _writer.writeWorkflowDirFromBundle)(workflowDirCtx, bundle);
|
|
281
336
|
};
|
|
337
|
+
function swapChannelReferences(step, channelsByType) {
|
|
338
|
+
// Temporary until we start shipping the `channel_type` field on channel steps
|
|
339
|
+
// so that we can then branch by that value.
|
|
340
|
+
switch(step.channel_key){
|
|
341
|
+
case "postmark":
|
|
342
|
+
case "sendgrid":
|
|
343
|
+
case "resend":
|
|
344
|
+
case "email":
|
|
345
|
+
case "knock-email":
|
|
346
|
+
var _channelsByType_email_;
|
|
347
|
+
return {
|
|
348
|
+
...step,
|
|
349
|
+
channel_key: (_channelsByType_email_ = channelsByType.email[0]) === null || _channelsByType_email_ === void 0 ? void 0 : _channelsByType_email_.key
|
|
350
|
+
};
|
|
351
|
+
case "in-app-feed":
|
|
352
|
+
case "knock-in-app-feed":
|
|
353
|
+
case "knock-feed":
|
|
354
|
+
var _channelsByType_in_app_feed_;
|
|
355
|
+
return {
|
|
356
|
+
...step,
|
|
357
|
+
channel_key: (_channelsByType_in_app_feed_ = channelsByType.in_app_feed[0]) === null || _channelsByType_in_app_feed_ === void 0 ? void 0 : _channelsByType_in_app_feed_.key
|
|
358
|
+
};
|
|
359
|
+
case "sms":
|
|
360
|
+
case "knock-sms":
|
|
361
|
+
case "twilio":
|
|
362
|
+
var _channelsByType_sms_;
|
|
363
|
+
return {
|
|
364
|
+
...step,
|
|
365
|
+
channel_key: (_channelsByType_sms_ = channelsByType.sms[0]) === null || _channelsByType_sms_ === void 0 ? void 0 : _channelsByType_sms_.key
|
|
366
|
+
};
|
|
367
|
+
case "push":
|
|
368
|
+
case "apns":
|
|
369
|
+
case "fcm":
|
|
370
|
+
var _channelsByType_push_;
|
|
371
|
+
return {
|
|
372
|
+
...step,
|
|
373
|
+
channel_key: (_channelsByType_push_ = channelsByType.push[0]) === null || _channelsByType_push_ === void 0 ? void 0 : _channelsByType_push_.key
|
|
374
|
+
};
|
|
375
|
+
case "chat":
|
|
376
|
+
var _channelsByType_chat_;
|
|
377
|
+
return {
|
|
378
|
+
...step,
|
|
379
|
+
channel_key: (_channelsByType_chat_ = channelsByType.chat[0]) === null || _channelsByType_chat_ === void 0 ? void 0 : _channelsByType_chat_.key
|
|
380
|
+
};
|
|
381
|
+
default:
|
|
382
|
+
throw new Error(`Unknown channel type: ${step.channel_key}`);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
function walkWorkflowSteps(steps, channelsByType) {
|
|
386
|
+
return steps.map((step)=>{
|
|
387
|
+
switch(step.type){
|
|
388
|
+
case _types.StepType.Channel:
|
|
389
|
+
return swapChannelReferences(step, channelsByType);
|
|
390
|
+
case _types.StepType.Branch:
|
|
391
|
+
var _step_branches;
|
|
392
|
+
return {
|
|
393
|
+
...step,
|
|
394
|
+
branches: ((_step_branches = step.branches) !== null && _step_branches !== void 0 ? _step_branches : []).map((branch)=>{
|
|
395
|
+
var _branch_steps;
|
|
396
|
+
return {
|
|
397
|
+
...branch,
|
|
398
|
+
steps: walkWorkflowSteps((_branch_steps = branch.steps) !== null && _branch_steps !== void 0 ? _branch_steps : [], channelsByType)
|
|
399
|
+
};
|
|
400
|
+
})
|
|
401
|
+
};
|
|
402
|
+
default:
|
|
403
|
+
return step;
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
const generateWorkflowFromTemplate = async (workflowDirCtx, templateString, attrs, channelsByType)=>{
|
|
408
|
+
let tempDir;
|
|
409
|
+
try {
|
|
410
|
+
var _workflow_steps;
|
|
411
|
+
// Download the template directory into a temp directory
|
|
412
|
+
tempDir = await _templates.downloadTemplate(templateString);
|
|
413
|
+
// Create a workflow directory context for the temp directory
|
|
414
|
+
const tempWorkflowDirCtx = {
|
|
415
|
+
type: "workflow",
|
|
416
|
+
key: "temp",
|
|
417
|
+
abspath: tempDir,
|
|
418
|
+
exists: true
|
|
419
|
+
};
|
|
420
|
+
// Read the workflow.json from the temp directory we downloaded
|
|
421
|
+
const [workflow, errors] = await (0, _reader.readWorkflowDir)(tempWorkflowDirCtx, {
|
|
422
|
+
withExtractedFiles: true
|
|
423
|
+
});
|
|
424
|
+
if (errors.length > 0 || !workflow) {
|
|
425
|
+
throw new Error(`Invalid workflow template: ${errors.join(", ")}`);
|
|
426
|
+
}
|
|
427
|
+
// Modify the workflow data with the new attributes
|
|
428
|
+
workflow.name = attrs.name;
|
|
429
|
+
// Parse the workflow steps, and replace any channel steps with the correct `channel_key`
|
|
430
|
+
workflow.steps = walkWorkflowSteps((_workflow_steps = workflow.steps) !== null && _workflow_steps !== void 0 ? _workflow_steps : [], channelsByType);
|
|
431
|
+
// Finally, we write the workflow into the target workflow directory
|
|
432
|
+
(0, _writer.writeWorkflowDirFromData)(workflowDirCtx, workflow);
|
|
433
|
+
return;
|
|
434
|
+
} finally{
|
|
435
|
+
await _templates.cleanupTempDir(tempDir);
|
|
436
|
+
}
|
|
437
|
+
};
|
|
@@ -45,6 +45,7 @@ const _core = require("@oclif/core");
|
|
|
45
45
|
const _fsextra = /*#__PURE__*/ _interop_require_wildcard(require("fs-extra"));
|
|
46
46
|
const _lodash = require("lodash");
|
|
47
47
|
const _quicktypecore = require("quicktype-core");
|
|
48
|
+
const _projectconfig = require("../../helpers/project-config");
|
|
48
49
|
const _string = require("../../helpers/string");
|
|
49
50
|
const _typegen = require("../../helpers/typegen");
|
|
50
51
|
const _processorisomorphic = require("./processor.isomorphic");
|
|
@@ -197,7 +198,7 @@ const formatStepSummary = (step)=>{
|
|
|
197
198
|
const formatStatus = (workflow)=>{
|
|
198
199
|
return workflow.active ? "active" : "inactive";
|
|
199
200
|
};
|
|
200
|
-
const ensureValidCommandTarget = async (props, runContext)=>{
|
|
201
|
+
const ensureValidCommandTarget = async (props, runContext, projectConfig)=>{
|
|
201
202
|
const { args, flags } = props;
|
|
202
203
|
const { commandId, resourceDir: resourceDirCtx, cwd: runCwd } = runContext;
|
|
203
204
|
// If the target resource is a different type than the current resource dir
|
|
@@ -209,6 +210,9 @@ const ensureValidCommandTarget = async (props, runContext)=>{
|
|
|
209
210
|
if (flags.all && args.workflowKey) {
|
|
210
211
|
return _core.ux.error(`workflowKey arg \`${args.workflowKey}\` cannot also be provided when using --all`);
|
|
211
212
|
}
|
|
213
|
+
// Targeting all workflow dirs in the workflows index dir.
|
|
214
|
+
// Default to knock project config first if present, otherwise cwd.
|
|
215
|
+
const workflowsIndexDirCtx = await (0, _projectconfig.resolveResourceDir)(projectConfig, "workflow", runCwd);
|
|
212
216
|
// --all flag is given, which means no workflow key arg.
|
|
213
217
|
if (flags.all) {
|
|
214
218
|
// If --all flag used inside a workflow directory, then require a workflows
|
|
@@ -216,16 +220,9 @@ const ensureValidCommandTarget = async (props, runContext)=>{
|
|
|
216
220
|
if (resourceDirCtx && !flags["workflows-dir"]) {
|
|
217
221
|
return _core.ux.error("Missing required flag workflows-dir");
|
|
218
222
|
}
|
|
219
|
-
// Targeting all workflow dirs in the workflows index dir.
|
|
220
|
-
// TODO: Default to the knock project config first if present before cwd.
|
|
221
|
-
const defaultToCwd = {
|
|
222
|
-
abspath: runCwd,
|
|
223
|
-
exists: true
|
|
224
|
-
};
|
|
225
|
-
const indexDirCtx = flags["workflows-dir"] || defaultToCwd;
|
|
226
223
|
return {
|
|
227
224
|
type: "workflowsIndexDir",
|
|
228
|
-
context:
|
|
225
|
+
context: flags["workflows-dir"] || workflowsIndexDirCtx
|
|
229
226
|
};
|
|
230
227
|
}
|
|
231
228
|
// Workflow key arg is given, which means no --all flag.
|
|
@@ -233,7 +230,7 @@ const ensureValidCommandTarget = async (props, runContext)=>{
|
|
|
233
230
|
if (resourceDirCtx && resourceDirCtx.key !== args.workflowKey) {
|
|
234
231
|
return _core.ux.error(`Cannot run ${commandId} \`${args.workflowKey}\` inside another workflow directory:\n${resourceDirCtx.key}`);
|
|
235
232
|
}
|
|
236
|
-
const targetDirPath = resourceDirCtx ? resourceDirCtx.abspath : _nodepath.resolve(
|
|
233
|
+
const targetDirPath = resourceDirCtx ? resourceDirCtx.abspath : _nodepath.resolve(workflowsIndexDirCtx.abspath, args.workflowKey);
|
|
237
234
|
const workflowDirCtx = {
|
|
238
235
|
type: "workflow",
|
|
239
236
|
key: args.workflowKey,
|
|
@@ -14,6 +14,7 @@ Object.defineProperty(exports, "load", {
|
|
|
14
14
|
});
|
|
15
15
|
const _nodepath = /*#__PURE__*/ _interop_require_wildcard(require("node:path"));
|
|
16
16
|
const _emaillayout = /*#__PURE__*/ _interop_require_wildcard(require("../marshal/email-layout"));
|
|
17
|
+
const _guide = /*#__PURE__*/ _interop_require_wildcard(require("../marshal/guide"));
|
|
17
18
|
const _messagetype = /*#__PURE__*/ _interop_require_wildcard(require("../marshal/message-type"));
|
|
18
19
|
const _partial = /*#__PURE__*/ _interop_require_wildcard(require("../marshal/partial"));
|
|
19
20
|
const _translation = /*#__PURE__*/ _interop_require_wildcard(require("../marshal/translation"));
|
|
@@ -74,6 +75,10 @@ const evaluateRecursively = async (ctx, currDir)=>{
|
|
|
74
75
|
if (isWorkflowDir) {
|
|
75
76
|
ctx.resourceDir = buildResourceDirContext("workflow", currDir);
|
|
76
77
|
}
|
|
78
|
+
const isGuideDir = await _guide.isGuideDir(currDir);
|
|
79
|
+
if (isGuideDir) {
|
|
80
|
+
ctx.resourceDir = buildResourceDirContext("guide", currDir);
|
|
81
|
+
}
|
|
77
82
|
const isEmailLayoutDir = await _emaillayout.isEmailLayoutDir(currDir);
|
|
78
83
|
if (isEmailLayoutDir) {
|
|
79
84
|
ctx.resourceDir = buildResourceDirContext("email_layout", currDir);
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get cleanupTempDir () {
|
|
13
|
+
return cleanupTempDir;
|
|
14
|
+
},
|
|
15
|
+
get downloadTemplate () {
|
|
16
|
+
return downloadTemplate;
|
|
17
|
+
},
|
|
18
|
+
get resolveTemplate () {
|
|
19
|
+
return resolveTemplate;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
const _nodeos = /*#__PURE__*/ _interop_require_wildcard(require("node:os"));
|
|
23
|
+
const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path"));
|
|
24
|
+
const _degit = /*#__PURE__*/ _interop_require_default(require("degit"));
|
|
25
|
+
const _fsextra = /*#__PURE__*/ _interop_require_wildcard(require("fs-extra"));
|
|
26
|
+
function _interop_require_default(obj) {
|
|
27
|
+
return obj && obj.__esModule ? obj : {
|
|
28
|
+
default: obj
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
32
|
+
if (typeof WeakMap !== "function") return null;
|
|
33
|
+
var cacheBabelInterop = new WeakMap();
|
|
34
|
+
var cacheNodeInterop = new WeakMap();
|
|
35
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
36
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
37
|
+
})(nodeInterop);
|
|
38
|
+
}
|
|
39
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
40
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
41
|
+
return obj;
|
|
42
|
+
}
|
|
43
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
44
|
+
return {
|
|
45
|
+
default: obj
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
49
|
+
if (cache && cache.has(obj)) {
|
|
50
|
+
return cache.get(obj);
|
|
51
|
+
}
|
|
52
|
+
var newObj = {
|
|
53
|
+
__proto__: null
|
|
54
|
+
};
|
|
55
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
56
|
+
for(var key in obj){
|
|
57
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
58
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
59
|
+
if (desc && (desc.get || desc.set)) {
|
|
60
|
+
Object.defineProperty(newObj, key, desc);
|
|
61
|
+
} else {
|
|
62
|
+
newObj[key] = obj[key];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
newObj.default = obj;
|
|
67
|
+
if (cache) {
|
|
68
|
+
cache.set(obj, newObj);
|
|
69
|
+
}
|
|
70
|
+
return newObj;
|
|
71
|
+
}
|
|
72
|
+
const DEFAULT_ORG = "knocklabs";
|
|
73
|
+
const DEFAULT_REPO = "templates";
|
|
74
|
+
const TEMP_DIR_PREFIX = "knock-cli-templates";
|
|
75
|
+
function resolveTemplate(templateString) {
|
|
76
|
+
const parts = templateString.split("/");
|
|
77
|
+
let org;
|
|
78
|
+
let repo;
|
|
79
|
+
let subdir;
|
|
80
|
+
if (parts.length === 2) {
|
|
81
|
+
// workflows/some-workflow
|
|
82
|
+
org = DEFAULT_ORG;
|
|
83
|
+
repo = DEFAULT_REPO;
|
|
84
|
+
subdir = parts.join("/");
|
|
85
|
+
}
|
|
86
|
+
if (parts.length === 4) {
|
|
87
|
+
// knocklabs/templates/workflows/some-workflow
|
|
88
|
+
org = parts[0];
|
|
89
|
+
repo = parts[1];
|
|
90
|
+
subdir = parts.slice(2).join("/");
|
|
91
|
+
}
|
|
92
|
+
if (!org || !repo || !subdir) {
|
|
93
|
+
throw new Error(`Invalid template string: ${templateString}. Expected format: org/repo/subdir`);
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
org,
|
|
97
|
+
repo,
|
|
98
|
+
subdir
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function buildSource(org, repo, subdir, branch = "main") {
|
|
102
|
+
const base = `${org}/${repo}`;
|
|
103
|
+
if (subdir) {
|
|
104
|
+
return `${base}/${subdir}#${branch}`;
|
|
105
|
+
}
|
|
106
|
+
return `${base}#${branch}`;
|
|
107
|
+
}
|
|
108
|
+
async function downloadTemplate(templateString) {
|
|
109
|
+
const { org, repo, subdir } = resolveTemplate(templateString);
|
|
110
|
+
const source = buildSource(org, repo, subdir);
|
|
111
|
+
// Create temp directory for template
|
|
112
|
+
const tempDir = _nodepath.default.join(_nodeos.tmpdir(), TEMP_DIR_PREFIX, `${org}-${repo}-${subdir.replace(/\//g, "-")}-${Date.now()}`);
|
|
113
|
+
await _fsextra.ensureDir(tempDir);
|
|
114
|
+
try {
|
|
115
|
+
const emitter = (0, _degit.default)(source, {
|
|
116
|
+
cache: false,
|
|
117
|
+
force: true,
|
|
118
|
+
verbose: false
|
|
119
|
+
});
|
|
120
|
+
await emitter.clone(tempDir);
|
|
121
|
+
return tempDir;
|
|
122
|
+
} catch (error) {
|
|
123
|
+
await _fsextra.remove(tempDir);
|
|
124
|
+
throw new Error(`Failed to download template: ${error instanceof Error ? error.message : "Unknown error"}\n\nSource: ${source}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async function cleanupTempDir(tempDir) {
|
|
128
|
+
if (tempDir && tempDir.includes(TEMP_DIR_PREFIX)) {
|
|
129
|
+
await _fsextra.remove(tempDir);
|
|
130
|
+
}
|
|
131
|
+
}
|