@lightward/mechanic-cli 0.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.
- package/LICENSE +21 -0
- package/README.md +424 -0
- package/bin/mechanic.js +5 -0
- package/dist/auth.d.ts +10 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +104 -0
- package/dist/base-command.d.ts +20 -0
- package/dist/base-command.d.ts.map +1 -0
- package/dist/base-command.js +82 -0
- package/dist/client.d.ts +40 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +172 -0
- package/dist/commands/auth/login.d.ts +10 -0
- package/dist/commands/auth/login.d.ts.map +1 -0
- package/dist/commands/auth/login.js +36 -0
- package/dist/commands/auth/logout.d.ts +6 -0
- package/dist/commands/auth/logout.d.ts.map +1 -0
- package/dist/commands/auth/logout.js +10 -0
- package/dist/commands/doctor.d.ts +7 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +106 -0
- package/dist/commands/github/init.d.ts +10 -0
- package/dist/commands/github/init.d.ts.map +1 -0
- package/dist/commands/github/init.js +50 -0
- package/dist/commands/help.d.ts +7 -0
- package/dist/commands/help.d.ts.map +1 -0
- package/dist/commands/help.js +10 -0
- package/dist/commands/init.d.ts +13 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +72 -0
- package/dist/commands/shop/status.d.ts +10 -0
- package/dist/commands/shop/status.d.ts.map +1 -0
- package/dist/commands/shop/status.js +138 -0
- package/dist/commands/tasks/bundle.d.ts +16 -0
- package/dist/commands/tasks/bundle.d.ts.map +1 -0
- package/dist/commands/tasks/bundle.js +83 -0
- package/dist/commands/tasks/diff.d.ts +16 -0
- package/dist/commands/tasks/diff.d.ts.map +1 -0
- package/dist/commands/tasks/diff.js +124 -0
- package/dist/commands/tasks/list.d.ts +11 -0
- package/dist/commands/tasks/list.d.ts.map +1 -0
- package/dist/commands/tasks/list.js +57 -0
- package/dist/commands/tasks/open.d.ts +13 -0
- package/dist/commands/tasks/open.d.ts.map +1 -0
- package/dist/commands/tasks/open.js +64 -0
- package/dist/commands/tasks/preview.d.ts +45 -0
- package/dist/commands/tasks/preview.d.ts.map +1 -0
- package/dist/commands/tasks/preview.js +373 -0
- package/dist/commands/tasks/publish.d.ts +16 -0
- package/dist/commands/tasks/publish.d.ts.map +1 -0
- package/dist/commands/tasks/publish.js +16 -0
- package/dist/commands/tasks/pull.d.ts +14 -0
- package/dist/commands/tasks/pull.d.ts.map +1 -0
- package/dist/commands/tasks/pull.js +96 -0
- package/dist/commands/tasks/push.d.ts +60 -0
- package/dist/commands/tasks/push.d.ts.map +1 -0
- package/dist/commands/tasks/push.js +370 -0
- package/dist/commands/tasks/status.d.ts +30 -0
- package/dist/commands/tasks/status.d.ts.map +1 -0
- package/dist/commands/tasks/status.js +183 -0
- package/dist/commands/tasks/unbundle.d.ts +16 -0
- package/dist/commands/tasks/unbundle.d.ts.map +1 -0
- package/dist/commands/tasks/unbundle.js +84 -0
- package/dist/commands/tasks/validate.d.ts +15 -0
- package/dist/commands/tasks/validate.d.ts.map +1 -0
- package/dist/commands/tasks/validate.js +78 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +227 -0
- package/dist/errors.d.ts +10 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +18 -0
- package/dist/fs.d.ts +10 -0
- package/dist/fs.d.ts.map +1 -0
- package/dist/fs.js +51 -0
- package/dist/github-workflows.d.ts +6 -0
- package/dist/github-workflows.d.ts.map +1 -0
- package/dist/github-workflows.js +293 -0
- package/dist/hash.d.ts +2 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +5 -0
- package/dist/json.d.ts +4 -0
- package/dist/json.d.ts.map +1 -0
- package/dist/json.js +30 -0
- package/dist/tasks.d.ts +48 -0
- package/dist/tasks.d.ts.map +1 -0
- package/dist/tasks.js +546 -0
- package/dist/types.d.ts +144 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +80 -0
- package/schemas/mechanic.schema.json +13 -0
- package/schemas/task-config.schema.json +23 -0
package/dist/tasks.js
ADDED
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { CliError } from "./errors.js";
|
|
4
|
+
import { ensureDir, pathExists, readJson, readText, removeFile, writeJson, writeText } from "./fs.js";
|
|
5
|
+
import { stableStringify } from "./json.js";
|
|
6
|
+
const SPLIT_FILES = [
|
|
7
|
+
["script", "script.liquid"],
|
|
8
|
+
["docs", "docs.md"],
|
|
9
|
+
["subscriptions_template", "subscriptions.liquid"],
|
|
10
|
+
["online_store_javascript", "online_store_javascript.js.liquid"],
|
|
11
|
+
["order_status_javascript", "order_status_javascript.js.liquid"],
|
|
12
|
+
];
|
|
13
|
+
const REMOTE_TASK_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
14
|
+
export function taskSlug(input) {
|
|
15
|
+
const slug = input
|
|
16
|
+
.toLowerCase()
|
|
17
|
+
.trim()
|
|
18
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
19
|
+
.replace(/^-+|-+$/g, "");
|
|
20
|
+
return slug || "task";
|
|
21
|
+
}
|
|
22
|
+
export async function taskFiles(project) {
|
|
23
|
+
if (!(await pathExists(project.tasksDir))) {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
const entries = await fs.readdir(project.tasksDir, { withFileTypes: true });
|
|
27
|
+
return entries
|
|
28
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith(".json"))
|
|
29
|
+
.map((entry) => path.join(project.tasksDir, entry.name))
|
|
30
|
+
.sort();
|
|
31
|
+
}
|
|
32
|
+
export function slugFromTaskFile(filePath) {
|
|
33
|
+
return taskSlug(path.basename(filePath, ".json"));
|
|
34
|
+
}
|
|
35
|
+
export function taskPath(project, slug) {
|
|
36
|
+
return path.join(project.tasksDir, `${slug}.json`);
|
|
37
|
+
}
|
|
38
|
+
function displayPath(filePath) {
|
|
39
|
+
return filePath.replace(/\\/g, "/");
|
|
40
|
+
}
|
|
41
|
+
export function displayTaskPath(project, filePath) {
|
|
42
|
+
const absolutePath = path.resolve(filePath);
|
|
43
|
+
const absoluteTasksDir = path.resolve(project.tasksDir);
|
|
44
|
+
const relativeToTasksDir = path.relative(absoluteTasksDir, absolutePath);
|
|
45
|
+
if (relativeToTasksDir && !relativeToTasksDir.startsWith("..") && !path.isAbsolute(relativeToTasksDir)) {
|
|
46
|
+
return displayPath(path.join(project.tasksDirName, relativeToTasksDir));
|
|
47
|
+
}
|
|
48
|
+
const segments = absolutePath.split(path.sep);
|
|
49
|
+
const tasksSegmentIndex = segments.lastIndexOf(path.basename(project.tasksDirName));
|
|
50
|
+
if (tasksSegmentIndex >= 0 && tasksSegmentIndex < segments.length - 1) {
|
|
51
|
+
return displayPath(segments.slice(tasksSegmentIndex).join(path.sep));
|
|
52
|
+
}
|
|
53
|
+
return displayPath(path.relative(project.cwd, absolutePath));
|
|
54
|
+
}
|
|
55
|
+
function duplicateTaskSlugMessages(project, files) {
|
|
56
|
+
const filesBySlug = new Map();
|
|
57
|
+
for (const file of files) {
|
|
58
|
+
const slug = slugFromTaskFile(file);
|
|
59
|
+
filesBySlug.set(slug, [...(filesBySlug.get(slug) || []), displayTaskPath(project, file)]);
|
|
60
|
+
}
|
|
61
|
+
return [...filesBySlug.entries()].flatMap(([slug, slugFiles]) => {
|
|
62
|
+
if (slugFiles.length < 2) {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
return [`- ${slug}: ${slugFiles.join(", ")}`];
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
export async function readTaskFile(filePath) {
|
|
69
|
+
return stripTaskIds(await readRawTaskFile(filePath));
|
|
70
|
+
}
|
|
71
|
+
export async function readRawTaskFile(filePath) {
|
|
72
|
+
const task = await readJson(filePath);
|
|
73
|
+
if (!task || typeof task !== "object" || Array.isArray(task)) {
|
|
74
|
+
throw new CliError(`${filePath} must contain a JSON object`);
|
|
75
|
+
}
|
|
76
|
+
return task;
|
|
77
|
+
}
|
|
78
|
+
function hasSubscriptionsTemplate(task) {
|
|
79
|
+
return task.subscriptions_template !== undefined && task.subscriptions_template !== null;
|
|
80
|
+
}
|
|
81
|
+
function stripTaskIds(task) {
|
|
82
|
+
const { id: _id, remote_id: _remoteId, ...exportTask } = task;
|
|
83
|
+
return exportTask;
|
|
84
|
+
}
|
|
85
|
+
function stripGeneratedFields(task) {
|
|
86
|
+
const exportTask = { ...task };
|
|
87
|
+
if (hasSubscriptionsTemplate(exportTask)) {
|
|
88
|
+
delete exportTask.subscriptions;
|
|
89
|
+
}
|
|
90
|
+
return exportTask;
|
|
91
|
+
}
|
|
92
|
+
function stripHelperMetadata(task) {
|
|
93
|
+
const { _mechanic: _helperMetadata, ...exportTask } = task;
|
|
94
|
+
return exportTask;
|
|
95
|
+
}
|
|
96
|
+
export async function writeTaskFilePath(filePath, task) {
|
|
97
|
+
await writeJson(filePath, stripGeneratedFields(stripTaskIds(task)));
|
|
98
|
+
return filePath;
|
|
99
|
+
}
|
|
100
|
+
export async function refreshHelperDirForTaskFile(filePath) {
|
|
101
|
+
const helperDir = helperDirForTaskFile(filePath);
|
|
102
|
+
if (helperDir && await pathExists(path.join(helperDir, "task.json"))) {
|
|
103
|
+
await unbundleTask(filePath, helperDir);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export async function writeTaskFilePathAndRefreshHelper(filePath, task) {
|
|
107
|
+
await writeTaskFilePath(filePath, task);
|
|
108
|
+
await refreshHelperDirForTaskFile(filePath);
|
|
109
|
+
return filePath;
|
|
110
|
+
}
|
|
111
|
+
export async function writeTaskFile(project, slug, task, force = false) {
|
|
112
|
+
const filePath = taskPath(project, slug);
|
|
113
|
+
if (!force && await pathExists(filePath)) {
|
|
114
|
+
throw new CliError(`${displayTaskPath(project, filePath)} already exists. Re-run with --force to overwrite.`);
|
|
115
|
+
}
|
|
116
|
+
return writeTaskFilePathAndRefreshHelper(filePath, task);
|
|
117
|
+
}
|
|
118
|
+
function uniqueStrings(values) {
|
|
119
|
+
return [...new Set(values)];
|
|
120
|
+
}
|
|
121
|
+
function looksLikeTaskPath(input) {
|
|
122
|
+
return input.endsWith(".json") || input.includes("/") || input.includes(path.sep);
|
|
123
|
+
}
|
|
124
|
+
function selectorSlug(input) {
|
|
125
|
+
const normalized = input.toLowerCase().endsWith(".json") ? input.slice(0, -".json".length) : input;
|
|
126
|
+
return taskSlug(path.basename(normalized));
|
|
127
|
+
}
|
|
128
|
+
async function statIfExists(filePath) {
|
|
129
|
+
try {
|
|
130
|
+
return await fs.stat(filePath);
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function linkForResolvedSlug(project, slug) {
|
|
140
|
+
return project.links.tasks[slug] || null;
|
|
141
|
+
}
|
|
142
|
+
function linkedTaskFile(project, slug, link) {
|
|
143
|
+
return path.resolve(project.cwd, link.file || `${project.tasksDirName}/${slug}.json`);
|
|
144
|
+
}
|
|
145
|
+
function selectorFromFile(project, input, file, source) {
|
|
146
|
+
const slug = slugFromTaskFile(file);
|
|
147
|
+
const link = linkForResolvedSlug(project, slug);
|
|
148
|
+
return {
|
|
149
|
+
input,
|
|
150
|
+
source,
|
|
151
|
+
slug,
|
|
152
|
+
file,
|
|
153
|
+
link,
|
|
154
|
+
remoteId: link?.remote_id,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
function selectorFromHelper(project, input, helperDir) {
|
|
158
|
+
const slug = taskSlug(path.basename(helperDir));
|
|
159
|
+
const link = linkForResolvedSlug(project, slug);
|
|
160
|
+
return {
|
|
161
|
+
input,
|
|
162
|
+
source: "helper",
|
|
163
|
+
slug,
|
|
164
|
+
file: `${helperDir}.json`,
|
|
165
|
+
helperDir,
|
|
166
|
+
link,
|
|
167
|
+
remoteId: link?.remote_id,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function selectorFromLink(project, input, slug, link, source) {
|
|
171
|
+
return {
|
|
172
|
+
input,
|
|
173
|
+
source,
|
|
174
|
+
slug,
|
|
175
|
+
file: linkedTaskFile(project, slug, link),
|
|
176
|
+
link,
|
|
177
|
+
remoteId: link.remote_id,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
function linkForRemoteId(project, remoteId) {
|
|
181
|
+
return Object.entries(project.links.tasks).find(([, link]) => link.remote_id === remoteId) || null;
|
|
182
|
+
}
|
|
183
|
+
function pathCandidatesForSelector(project, input) {
|
|
184
|
+
const raw = path.resolve(project.cwd, input);
|
|
185
|
+
const candidates = [raw];
|
|
186
|
+
if (!input.toLowerCase().endsWith(".json")) {
|
|
187
|
+
candidates.push(`${raw}.json`);
|
|
188
|
+
}
|
|
189
|
+
if (!looksLikeTaskPath(input)) {
|
|
190
|
+
const slug = selectorSlug(input);
|
|
191
|
+
candidates.push(path.join(project.tasksDir, slug));
|
|
192
|
+
candidates.push(taskPath(project, slug));
|
|
193
|
+
}
|
|
194
|
+
return uniqueStrings(candidates);
|
|
195
|
+
}
|
|
196
|
+
async function resolveExistingPathSelector(project, input, allowHelperDir) {
|
|
197
|
+
for (const candidate of pathCandidatesForSelector(project, input)) {
|
|
198
|
+
const stat = await statIfExists(candidate);
|
|
199
|
+
if (!stat) {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (stat.isFile()) {
|
|
203
|
+
return selectorFromFile(project, input, candidate, "file");
|
|
204
|
+
}
|
|
205
|
+
if (!stat.isDirectory()) {
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (!(await pathExists(path.join(candidate, "task.json")))) {
|
|
209
|
+
throw new CliError(`${displayTaskPath(project, candidate)} is a directory, not a Mechanic helper task directory.`);
|
|
210
|
+
}
|
|
211
|
+
if (allowHelperDir) {
|
|
212
|
+
return selectorFromHelper(project, input, candidate);
|
|
213
|
+
}
|
|
214
|
+
const siblingFile = `${candidate}.json`;
|
|
215
|
+
if (await pathExists(siblingFile)) {
|
|
216
|
+
return selectorFromFile(project, input, siblingFile, "helper");
|
|
217
|
+
}
|
|
218
|
+
throw new CliError([
|
|
219
|
+
`No canonical task JSON file found for helper directory ${displayTaskPath(project, candidate)}.`,
|
|
220
|
+
`Run "mechanic tasks bundle ${displayTaskPath(project, candidate)}" first.`,
|
|
221
|
+
].join("\n"), 2);
|
|
222
|
+
}
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
function ambiguousTaskSelectorError(project, input, files) {
|
|
226
|
+
return new CliError([
|
|
227
|
+
`More than one local task matched "${input}".`,
|
|
228
|
+
...files.map((file) => ` ${displayTaskPath(project, file)}`),
|
|
229
|
+
"",
|
|
230
|
+
"Use the full file path.",
|
|
231
|
+
].join("\n"), 2);
|
|
232
|
+
}
|
|
233
|
+
async function resolveLocalSlugSelector(project, input) {
|
|
234
|
+
const slug = selectorSlug(input);
|
|
235
|
+
const files = (await taskFiles(project)).filter((file) => slugFromTaskFile(file) === slug);
|
|
236
|
+
if (files.length > 1) {
|
|
237
|
+
throw ambiguousTaskSelectorError(project, input, files);
|
|
238
|
+
}
|
|
239
|
+
if (files.length === 1) {
|
|
240
|
+
return selectorFromFile(project, input, files[0], "slug");
|
|
241
|
+
}
|
|
242
|
+
const link = linkForResolvedSlug(project, slug);
|
|
243
|
+
if (link) {
|
|
244
|
+
return selectorFromLink(project, input, slug, link, "slug");
|
|
245
|
+
}
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
export async function resolveTaskSelector(project, input, options = {}) {
|
|
249
|
+
const local = await resolveExistingPathSelector(project, input, Boolean(options.allowHelperDir));
|
|
250
|
+
if (local) {
|
|
251
|
+
return local;
|
|
252
|
+
}
|
|
253
|
+
const remoteLink = linkForRemoteId(project, input);
|
|
254
|
+
if (remoteLink) {
|
|
255
|
+
return selectorFromLink(project, input, remoteLink[0], remoteLink[1], "linked_remote_id");
|
|
256
|
+
}
|
|
257
|
+
const slug = await resolveLocalSlugSelector(project, input);
|
|
258
|
+
if (slug) {
|
|
259
|
+
return slug;
|
|
260
|
+
}
|
|
261
|
+
if (options.allowRemoteId && REMOTE_TASK_ID_PATTERN.test(input)) {
|
|
262
|
+
return {
|
|
263
|
+
input,
|
|
264
|
+
source: "remote_id",
|
|
265
|
+
remoteId: input,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
if (REMOTE_TASK_ID_PATTERN.test(input)) {
|
|
269
|
+
throw new CliError([
|
|
270
|
+
`No local task file is linked to task ID ${input}.`,
|
|
271
|
+
`Run "mechanic tasks pull ${input}" first, or use "mechanic tasks preview --remote ${input}" to preview the current task in Mechanic.`,
|
|
272
|
+
].join("\n"), 2);
|
|
273
|
+
}
|
|
274
|
+
if (looksLikeTaskPath(input)) {
|
|
275
|
+
throw new CliError(`No local task file or helper directory found: ${input}`, 2);
|
|
276
|
+
}
|
|
277
|
+
throw new CliError(`No local task matched "${input}". Use a task file path or run "mechanic tasks pull" first.`, 2);
|
|
278
|
+
}
|
|
279
|
+
export async function selectedTaskFiles(project, input, all) {
|
|
280
|
+
if (input && all) {
|
|
281
|
+
throw new CliError("Use either a file argument or --all, not both.");
|
|
282
|
+
}
|
|
283
|
+
if (all) {
|
|
284
|
+
const files = await taskFiles(project);
|
|
285
|
+
if (files.length === 0) {
|
|
286
|
+
throw new CliError(`No task JSON files found in ${project.tasksDirName}`);
|
|
287
|
+
}
|
|
288
|
+
const duplicates = duplicateTaskSlugMessages(project, files);
|
|
289
|
+
if (duplicates.length > 0) {
|
|
290
|
+
throw new CliError([
|
|
291
|
+
"Multiple task files normalize to the same task slug.",
|
|
292
|
+
...duplicates,
|
|
293
|
+
"Rename one of the files before continuing.",
|
|
294
|
+
].join("\n"), 2);
|
|
295
|
+
}
|
|
296
|
+
return files;
|
|
297
|
+
}
|
|
298
|
+
if (!input) {
|
|
299
|
+
throw new CliError("A task file argument or --all is required.");
|
|
300
|
+
}
|
|
301
|
+
let selector;
|
|
302
|
+
try {
|
|
303
|
+
selector = await resolveTaskSelector(project, input);
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
if (looksLikeTaskPath(input)
|
|
307
|
+
&& error instanceof CliError
|
|
308
|
+
&& error.message.startsWith("No local task file or helper directory found:")) {
|
|
309
|
+
return [path.resolve(project.cwd, input)];
|
|
310
|
+
}
|
|
311
|
+
throw error;
|
|
312
|
+
}
|
|
313
|
+
if (!selector.file) {
|
|
314
|
+
throw new CliError(`No local task file found for ${input}.`, 2);
|
|
315
|
+
}
|
|
316
|
+
return [selector.file];
|
|
317
|
+
}
|
|
318
|
+
export function remoteChangedSinceLastPull(link, remote) {
|
|
319
|
+
return remote.content_hash !== link.last_remote_content_hash;
|
|
320
|
+
}
|
|
321
|
+
export function remoteChangedSinceLastPullDetails(force = false) {
|
|
322
|
+
return force ? "remote changed since last pull; --force set" : "remote changed since last pull";
|
|
323
|
+
}
|
|
324
|
+
export function remoteChangedSinceLastPullMessage(relativeFile, remoteId) {
|
|
325
|
+
return `${relativeFile} has remote changes since the last pull. Run "mechanic tasks diff ${relativeFile}" to review, then "mechanic tasks pull ${remoteId}" to keep the remote version, or re-run with --force only if the local file should win.`;
|
|
326
|
+
}
|
|
327
|
+
export function taskForPush(task) {
|
|
328
|
+
const { enabled: _enabled, id: _id, remote_id: _remoteId, ...payload } = task;
|
|
329
|
+
return stripGeneratedFields(payload);
|
|
330
|
+
}
|
|
331
|
+
export async function nextAvailableSlug(project, baseSlug) {
|
|
332
|
+
const existing = new Set((await taskFiles(project)).map((filePath) => slugFromTaskFile(filePath)));
|
|
333
|
+
let candidate = baseSlug;
|
|
334
|
+
let suffix = 2;
|
|
335
|
+
while (existing.has(candidate)) {
|
|
336
|
+
candidate = `${baseSlug}-${suffix}`;
|
|
337
|
+
suffix += 1;
|
|
338
|
+
}
|
|
339
|
+
return candidate;
|
|
340
|
+
}
|
|
341
|
+
export async function taskFromHelperDir(dirPath) {
|
|
342
|
+
return stripTaskIds(await rawTaskFromHelperDir(dirPath));
|
|
343
|
+
}
|
|
344
|
+
export function helperDirForTaskFile(filePath) {
|
|
345
|
+
if (!filePath.toLowerCase().endsWith(".json")) {
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
return filePath.slice(0, -".json".length);
|
|
349
|
+
}
|
|
350
|
+
export async function unbundledHelperDirForTaskFile(filePath, task) {
|
|
351
|
+
const helperDir = helperDirForTaskFile(filePath);
|
|
352
|
+
if (!helperDir || !(await pathExists(path.join(helperDir, "task.json")))) {
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
const helperTask = await taskFromHelperDir(helperDir);
|
|
356
|
+
return stableStringify(taskForPush(helperTask)) === stableStringify(taskForPush(stripTaskIds(task))) ? null : helperDir;
|
|
357
|
+
}
|
|
358
|
+
export async function rawTaskFromHelperDir(dirPath) {
|
|
359
|
+
const base = await readJson(path.join(dirPath, "task.json"));
|
|
360
|
+
if (!base || typeof base !== "object" || Array.isArray(base)) {
|
|
361
|
+
throw new CliError(`${path.join(dirPath, "task.json")} must contain a JSON object`);
|
|
362
|
+
}
|
|
363
|
+
const task = stripHelperMetadata({ ...base });
|
|
364
|
+
for (const [field, fileName] of SPLIT_FILES) {
|
|
365
|
+
const filePath = path.join(dirPath, fileName);
|
|
366
|
+
if (await pathExists(filePath)) {
|
|
367
|
+
task[field] = await readText(filePath);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return task;
|
|
371
|
+
}
|
|
372
|
+
export async function unbundleTask(filePath, outDir) {
|
|
373
|
+
const task = await readTaskFile(filePath);
|
|
374
|
+
const taskJson = { ...task };
|
|
375
|
+
await ensureDir(outDir);
|
|
376
|
+
for (const [field, fileName] of SPLIT_FILES) {
|
|
377
|
+
const value = task[field];
|
|
378
|
+
const helperPath = path.join(outDir, fileName);
|
|
379
|
+
if (typeof value === "string") {
|
|
380
|
+
delete taskJson[field];
|
|
381
|
+
await writeText(helperPath, value);
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
await removeFile(helperPath);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
if (hasSubscriptionsTemplate(task)) {
|
|
388
|
+
delete taskJson.subscriptions;
|
|
389
|
+
}
|
|
390
|
+
await writeJson(path.join(outDir, "task.json"), taskJson);
|
|
391
|
+
}
|
|
392
|
+
export async function bundleTask(dirPath, outFile) {
|
|
393
|
+
await writeJson(outFile, await taskFromHelperDir(dirPath));
|
|
394
|
+
}
|
|
395
|
+
export function validateTask(task, source) {
|
|
396
|
+
const errors = [];
|
|
397
|
+
if ("id" in task || "remote_id" in task) {
|
|
398
|
+
errors.push("Task export must not include id or remote_id.");
|
|
399
|
+
}
|
|
400
|
+
if (typeof task.name !== "string" || task.name.trim() === "") {
|
|
401
|
+
errors.push("Task export must include a non-empty name.");
|
|
402
|
+
}
|
|
403
|
+
if ("script" in task && task.script !== null && typeof task.script !== "string") {
|
|
404
|
+
errors.push("script must be a string or null when present.");
|
|
405
|
+
}
|
|
406
|
+
if ("docs" in task && task.docs !== null && typeof task.docs !== "string") {
|
|
407
|
+
errors.push("docs must be a string or null when present.");
|
|
408
|
+
}
|
|
409
|
+
if ("subscriptions_template" in task
|
|
410
|
+
&& task.subscriptions_template !== null
|
|
411
|
+
&& typeof task.subscriptions_template !== "string") {
|
|
412
|
+
errors.push("subscriptions_template must be a string or null when present.");
|
|
413
|
+
}
|
|
414
|
+
if ("online_store_javascript" in task
|
|
415
|
+
&& task.online_store_javascript !== null
|
|
416
|
+
&& typeof task.online_store_javascript !== "string") {
|
|
417
|
+
errors.push("online_store_javascript must be a string or null when present.");
|
|
418
|
+
}
|
|
419
|
+
if ("order_status_javascript" in task
|
|
420
|
+
&& task.order_status_javascript !== null
|
|
421
|
+
&& typeof task.order_status_javascript !== "string") {
|
|
422
|
+
errors.push("order_status_javascript must be a string or null when present.");
|
|
423
|
+
}
|
|
424
|
+
if ("options" in task && (!task.options || typeof task.options !== "object" || Array.isArray(task.options))) {
|
|
425
|
+
errors.push("options must be an object when present.");
|
|
426
|
+
}
|
|
427
|
+
if ("preview_event_definitions" in task && !Array.isArray(task.preview_event_definitions)) {
|
|
428
|
+
errors.push("preview_event_definitions must be an array when present.");
|
|
429
|
+
}
|
|
430
|
+
if ("tags" in task && !Array.isArray(task.tags)) {
|
|
431
|
+
errors.push("tags must be an array when present.");
|
|
432
|
+
}
|
|
433
|
+
return {
|
|
434
|
+
ok: errors.length === 0,
|
|
435
|
+
source,
|
|
436
|
+
errors,
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
export function validateTaskForPush(task, source) {
|
|
440
|
+
return validateTask(task, source);
|
|
441
|
+
}
|
|
442
|
+
function comparableTaskValue(value) {
|
|
443
|
+
return value === undefined ? "(missing)" : String(stableStringify(value));
|
|
444
|
+
}
|
|
445
|
+
function taskValueLines(value) {
|
|
446
|
+
if (value === undefined) {
|
|
447
|
+
return ["(missing)"];
|
|
448
|
+
}
|
|
449
|
+
if (typeof value === "string") {
|
|
450
|
+
const lines = value.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
|
|
451
|
+
if (lines.length > 1 && lines[lines.length - 1] === "") {
|
|
452
|
+
lines.pop();
|
|
453
|
+
}
|
|
454
|
+
return lines;
|
|
455
|
+
}
|
|
456
|
+
return String(stableStringify(value)).split("\n");
|
|
457
|
+
}
|
|
458
|
+
function lineDiff(remoteLines, localLines) {
|
|
459
|
+
const scores = Array.from({ length: remoteLines.length + 1 }, () => (Array.from({ length: localLines.length + 1 }, () => 0)));
|
|
460
|
+
for (let remoteIndex = remoteLines.length - 1; remoteIndex >= 0; remoteIndex -= 1) {
|
|
461
|
+
for (let localIndex = localLines.length - 1; localIndex >= 0; localIndex -= 1) {
|
|
462
|
+
scores[remoteIndex][localIndex] = remoteLines[remoteIndex] === localLines[localIndex]
|
|
463
|
+
? scores[remoteIndex + 1][localIndex + 1] + 1
|
|
464
|
+
: Math.max(scores[remoteIndex + 1][localIndex], scores[remoteIndex][localIndex + 1]);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
const operations = [];
|
|
468
|
+
let remoteIndex = 0;
|
|
469
|
+
let localIndex = 0;
|
|
470
|
+
while (remoteIndex < remoteLines.length || localIndex < localLines.length) {
|
|
471
|
+
if (remoteIndex < remoteLines.length
|
|
472
|
+
&& localIndex < localLines.length
|
|
473
|
+
&& remoteLines[remoteIndex] === localLines[localIndex]) {
|
|
474
|
+
operations.push({ kind: "context", line: remoteLines[remoteIndex] });
|
|
475
|
+
remoteIndex += 1;
|
|
476
|
+
localIndex += 1;
|
|
477
|
+
}
|
|
478
|
+
else if (remoteIndex < remoteLines.length
|
|
479
|
+
&& (localIndex >= localLines.length
|
|
480
|
+
|| scores[remoteIndex + 1][localIndex] >= scores[remoteIndex][localIndex + 1])) {
|
|
481
|
+
operations.push({ kind: "remove", line: remoteLines[remoteIndex] });
|
|
482
|
+
remoteIndex += 1;
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
operations.push({ kind: "add", line: localLines[localIndex] });
|
|
486
|
+
localIndex += 1;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
return operations;
|
|
490
|
+
}
|
|
491
|
+
function formattedLineDiff(remoteLines, localLines) {
|
|
492
|
+
const operations = lineDiff(remoteLines, localLines);
|
|
493
|
+
const changeIndexes = operations.flatMap((operation, index) => (operation.kind === "context" ? [] : [index]));
|
|
494
|
+
if (changeIndexes.length === 0) {
|
|
495
|
+
return [];
|
|
496
|
+
}
|
|
497
|
+
const contextLineCount = 3;
|
|
498
|
+
const ranges = [];
|
|
499
|
+
for (const index of changeIndexes) {
|
|
500
|
+
const start = Math.max(0, index - contextLineCount);
|
|
501
|
+
const end = Math.min(operations.length - 1, index + contextLineCount);
|
|
502
|
+
const previous = ranges[ranges.length - 1];
|
|
503
|
+
if (previous && start <= previous.end + 1) {
|
|
504
|
+
previous.end = Math.max(previous.end, end);
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
ranges.push({ start, end });
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
return ranges.flatMap((range) => {
|
|
511
|
+
const lines = ["@@"];
|
|
512
|
+
for (let index = range.start; index <= range.end; index += 1) {
|
|
513
|
+
const operation = operations[index];
|
|
514
|
+
const prefix = operation.kind === "add"
|
|
515
|
+
? "+"
|
|
516
|
+
: operation.kind === "remove" ? "-" : " ";
|
|
517
|
+
lines.push(`${prefix}${operation.line}`);
|
|
518
|
+
}
|
|
519
|
+
return lines;
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
function formattedValueDiff(remoteValue, localValue) {
|
|
523
|
+
const lines = formattedLineDiff(taskValueLines(remoteValue), taskValueLines(localValue));
|
|
524
|
+
if (lines.length > 0) {
|
|
525
|
+
return lines;
|
|
526
|
+
}
|
|
527
|
+
return [
|
|
528
|
+
"@@",
|
|
529
|
+
`-${comparableTaskValue(remoteValue)}`,
|
|
530
|
+
`+${comparableTaskValue(localValue)}`,
|
|
531
|
+
];
|
|
532
|
+
}
|
|
533
|
+
export function diffTasks(local, remote) {
|
|
534
|
+
const comparableLocal = stripGeneratedFields(local);
|
|
535
|
+
const comparableRemote = stripGeneratedFields(remote);
|
|
536
|
+
const fields = [...new Set([...Object.keys(comparableRemote), ...Object.keys(comparableLocal)])].sort();
|
|
537
|
+
const changedFields = fields.filter((field) => (comparableTaskValue(comparableLocal[field]) !== comparableTaskValue(comparableRemote[field])));
|
|
538
|
+
if (changedFields.length === 0) {
|
|
539
|
+
return null;
|
|
540
|
+
}
|
|
541
|
+
const sections = [`Changed fields: ${changedFields.join(", ")}`];
|
|
542
|
+
for (const field of changedFields) {
|
|
543
|
+
sections.push("", `## ${field}`, "--- remote", "+++ local", ...formattedValueDiff(comparableRemote[field], comparableLocal[field]));
|
|
544
|
+
}
|
|
545
|
+
return sections.join("\n");
|
|
546
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
export type JsonObject = Record<string, unknown>;
|
|
2
|
+
export type MechanicConfig = {
|
|
3
|
+
shop_domain: string;
|
|
4
|
+
api_base_url: string;
|
|
5
|
+
app_url?: string;
|
|
6
|
+
tasks_dir: string;
|
|
7
|
+
};
|
|
8
|
+
export type LinkEntry = {
|
|
9
|
+
file: string;
|
|
10
|
+
remote_id: string;
|
|
11
|
+
last_remote_content_hash: string;
|
|
12
|
+
};
|
|
13
|
+
export type LinksFile = {
|
|
14
|
+
tasks: Record<string, LinkEntry>;
|
|
15
|
+
};
|
|
16
|
+
export type Project = {
|
|
17
|
+
cwd: string;
|
|
18
|
+
configPath: string;
|
|
19
|
+
linksPath: string;
|
|
20
|
+
shopDomain: string;
|
|
21
|
+
apiBaseUrl: string;
|
|
22
|
+
appUrl: string;
|
|
23
|
+
tasksDir: string;
|
|
24
|
+
tasksDirName: string;
|
|
25
|
+
links: LinksFile;
|
|
26
|
+
};
|
|
27
|
+
export type TaskEnvelope = {
|
|
28
|
+
id: string;
|
|
29
|
+
updated_at?: string;
|
|
30
|
+
content_hash: string;
|
|
31
|
+
task: JsonObject;
|
|
32
|
+
};
|
|
33
|
+
export type TaskListResponse = {
|
|
34
|
+
tasks: TaskEnvelope[];
|
|
35
|
+
};
|
|
36
|
+
export type TaskPreviewResponse = {
|
|
37
|
+
status: "passed" | "failed" | "invalid";
|
|
38
|
+
message?: string;
|
|
39
|
+
errors: Record<string, unknown>;
|
|
40
|
+
task: {
|
|
41
|
+
id?: string | null;
|
|
42
|
+
name?: string | null;
|
|
43
|
+
event_topics: string[];
|
|
44
|
+
shopify_api_version?: string | null;
|
|
45
|
+
shopify_access_scopes_required: string[];
|
|
46
|
+
};
|
|
47
|
+
source: {
|
|
48
|
+
kind: "local_draft" | "local_draft_for_existing_task" | "remote_current";
|
|
49
|
+
task_id?: string | null;
|
|
50
|
+
persisted: boolean;
|
|
51
|
+
remote_enabled?: boolean | null;
|
|
52
|
+
};
|
|
53
|
+
summary: {
|
|
54
|
+
events: number;
|
|
55
|
+
task_runs: number;
|
|
56
|
+
action_runs: number;
|
|
57
|
+
failed_task_runs: number;
|
|
58
|
+
failed_action_runs: number;
|
|
59
|
+
shopify_admin_api_requested: boolean;
|
|
60
|
+
};
|
|
61
|
+
permissions: {
|
|
62
|
+
required_by_preview: string[];
|
|
63
|
+
granted: {
|
|
64
|
+
app: string[];
|
|
65
|
+
task_runtime: string[];
|
|
66
|
+
};
|
|
67
|
+
missing: {
|
|
68
|
+
app: string[];
|
|
69
|
+
task_runtime: string[];
|
|
70
|
+
};
|
|
71
|
+
approval: {
|
|
72
|
+
required: boolean;
|
|
73
|
+
can_approve_from_api: boolean;
|
|
74
|
+
action: string;
|
|
75
|
+
app_url: string;
|
|
76
|
+
};
|
|
77
|
+
warnings: string[];
|
|
78
|
+
};
|
|
79
|
+
events: Array<{
|
|
80
|
+
topic: string;
|
|
81
|
+
shopify_topic?: string | null;
|
|
82
|
+
source?: string | null;
|
|
83
|
+
source_name?: string | null;
|
|
84
|
+
liquid_variable_names?: string[];
|
|
85
|
+
task_runs: Array<{
|
|
86
|
+
ok: boolean | null;
|
|
87
|
+
error?: string | null;
|
|
88
|
+
result?: string | null;
|
|
89
|
+
result_meta?: Record<string, unknown> | null;
|
|
90
|
+
action_runs: Array<{
|
|
91
|
+
action_type?: string | null;
|
|
92
|
+
ok: boolean | null;
|
|
93
|
+
error?: string | null;
|
|
94
|
+
result?: unknown;
|
|
95
|
+
result_meta?: Record<string, unknown> | null;
|
|
96
|
+
}>;
|
|
97
|
+
}>;
|
|
98
|
+
}>;
|
|
99
|
+
};
|
|
100
|
+
export type ShopStatusResponse = {
|
|
101
|
+
shop: {
|
|
102
|
+
shopify_domain: string;
|
|
103
|
+
};
|
|
104
|
+
queue: {
|
|
105
|
+
running: number | null;
|
|
106
|
+
limit: number | null;
|
|
107
|
+
available: number | null;
|
|
108
|
+
waiting: number | null;
|
|
109
|
+
oldest_waiting_ms: number | null;
|
|
110
|
+
partial: boolean;
|
|
111
|
+
};
|
|
112
|
+
running: {
|
|
113
|
+
event_runs: number | null;
|
|
114
|
+
task_runs: number | null;
|
|
115
|
+
action_runs: number | null;
|
|
116
|
+
};
|
|
117
|
+
backlog: {
|
|
118
|
+
event_runs: number | null;
|
|
119
|
+
task_runs: number | null;
|
|
120
|
+
action_runs: number | null;
|
|
121
|
+
by_event_topic: {
|
|
122
|
+
event_topic: string | null;
|
|
123
|
+
count: number;
|
|
124
|
+
}[];
|
|
125
|
+
by_task: {
|
|
126
|
+
task_id: string;
|
|
127
|
+
task_name?: string | null;
|
|
128
|
+
count: number;
|
|
129
|
+
}[];
|
|
130
|
+
by_action: {
|
|
131
|
+
action_type: string | null;
|
|
132
|
+
task_id: string;
|
|
133
|
+
task_name?: string | null;
|
|
134
|
+
count: number;
|
|
135
|
+
}[];
|
|
136
|
+
};
|
|
137
|
+
lag: {
|
|
138
|
+
event_run_ms: number | null;
|
|
139
|
+
task_run_ms: number | null;
|
|
140
|
+
action_run_ms: number | null;
|
|
141
|
+
};
|
|
142
|
+
checked_at: string;
|
|
143
|
+
};
|
|
144
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEjD,MAAM,MAAM,cAAc,GAAG;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,wBAAwB,EAAE,MAAM,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,SAAS,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,UAAU,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,IAAI,EAAE;QACJ,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,YAAY,EAAE,MAAM,EAAE,CAAC;QACvB,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACpC,8BAA8B,EAAE,MAAM,EAAE,CAAC;KAC1C,CAAC;IACF,MAAM,EAAE;QACN,IAAI,EAAE,aAAa,GAAG,+BAA+B,GAAG,gBAAgB,CAAC;QACzE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,SAAS,EAAE,OAAO,CAAC;QACnB,cAAc,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;KACjC,CAAC;IACF,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,gBAAgB,EAAE,MAAM,CAAC;QACzB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,2BAA2B,EAAE,OAAO,CAAC;KACtC,CAAC;IACF,WAAW,EAAE;QACX,mBAAmB,EAAE,MAAM,EAAE,CAAC;QAC9B,OAAO,EAAE;YACP,GAAG,EAAE,MAAM,EAAE,CAAC;YACd,YAAY,EAAE,MAAM,EAAE,CAAC;SACxB,CAAC;QACF,OAAO,EAAE;YACP,GAAG,EAAE,MAAM,EAAE,CAAC;YACd,YAAY,EAAE,MAAM,EAAE,CAAC;SACxB,CAAC;QACF,QAAQ,EAAE;YACR,QAAQ,EAAE,OAAO,CAAC;YAClB,oBAAoB,EAAE,OAAO,CAAC;YAC9B,MAAM,EAAE,MAAM,CAAC;YACf,OAAO,EAAE,MAAM,CAAC;SACjB,CAAC;QACF,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IACF,MAAM,EAAE,KAAK,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;QACjC,SAAS,EAAE,KAAK,CAAC;YACf,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;YACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;YACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;YACvB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;YAC7C,WAAW,EAAE,KAAK,CAAC;gBACjB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;gBAC5B,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;gBACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;gBACtB,MAAM,CAAC,EAAE,OAAO,CAAC;gBACjB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;aAC9C,CAAC,CAAC;SACJ,CAAC,CAAC;KACJ,CAAC,CAAC;CACJ,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE;QACJ,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,KAAK,EAAE;QACL,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;QACjC,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,OAAO,EAAE;QACP,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5B,CAAC;IACF,OAAO,EAAE;QACP,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,cAAc,EAAE;YAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QAChE,OAAO,EAAE;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QACzE,SAAS,EAAE;YAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;YAAC,OAAO,EAAE,MAAM,CAAC;YAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;KACxG,CAAC;IACF,GAAG,EAAE;QACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;KAC9B,CAAC;IACF,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|