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