@50arms/plugin-sdk 0.2.58 → 0.2.59
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/card-kit.d.ts +109 -66
- package/dist/cli.js +183 -44
- package/dist/publish.js +168 -41
- package/dist/vite.js +186 -58
- package/dist/widgets.js +5 -1
- package/package.json +2 -2
package/dist/publish.js
CHANGED
|
@@ -5795,7 +5795,14 @@ var mtimeFilter = (opt) => {
|
|
|
5795
5795
|
var execFileAsync = promisify(execFile);
|
|
5796
5796
|
var EXCLUDED_SEGMENTS = /* @__PURE__ */ new Set(["node_modules", ".git"]);
|
|
5797
5797
|
var EXCLUDED_TOP_LEVEL = /* @__PURE__ */ new Set(["dist"]);
|
|
5798
|
-
var LOCKFILE_NAMES = [
|
|
5798
|
+
var LOCKFILE_NAMES = [
|
|
5799
|
+
"package-lock.json",
|
|
5800
|
+
"npm-shrinkwrap.json",
|
|
5801
|
+
"pnpm-lock.yaml",
|
|
5802
|
+
"yarn.lock",
|
|
5803
|
+
"bun.lock",
|
|
5804
|
+
"bun.lockb"
|
|
5805
|
+
];
|
|
5799
5806
|
function isEnvFile(relativePath) {
|
|
5800
5807
|
return (relativePath.split("/").pop() ?? "").startsWith(".env");
|
|
5801
5808
|
}
|
|
@@ -5807,7 +5814,9 @@ var REGEX_SPECIALS = /[.+^${}()|[\]\\]/g;
|
|
|
5807
5814
|
var GLOBSTAR = String.fromCharCode(1);
|
|
5808
5815
|
function ignoreRule(line) {
|
|
5809
5816
|
if (line.startsWith("!")) {
|
|
5810
|
-
throw new Error(
|
|
5817
|
+
throw new Error(
|
|
5818
|
+
`danx-plugin: the .gitignore line "${line}" negates a pattern, which is not supported outside a git repository; put the project in a git repository or remove the negation`
|
|
5819
|
+
);
|
|
5811
5820
|
}
|
|
5812
5821
|
const body = line.replace(/^\//, "").replace(/\/$/, "");
|
|
5813
5822
|
const anchored = line.startsWith("/") || body.includes("/");
|
|
@@ -5829,9 +5838,12 @@ async function walk(dir) {
|
|
|
5829
5838
|
const ignored = await topLevelIgnoreRules(dir);
|
|
5830
5839
|
const found = [];
|
|
5831
5840
|
const visit = async (prefix) => {
|
|
5832
|
-
for (const entry of await readdir(join2(dir, prefix), {
|
|
5841
|
+
for (const entry of await readdir(join2(dir, prefix), {
|
|
5842
|
+
withFileTypes: true
|
|
5843
|
+
})) {
|
|
5833
5844
|
const relative = prefix === "" ? entry.name : `${prefix}/${entry.name}`;
|
|
5834
|
-
if (excluded(relative) || ignored.some((rule) => rule(relative)))
|
|
5845
|
+
if (excluded(relative) || ignored.some((rule) => rule(relative)))
|
|
5846
|
+
continue;
|
|
5835
5847
|
if (entry.isDirectory()) await visit(relative);
|
|
5836
5848
|
else found.push(relative);
|
|
5837
5849
|
}
|
|
@@ -5845,33 +5857,60 @@ function gitFailure(err) {
|
|
|
5845
5857
|
}
|
|
5846
5858
|
async function gitFiles(dir) {
|
|
5847
5859
|
try {
|
|
5848
|
-
await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
5860
|
+
await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
5861
|
+
cwd: dir,
|
|
5862
|
+
windowsHide: true
|
|
5863
|
+
});
|
|
5849
5864
|
} catch (err) {
|
|
5850
|
-
if (err.code === 128 && /not a git repository/i.test(gitFailure(err)))
|
|
5851
|
-
|
|
5865
|
+
if (err.code === 128 && /not a git repository/i.test(gitFailure(err)))
|
|
5866
|
+
return null;
|
|
5867
|
+
throw new Error(
|
|
5868
|
+
`danx-plugin: git could not tell whether ${dir} is a work tree: ${gitFailure(err)}`
|
|
5869
|
+
);
|
|
5852
5870
|
}
|
|
5853
5871
|
let stdout;
|
|
5854
5872
|
try {
|
|
5855
|
-
({ stdout } = await execFileAsync(
|
|
5873
|
+
({ stdout } = await execFileAsync(
|
|
5874
|
+
"git",
|
|
5875
|
+
["ls-files", "-z", "--cached", "--others", "--exclude-standard"],
|
|
5876
|
+
{ cwd: dir, windowsHide: true, maxBuffer: 64 * 1024 * 1024 }
|
|
5877
|
+
));
|
|
5856
5878
|
} catch (err) {
|
|
5857
|
-
throw new Error(
|
|
5879
|
+
throw new Error(
|
|
5880
|
+
`danx-plugin: git ls-files failed in ${dir}: ${gitFailure(err)}`
|
|
5881
|
+
);
|
|
5858
5882
|
}
|
|
5859
5883
|
const listed = stdout.split("\0").filter((path8) => path8 !== "");
|
|
5860
|
-
const present = await Promise.all(
|
|
5884
|
+
const present = await Promise.all(
|
|
5885
|
+
listed.map(
|
|
5886
|
+
(path8) => lstat(join2(dir, path8)).then(
|
|
5887
|
+
() => true,
|
|
5888
|
+
() => false
|
|
5889
|
+
)
|
|
5890
|
+
)
|
|
5891
|
+
);
|
|
5861
5892
|
return listed.filter((_, i) => present[i]);
|
|
5862
5893
|
}
|
|
5863
5894
|
async function sourceFiles(projectDir) {
|
|
5864
5895
|
const dir = resolve(projectDir);
|
|
5865
|
-
const files = (await gitFiles(dir) ?? await walk(dir)).filter(
|
|
5896
|
+
const files = (await gitFiles(dir) ?? await walk(dir)).filter(
|
|
5897
|
+
(path8) => !excluded(path8)
|
|
5898
|
+
);
|
|
5866
5899
|
if (!files.some((path8) => LOCKFILE_NAMES.includes(path8))) {
|
|
5867
|
-
throw new Error(
|
|
5900
|
+
throw new Error(
|
|
5901
|
+
`danx-plugin: ${projectDir} has no lockfile (${LOCKFILE_NAMES.join(", ")}) among its source files; commit or create one so the source download builds as is`
|
|
5902
|
+
);
|
|
5868
5903
|
}
|
|
5869
5904
|
return files.sort();
|
|
5870
5905
|
}
|
|
5871
5906
|
async function archiveSource(projectDir) {
|
|
5872
5907
|
const dir = resolve(projectDir);
|
|
5873
5908
|
const chunks = [];
|
|
5874
|
-
for await (const chunk of create(
|
|
5909
|
+
for await (const chunk of create(
|
|
5910
|
+
{ cwd: dir, gzip: true, portable: true, mtime: /* @__PURE__ */ new Date(0) },
|
|
5911
|
+
await sourceFiles(dir)
|
|
5912
|
+
))
|
|
5913
|
+
chunks.push(chunk);
|
|
5875
5914
|
return Buffer.concat(chunks);
|
|
5876
5915
|
}
|
|
5877
5916
|
|
|
@@ -5894,11 +5933,18 @@ var PLUGIN_RUNTIME_SPECIFIERS = [
|
|
|
5894
5933
|
{ specifier: "react/jsx-runtime", library: "react" },
|
|
5895
5934
|
{ specifier: "react-dom", library: "react-dom" },
|
|
5896
5935
|
{ specifier: "@50arms/ui", library: "@50arms/ui" },
|
|
5897
|
-
{
|
|
5936
|
+
{
|
|
5937
|
+
specifier: `${CARD_KIT_LIBRARY}@${CARD_KIT_MAJOR}`,
|
|
5938
|
+
library: CARD_KIT_LIBRARY
|
|
5939
|
+
}
|
|
5940
|
+
];
|
|
5941
|
+
var PLUGIN_RUNTIME_LEGACY_ALIASES = [
|
|
5942
|
+
{ specifier: "@danxbot/ui", library: "@50arms/ui", major: 33 }
|
|
5898
5943
|
];
|
|
5899
|
-
var PLUGIN_RUNTIME_LEGACY_ALIASES = [{ specifier: "@danxbot/ui", library: "@50arms/ui", major: 33 }];
|
|
5900
5944
|
var PLUGIN_NEVER_BUNDLED_PACKAGES = [
|
|
5901
|
-
...PLUGIN_RUNTIME_LIBRARIES.map((library) => library.name).filter(
|
|
5945
|
+
...PLUGIN_RUNTIME_LIBRARIES.map((library) => library.name).filter(
|
|
5946
|
+
(name2) => name2 !== CARD_KIT_LIBRARY
|
|
5947
|
+
),
|
|
5902
5948
|
// A source still importing the old name, built with the current SDK, would bundle a second copy of the design system; the build refuses it.
|
|
5903
5949
|
...PLUGIN_RUNTIME_LEGACY_ALIASES.map((alias) => alias.specifier),
|
|
5904
5950
|
"scheduler",
|
|
@@ -5914,17 +5960,29 @@ var BUILD_OUTPUT_TAIL_CHARS = 4e3;
|
|
|
5914
5960
|
function runProjectBuild(projectDir) {
|
|
5915
5961
|
return new Promise((resolvePromise, reject) => {
|
|
5916
5962
|
let output = "";
|
|
5917
|
-
const child = spawn("npm", ["run", "build"], {
|
|
5963
|
+
const child = spawn("npm", ["run", "build"], {
|
|
5964
|
+
cwd: projectDir,
|
|
5965
|
+
windowsHide: true,
|
|
5966
|
+
shell: process.platform === "win32",
|
|
5967
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
5968
|
+
});
|
|
5918
5969
|
const keep = (chunk) => {
|
|
5919
|
-
output = (output + chunk.toString("utf8")).slice(
|
|
5970
|
+
output = (output + chunk.toString("utf8")).slice(
|
|
5971
|
+
-BUILD_OUTPUT_TAIL_CHARS
|
|
5972
|
+
);
|
|
5920
5973
|
};
|
|
5921
5974
|
child.stdout.on("data", keep);
|
|
5922
5975
|
child.stderr.on("data", keep);
|
|
5923
5976
|
child.on("error", reject);
|
|
5924
5977
|
child.on("close", (code2, signal) => {
|
|
5925
5978
|
if (code2 === 0) resolvePromise();
|
|
5926
|
-
else
|
|
5927
|
-
|
|
5979
|
+
else
|
|
5980
|
+
reject(
|
|
5981
|
+
new Error(
|
|
5982
|
+
`danx-plugin: \`npm run build\` failed in ${projectDir} (${signal === null ? `exit ${code2}` : `killed by ${signal}`}):
|
|
5983
|
+
${output.trim()}`
|
|
5984
|
+
)
|
|
5985
|
+
);
|
|
5928
5986
|
});
|
|
5929
5987
|
});
|
|
5930
5988
|
}
|
|
@@ -5936,12 +5994,24 @@ async function readBuiltPlugin(projectDir) {
|
|
|
5936
5994
|
const distDir = join3(resolve2(projectDir), PLUGIN_DIST_DIR);
|
|
5937
5995
|
let manifest;
|
|
5938
5996
|
try {
|
|
5939
|
-
manifest = JSON.parse(
|
|
5997
|
+
manifest = JSON.parse(
|
|
5998
|
+
await readFile2(join3(distDir, PLUGIN_MANIFEST_FILE), "utf8")
|
|
5999
|
+
);
|
|
5940
6000
|
} catch (err) {
|
|
5941
|
-
throw new Error(
|
|
6001
|
+
throw new Error(
|
|
6002
|
+
`danx-plugin: the build left no readable ${PLUGIN_DIST_DIR}/${PLUGIN_MANIFEST_FILE} in ${projectDir} (is the danxPlugin() preset in vite.config?): ${err.message}`
|
|
6003
|
+
);
|
|
5942
6004
|
}
|
|
5943
|
-
if (!isManifest(manifest))
|
|
5944
|
-
|
|
6005
|
+
if (!isManifest(manifest))
|
|
6006
|
+
throw new Error(
|
|
6007
|
+
`danx-plugin: ${PLUGIN_DIST_DIR}/${PLUGIN_MANIFEST_FILE} in ${projectDir} has no entry, no exports list, no widgets list or no files list of paths`
|
|
6008
|
+
);
|
|
6009
|
+
const files = await Promise.all(
|
|
6010
|
+
manifest.files.map(async (file) => ({
|
|
6011
|
+
path: file.path,
|
|
6012
|
+
bytes: await readFile2(join3(distDir, file.path))
|
|
6013
|
+
}))
|
|
6014
|
+
);
|
|
5945
6015
|
return { manifest, files };
|
|
5946
6016
|
}
|
|
5947
6017
|
async function buildPlugin(projectDir) {
|
|
@@ -5954,11 +6024,21 @@ import { createHash } from "node:crypto";
|
|
|
5954
6024
|
var PLUGIN_SCREENSHOT_FILE = "screenshot.png";
|
|
5955
6025
|
function withScreenshot(built, png) {
|
|
5956
6026
|
if (built.files.some((file) => file.path === PLUGIN_SCREENSHOT_FILE)) {
|
|
5957
|
-
throw new Error(
|
|
6027
|
+
throw new Error(
|
|
6028
|
+
`danx-plugin: the build already produced ${PLUGIN_SCREENSHOT_FILE}; rename it so the publish screenshot does not replace it`
|
|
6029
|
+
);
|
|
5958
6030
|
}
|
|
5959
|
-
const entry = {
|
|
6031
|
+
const entry = {
|
|
6032
|
+
path: PLUGIN_SCREENSHOT_FILE,
|
|
6033
|
+
size: png.length,
|
|
6034
|
+
sha256: createHash("sha256").update(png).digest("hex")
|
|
6035
|
+
};
|
|
5960
6036
|
return {
|
|
5961
|
-
manifest: {
|
|
6037
|
+
manifest: {
|
|
6038
|
+
...built.manifest,
|
|
6039
|
+
screenshot: PLUGIN_SCREENSHOT_FILE,
|
|
6040
|
+
files: [...built.manifest.files, entry]
|
|
6041
|
+
},
|
|
5962
6042
|
files: [...built.files, { path: PLUGIN_SCREENSHOT_FILE, bytes: png }]
|
|
5963
6043
|
};
|
|
5964
6044
|
}
|
|
@@ -5970,20 +6050,36 @@ function fetchTransport(config, fetchImpl = fetch) {
|
|
|
5970
6050
|
async request({ method, path: path8, query, body }) {
|
|
5971
6051
|
const search = query === void 0 ? "" : `?${new URLSearchParams(Object.entries(query).map(([k, v]) => [k, String(v)]))}`;
|
|
5972
6052
|
const url = `${base}${path8}${search}`;
|
|
5973
|
-
const headers = {
|
|
6053
|
+
const headers = {
|
|
6054
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
6055
|
+
Accept: "application/json"
|
|
6056
|
+
};
|
|
5974
6057
|
if (body !== void 0) headers["Content-Type"] = "application/json";
|
|
5975
|
-
const res = await fetchImpl(url, {
|
|
6058
|
+
const res = await fetchImpl(url, {
|
|
6059
|
+
method,
|
|
6060
|
+
headers,
|
|
6061
|
+
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
6062
|
+
});
|
|
5976
6063
|
const text = await res.text();
|
|
5977
|
-
if (res.status >= 500)
|
|
6064
|
+
if (res.status >= 500)
|
|
6065
|
+
throw new Error(
|
|
6066
|
+
`danx-plugin: server error ${res.status} on ${method} ${url}: ${text.slice(0, 500)}`
|
|
6067
|
+
);
|
|
5978
6068
|
let parsed = null;
|
|
5979
6069
|
if (text !== "") {
|
|
5980
6070
|
try {
|
|
5981
6071
|
parsed = JSON.parse(text);
|
|
5982
6072
|
} catch {
|
|
5983
|
-
throw new Error(
|
|
6073
|
+
throw new Error(
|
|
6074
|
+
`danx-plugin: non-JSON answer (status ${res.status}) from ${method} ${url}: ${text.slice(0, 200)}`
|
|
6075
|
+
);
|
|
5984
6076
|
}
|
|
5985
6077
|
}
|
|
5986
|
-
return {
|
|
6078
|
+
return {
|
|
6079
|
+
ok: res.status >= 200 && res.status < 300,
|
|
6080
|
+
status: res.status,
|
|
6081
|
+
body: parsed
|
|
6082
|
+
};
|
|
5987
6083
|
}
|
|
5988
6084
|
};
|
|
5989
6085
|
}
|
|
@@ -5993,7 +6089,10 @@ var PLUGINS_SETTINGS_PATH = "/settings/team/plugins";
|
|
|
5993
6089
|
var LIST_PAGE = 1e3;
|
|
5994
6090
|
function field(body, name2, type, where) {
|
|
5995
6091
|
const value = body?.[name2];
|
|
5996
|
-
if (typeof value !== type)
|
|
6092
|
+
if (typeof value !== type)
|
|
6093
|
+
throw new Error(
|
|
6094
|
+
`danx-plugin: ${where} answered without a ${type} "${name2}"`
|
|
6095
|
+
);
|
|
5997
6096
|
return value;
|
|
5998
6097
|
}
|
|
5999
6098
|
function refused(step, result) {
|
|
@@ -6001,17 +6100,28 @@ function refused(step, result) {
|
|
|
6001
6100
|
}
|
|
6002
6101
|
async function findPlugin(transport, key) {
|
|
6003
6102
|
for (let offset = 0; ; offset += LIST_PAGE) {
|
|
6004
|
-
const page = await transport.request({
|
|
6103
|
+
const page = await transport.request({
|
|
6104
|
+
method: "GET",
|
|
6105
|
+
path: "/api/plugins",
|
|
6106
|
+
query: { q: key, limit: LIST_PAGE, offset }
|
|
6107
|
+
});
|
|
6005
6108
|
if (!page.ok) return { kind: "refused", result: page };
|
|
6006
6109
|
const { plugins, total } = page.body;
|
|
6007
|
-
if (!Array.isArray(plugins) || typeof total !== "number")
|
|
6110
|
+
if (!Array.isArray(plugins) || typeof total !== "number")
|
|
6111
|
+
throw new Error(
|
|
6112
|
+
'danx-plugin: GET /api/plugins answered without "plugins" and "total"'
|
|
6113
|
+
);
|
|
6008
6114
|
const match = plugins.find((plugin) => plugin.key === key);
|
|
6009
6115
|
if (match !== void 0) return { kind: "found", id: match.id };
|
|
6010
|
-
if (offset + plugins.length >= total || plugins.length === 0)
|
|
6116
|
+
if (offset + plugins.length >= total || plugins.length === 0)
|
|
6117
|
+
return { kind: "absent" };
|
|
6011
6118
|
}
|
|
6012
6119
|
}
|
|
6013
6120
|
function assertNote(note) {
|
|
6014
|
-
if (note.trim() === "")
|
|
6121
|
+
if (note.trim() === "")
|
|
6122
|
+
throw new Error(
|
|
6123
|
+
"danx-plugin: `note` is required: say what this revision changes"
|
|
6124
|
+
);
|
|
6015
6125
|
}
|
|
6016
6126
|
async function uploadRevision(transport, input) {
|
|
6017
6127
|
assertNote(input.note);
|
|
@@ -6021,7 +6131,11 @@ async function uploadRevision(transport, input) {
|
|
|
6021
6131
|
if (found.kind === "found") {
|
|
6022
6132
|
pluginId = found.id;
|
|
6023
6133
|
} else {
|
|
6024
|
-
const created = await transport.request({
|
|
6134
|
+
const created = await transport.request({
|
|
6135
|
+
method: "POST",
|
|
6136
|
+
path: "/api/plugins",
|
|
6137
|
+
body: { key: input.plugin, name: input.name ?? input.plugin }
|
|
6138
|
+
});
|
|
6025
6139
|
if (!created.ok) return refused("create", created);
|
|
6026
6140
|
pluginId = field(created.body, "id", "number", "POST /api/plugins");
|
|
6027
6141
|
}
|
|
@@ -6032,7 +6146,10 @@ async function uploadRevision(transport, input) {
|
|
|
6032
6146
|
body: {
|
|
6033
6147
|
note: input.note,
|
|
6034
6148
|
manifest: input.built.manifest,
|
|
6035
|
-
files: input.built.files.map((file) => ({
|
|
6149
|
+
files: input.built.files.map((file) => ({
|
|
6150
|
+
path: file.path,
|
|
6151
|
+
content_base64: file.bytes.toString("base64")
|
|
6152
|
+
})),
|
|
6036
6153
|
source_archive_base64: input.source.toString("base64")
|
|
6037
6154
|
}
|
|
6038
6155
|
});
|
|
@@ -6043,8 +6160,18 @@ async function uploadRevision(transport, input) {
|
|
|
6043
6160
|
body: {
|
|
6044
6161
|
plugin: input.plugin,
|
|
6045
6162
|
plugin_id: pluginId,
|
|
6046
|
-
revision_id: field(
|
|
6047
|
-
|
|
6163
|
+
revision_id: field(
|
|
6164
|
+
uploaded.body,
|
|
6165
|
+
"id",
|
|
6166
|
+
"string",
|
|
6167
|
+
`POST ${route}`
|
|
6168
|
+
),
|
|
6169
|
+
revision_no: field(
|
|
6170
|
+
uploaded.body,
|
|
6171
|
+
"revision_no",
|
|
6172
|
+
"number",
|
|
6173
|
+
`POST ${route}`
|
|
6174
|
+
),
|
|
6048
6175
|
approval_url: `${input.dashboardUrl.replace(/\/+$/, "")}${PLUGINS_SETTINGS_PATH}`
|
|
6049
6176
|
}
|
|
6050
6177
|
};
|