amulets-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/README.md +61 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +46 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/login.d.ts +3 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +78 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +3 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +19 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/pull.d.ts +3 -0
- package/dist/commands/pull.d.ts.map +1 -0
- package/dist/commands/pull.js +92 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/push.d.ts +3 -0
- package/dist/commands/push.d.ts.map +1 -0
- package/dist/commands/push.js +179 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/commands/update.d.ts +3 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +21 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/versions.d.ts +3 -0
- package/dist/commands/versions.d.ts.map +1 -0
- package/dist/commands/versions.js +61 -0
- package/dist/commands/versions.js.map +1 -0
- package/dist/commands/whoami.d.ts +3 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +29 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api.d.ts +65 -0
- package/dist/lib/api.d.ts.map +1 -0
- package/dist/lib/api.js +68 -0
- package/dist/lib/api.js.map +1 -0
- package/dist/lib/auth.d.ts +15 -0
- package/dist/lib/auth.d.ts.map +1 -0
- package/dist/lib/auth.js +69 -0
- package/dist/lib/auth.js.map +1 -0
- package/dist/lib/config.d.ts +16 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +89 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/update-check.d.ts +5 -0
- package/dist/lib/update-check.d.ts.map +1 -0
- package/dist/lib/update-check.js +74 -0
- package/dist/lib/update-check.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.registerVersions = registerVersions;
|
|
7
|
+
const ora_1 = __importDefault(require("ora"));
|
|
8
|
+
const api_js_1 = require("../lib/api.js");
|
|
9
|
+
const config_js_1 = require("../lib/config.js");
|
|
10
|
+
function registerVersions(program) {
|
|
11
|
+
program
|
|
12
|
+
.command('versions <owner/name>')
|
|
13
|
+
.description('List all versions of an asset')
|
|
14
|
+
.action(async (ownerName) => {
|
|
15
|
+
const token = await (0, config_js_1.requireToken)();
|
|
16
|
+
let owner;
|
|
17
|
+
let name;
|
|
18
|
+
if (ownerName.includes('/')) {
|
|
19
|
+
const parts = ownerName.split('/');
|
|
20
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
21
|
+
console.error('Error: argument must be in <owner/name> or <name> format');
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
owner = parts[0];
|
|
25
|
+
name = parts[1];
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
const me = await (0, api_js_1.getMe)(token);
|
|
29
|
+
if (!me.username) {
|
|
30
|
+
console.error('Error: could not resolve your username — use <owner/name> format');
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
owner = me.username;
|
|
34
|
+
name = ownerName;
|
|
35
|
+
}
|
|
36
|
+
const spinner = (0, ora_1.default)(`Fetching versions for ${owner}/${name}...`).start();
|
|
37
|
+
try {
|
|
38
|
+
const { versions } = await (0, api_js_1.getAssetVersions)(owner, name, token);
|
|
39
|
+
spinner.stop();
|
|
40
|
+
if (versions.length === 0) {
|
|
41
|
+
console.log('No versions found.');
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const versionWidth = Math.max(7, ...versions.map((v) => v.version.length));
|
|
45
|
+
const header = `${'VERSION'.padEnd(versionWidth)} ${'DATE'.padEnd(20)} MESSAGE`;
|
|
46
|
+
console.log(header);
|
|
47
|
+
console.log('─'.repeat(header.length));
|
|
48
|
+
for (const v of versions) {
|
|
49
|
+
const date = new Date(v.created_at).toISOString().slice(0, 10);
|
|
50
|
+
const msg = v.message ?? '—';
|
|
51
|
+
console.log(`${v.version.padEnd(versionWidth)} ${date.padEnd(20)} ${msg}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
const message = err instanceof api_js_1.ApiError ? err.message : String(err);
|
|
56
|
+
spinner.fail(`Failed to list versions: ${message}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=versions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"versions.js","sourceRoot":"","sources":["../../src/commands/versions.ts"],"names":[],"mappings":";;;;;AAKA,4CAuDC;AA3DD,8CAAqB;AACrB,0CAAiE;AACjE,gDAA+C;AAE/C,SAAgB,gBAAgB,CAAC,OAAgB;IAC/C,OAAO;SACJ,OAAO,CAAC,uBAAuB,CAAC;SAChC,WAAW,CAAC,+BAA+B,CAAC;SAC5C,MAAM,CAAC,KAAK,EAAE,SAAiB,EAAE,EAAE;QAClC,MAAM,KAAK,GAAG,MAAM,IAAA,wBAAY,GAAE,CAAA;QAElC,IAAI,KAAa,CAAA;QACjB,IAAI,IAAY,CAAA;QAEhB,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;YAClC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjD,OAAO,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAA;gBACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YACD,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;YAChB,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;aAAM,CAAC;YACN,MAAM,EAAE,GAAG,MAAM,IAAA,cAAK,EAAC,KAAK,CAAC,CAAA;YAC7B,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC;gBACjB,OAAO,CAAC,KAAK,CAAC,kEAAkE,CAAC,CAAA;gBACjF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YACD,KAAK,GAAG,EAAE,CAAC,QAAQ,CAAA;YACnB,IAAI,GAAG,SAAS,CAAA;QAClB,CAAC;QAED,MAAM,OAAO,GAAG,IAAA,aAAG,EAAC,yBAAyB,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,KAAK,EAAE,CAAA;QAExE,IAAI,CAAC;YACH,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,IAAA,yBAAgB,EAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;YAC/D,OAAO,CAAC,IAAI,EAAE,CAAA;YAEd,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC1B,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAA;gBACjC,OAAM;YACR,CAAC;YAED,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;YAC1E,MAAM,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,CAAA;YACjF,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YACnB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAA;YAEtC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;gBACzB,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;gBAC9D,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,IAAI,GAAG,CAAA;gBAC5B,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,CAAA;YAC9E,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,iBAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACnE,OAAO,CAAC,IAAI,CAAC,4BAA4B,OAAO,EAAE,CAAC,CAAA;YACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;IACH,CAAC,CAAC,CAAA;AACN,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whoami.d.ts","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGxC,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAyBrD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerWhoami = registerWhoami;
|
|
4
|
+
const config_js_1 = require("../lib/config.js");
|
|
5
|
+
function registerWhoami(program) {
|
|
6
|
+
program
|
|
7
|
+
.command('whoami')
|
|
8
|
+
.description('Show the currently authenticated user')
|
|
9
|
+
.action(async () => {
|
|
10
|
+
const token = await (0, config_js_1.requireToken)();
|
|
11
|
+
const apiUrl = (0, config_js_1.getApiUrl)();
|
|
12
|
+
try {
|
|
13
|
+
const res = await fetch(`${apiUrl}/api/auth/me`, {
|
|
14
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
15
|
+
});
|
|
16
|
+
if (!res.ok) {
|
|
17
|
+
console.error('Not authenticated. Run `amulets login` first.');
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
const user = (await res.json());
|
|
21
|
+
console.log(`Logged in as: ${user.username ?? user.id ?? 'unknown'}`);
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=whoami.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":";;AAGA,wCAyBC;AA3BD,gDAA0D;AAE1D,SAAgB,cAAc,CAAC,OAAgB;IAC7C,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,uCAAuC,CAAC;SACpD,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,KAAK,GAAG,MAAM,IAAA,wBAAY,GAAE,CAAA;QAClC,MAAM,MAAM,GAAG,IAAA,qBAAS,GAAE,CAAA;QAE1B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,cAAc,EAAE;gBAC/C,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;aAC9C,CAAC,CAAA;YAEF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAA;gBAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAuC,CAAA;YACrE,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,EAAE,IAAI,SAAS,EAAE,CAAC,CAAA;QACvE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;YAC3E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;IACH,CAAC,CAAC,CAAA;AACN,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const package_json_1 = __importDefault(require("../package.json"));
|
|
9
|
+
const list_js_1 = require("./commands/list.js");
|
|
10
|
+
const login_js_1 = require("./commands/login.js");
|
|
11
|
+
const logout_js_1 = require("./commands/logout.js");
|
|
12
|
+
const pull_js_1 = require("./commands/pull.js");
|
|
13
|
+
const push_js_1 = require("./commands/push.js");
|
|
14
|
+
const update_js_1 = require("./commands/update.js");
|
|
15
|
+
const versions_js_1 = require("./commands/versions.js");
|
|
16
|
+
const whoami_js_1 = require("./commands/whoami.js");
|
|
17
|
+
const update_check_js_1 = require("./lib/update-check.js");
|
|
18
|
+
const { version } = package_json_1.default;
|
|
19
|
+
const program = new commander_1.Command();
|
|
20
|
+
program
|
|
21
|
+
.name('amulets')
|
|
22
|
+
.description('Manage your private AI skills — push, pull, and sync')
|
|
23
|
+
.version(version, '-v, --version', 'output the version number');
|
|
24
|
+
(0, login_js_1.registerLogin)(program);
|
|
25
|
+
(0, logout_js_1.registerLogout)(program);
|
|
26
|
+
(0, whoami_js_1.registerWhoami)(program);
|
|
27
|
+
(0, push_js_1.registerPush)(program);
|
|
28
|
+
(0, pull_js_1.registerPull)(program);
|
|
29
|
+
(0, list_js_1.registerList)(program);
|
|
30
|
+
(0, versions_js_1.registerVersions)(program);
|
|
31
|
+
(0, update_js_1.registerUpdate)(program, version);
|
|
32
|
+
void (async () => {
|
|
33
|
+
const updatePromise = (0, update_check_js_1.startUpdateCheck)(version);
|
|
34
|
+
await program.parseAsync();
|
|
35
|
+
const latest = await Promise.race([
|
|
36
|
+
updatePromise,
|
|
37
|
+
new Promise((resolve) => setTimeout(() => resolve(null), 500)),
|
|
38
|
+
]);
|
|
39
|
+
if (latest && process.argv[2] !== 'update') {
|
|
40
|
+
process.stderr.write((0, update_check_js_1.formatUpdateNotice)(version, latest));
|
|
41
|
+
}
|
|
42
|
+
})();
|
|
43
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AACA,yCAAmC;AACnC,mEAAiC;AACjC,gDAAiD;AACjD,kDAAmD;AACnD,oDAAqD;AACrD,gDAAiD;AACjD,gDAAiD;AACjD,oDAAqD;AACrD,wDAAyD;AACzD,oDAAqD;AACrD,2DAA4E;AAE5E,MAAM,EAAE,OAAO,EAAE,GAAG,sBAAG,CAAA;AAEvB,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAA;AAE7B,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,sDAAsD,CAAC;KACnE,OAAO,CAAC,OAAO,EAAE,eAAe,EAAE,2BAA2B,CAAC,CAAA;AAEjE,IAAA,wBAAa,EAAC,OAAO,CAAC,CAAA;AACtB,IAAA,0BAAc,EAAC,OAAO,CAAC,CAAA;AACvB,IAAA,0BAAc,EAAC,OAAO,CAAC,CAAA;AACvB,IAAA,sBAAY,EAAC,OAAO,CAAC,CAAA;AACrB,IAAA,sBAAY,EAAC,OAAO,CAAC,CAAA;AACrB,IAAA,sBAAY,EAAC,OAAO,CAAC,CAAA;AACrB,IAAA,8BAAgB,EAAC,OAAO,CAAC,CAAA;AACzB,IAAA,0BAAc,EAAC,OAAO,EAAE,OAAO,CAAC,CAAA;AAEhC,KAAK,CAAC,KAAK,IAAI,EAAE;IACf,MAAM,aAAa,GAAG,IAAA,kCAAgB,EAAC,OAAO,CAAC,CAAA;IAE/C,MAAM,OAAO,CAAC,UAAU,EAAE,CAAA;IAE1B,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;QAChC,aAAa;QACb,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;KACrE,CAAC,CAAA;IAEF,IAAI,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC3C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAA,oCAAkB,EAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAA;IAC3D,CAAC;AACH,CAAC,CAAC,EAAE,CAAA"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export interface Asset {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
slug: string;
|
|
5
|
+
description: string | null;
|
|
6
|
+
asset_format: 'file' | 'skill' | 'bundle';
|
|
7
|
+
tags: string[];
|
|
8
|
+
created_at: string;
|
|
9
|
+
updated_at: string;
|
|
10
|
+
}
|
|
11
|
+
export interface AssetVersion {
|
|
12
|
+
id: string;
|
|
13
|
+
asset_id: string;
|
|
14
|
+
version: string;
|
|
15
|
+
message: string | null;
|
|
16
|
+
created_at: string;
|
|
17
|
+
}
|
|
18
|
+
export declare class ApiError extends Error {
|
|
19
|
+
status: number;
|
|
20
|
+
constructor(status: number, message: string);
|
|
21
|
+
}
|
|
22
|
+
export declare function pushSimpleAsset(token: string, payload: {
|
|
23
|
+
name: string;
|
|
24
|
+
slug: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
tags?: string[];
|
|
27
|
+
version: string;
|
|
28
|
+
message?: string;
|
|
29
|
+
content: string;
|
|
30
|
+
}): Promise<{
|
|
31
|
+
asset: Asset;
|
|
32
|
+
version: AssetVersion;
|
|
33
|
+
}>;
|
|
34
|
+
export declare function pushPackageAsset(token: string, formData: FormData): Promise<{
|
|
35
|
+
asset: Asset;
|
|
36
|
+
version: AssetVersion;
|
|
37
|
+
}>;
|
|
38
|
+
export declare function getAssetVersion(owner: string, name: string, version: string, token: string): Promise<{
|
|
39
|
+
version: string;
|
|
40
|
+
content?: string;
|
|
41
|
+
download_url?: string;
|
|
42
|
+
file_manifest?: unknown;
|
|
43
|
+
}>;
|
|
44
|
+
export declare function getAssetVersions(owner: string, name: string, token: string): Promise<{
|
|
45
|
+
versions: Array<{
|
|
46
|
+
id: string;
|
|
47
|
+
version: string;
|
|
48
|
+
message: string | null;
|
|
49
|
+
created_at: string;
|
|
50
|
+
}>;
|
|
51
|
+
}>;
|
|
52
|
+
export declare function getMe(token: string): Promise<{
|
|
53
|
+
username: string | null;
|
|
54
|
+
id: string;
|
|
55
|
+
}>;
|
|
56
|
+
export declare function listMyAssets(token: string): Promise<{
|
|
57
|
+
assets: Array<Asset & {
|
|
58
|
+
asset_versions: Array<{
|
|
59
|
+
id: string;
|
|
60
|
+
version: string;
|
|
61
|
+
created_at: string;
|
|
62
|
+
}>;
|
|
63
|
+
}>;
|
|
64
|
+
}>;
|
|
65
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,YAAY,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;IACzC,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,qBAAa,QAAS,SAAQ,KAAK;IAExB,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM;CAIlB;AA6BD,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;IACP,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;CAChB,GACA,OAAO,CAAC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,YAAY,CAAA;CAAE,CAAC,CAOlD;AAED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,YAAY,CAAA;CAAE,CAAC,CAMlD;AAED,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC;IACT,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB,CAAC,CAED;AAED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC;IACT,QAAQ,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC7F,CAAC,CAED;AAED,wBAAsB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,CAE3F;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACzD,MAAM,EAAE,KAAK,CACX,KAAK,GAAG;QAAE,cAAc,EAAE,KAAK,CAAC;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CACvF,CAAA;CACF,CAAC,CAED"}
|
package/dist/lib/api.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ApiError = void 0;
|
|
4
|
+
exports.pushSimpleAsset = pushSimpleAsset;
|
|
5
|
+
exports.pushPackageAsset = pushPackageAsset;
|
|
6
|
+
exports.getAssetVersion = getAssetVersion;
|
|
7
|
+
exports.getAssetVersions = getAssetVersions;
|
|
8
|
+
exports.getMe = getMe;
|
|
9
|
+
exports.listMyAssets = listMyAssets;
|
|
10
|
+
const config_js_1 = require("./config.js");
|
|
11
|
+
class ApiError extends Error {
|
|
12
|
+
status;
|
|
13
|
+
constructor(status, message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.status = status;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.ApiError = ApiError;
|
|
19
|
+
async function request(path, options = {}) {
|
|
20
|
+
const { token, headers: extraHeaders, ...fetchOptions } = options;
|
|
21
|
+
const apiUrl = (0, config_js_1.getApiUrl)();
|
|
22
|
+
const url = `${apiUrl}${path}`;
|
|
23
|
+
const headers = { ...extraHeaders };
|
|
24
|
+
if (token)
|
|
25
|
+
headers.Authorization = `Bearer ${token}`;
|
|
26
|
+
const res = await fetch(url, { ...fetchOptions, headers });
|
|
27
|
+
if (!res.ok) {
|
|
28
|
+
let message = `HTTP ${res.status}`;
|
|
29
|
+
try {
|
|
30
|
+
const body = (await res.json());
|
|
31
|
+
if (body.error)
|
|
32
|
+
message = body.error;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// ignore parse errors
|
|
36
|
+
}
|
|
37
|
+
throw new ApiError(res.status, message);
|
|
38
|
+
}
|
|
39
|
+
return res.json();
|
|
40
|
+
}
|
|
41
|
+
async function pushSimpleAsset(token, payload) {
|
|
42
|
+
return request('/api/assets', {
|
|
43
|
+
method: 'POST',
|
|
44
|
+
token,
|
|
45
|
+
headers: { 'Content-Type': 'application/json' },
|
|
46
|
+
body: JSON.stringify(payload),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
async function pushPackageAsset(token, formData) {
|
|
50
|
+
return request('/api/assets', {
|
|
51
|
+
method: 'POST',
|
|
52
|
+
token,
|
|
53
|
+
body: formData,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
async function getAssetVersion(owner, name, version, token) {
|
|
57
|
+
return request(`/api/assets/${owner}/${name}/${version}`, { token });
|
|
58
|
+
}
|
|
59
|
+
async function getAssetVersions(owner, name, token) {
|
|
60
|
+
return request(`/api/assets/${owner}/${name}/versions`, { token });
|
|
61
|
+
}
|
|
62
|
+
async function getMe(token) {
|
|
63
|
+
return request('/api/auth/me', { token });
|
|
64
|
+
}
|
|
65
|
+
async function listMyAssets(token) {
|
|
66
|
+
return request('/api/me/assets', { token });
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":";;;AAyDA,0CAkBC;AAED,4CASC;AAED,0CAYC;AAED,4CAQC;AAED,sBAEC;AAED,oCAMC;AA1HD,2CAAuC;AAqBvC,MAAa,QAAS,SAAQ,KAAK;IAExB;IADT,YACS,MAAc,EACrB,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAA;QAHP,WAAM,GAAN,MAAM,CAAQ;IAIvB,CAAC;CACF;AAPD,4BAOC;AAED,KAAK,UAAU,OAAO,CACpB,IAAY,EACZ,UAA8E,EAAE;IAEhF,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,YAAY,EAAE,GAAG,OAAO,CAAA;IACjE,MAAM,MAAM,GAAG,IAAA,qBAAS,GAAE,CAAA;IAC1B,MAAM,GAAG,GAAG,GAAG,MAAM,GAAG,IAAI,EAAE,CAAA;IAE9B,MAAM,OAAO,GAA2B,EAAE,GAAG,YAAY,EAAE,CAAA;IAC3D,IAAI,KAAK;QAAE,OAAO,CAAC,aAAa,GAAG,UAAU,KAAK,EAAE,CAAA;IAEpD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,YAAY,EAAE,OAAO,EAAE,CAAC,CAAA;IAE1D,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,IAAI,OAAO,GAAG,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAA;QAClC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAuB,CAAA;YACrD,IAAI,IAAI,CAAC,KAAK;gBAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAA;QACtC,CAAC;QAAC,MAAM,CAAC;YACP,sBAAsB;QACxB,CAAC;QACD,MAAM,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACzC,CAAC;IAED,OAAO,GAAG,CAAC,IAAI,EAAgB,CAAA;AACjC,CAAC;AAEM,KAAK,UAAU,eAAe,CACnC,KAAa,EACb,OAQC;IAED,OAAO,OAAO,CAAC,aAAa,EAAE;QAC5B,MAAM,EAAE,MAAM;QACd,KAAK;QACL,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;KAC9B,CAAC,CAAA;AACJ,CAAC;AAEM,KAAK,UAAU,gBAAgB,CACpC,KAAa,EACb,QAAkB;IAElB,OAAO,OAAO,CAAC,aAAa,EAAE;QAC5B,MAAM,EAAE,MAAM;QACd,KAAK;QACL,IAAI,EAAE,QAAQ;KACf,CAAC,CAAA;AACJ,CAAC;AAEM,KAAK,UAAU,eAAe,CACnC,KAAa,EACb,IAAY,EACZ,OAAe,EACf,KAAa;IAOb,OAAO,OAAO,CAAC,eAAe,KAAK,IAAI,IAAI,IAAI,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;AACtE,CAAC;AAEM,KAAK,UAAU,gBAAgB,CACpC,KAAa,EACb,IAAY,EACZ,KAAa;IAIb,OAAO,OAAO,CAAC,eAAe,KAAK,IAAI,IAAI,WAAW,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;AACpE,CAAC;AAEM,KAAK,UAAU,KAAK,CAAC,KAAa;IACvC,OAAO,OAAO,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;AAC3C,CAAC;AAEM,KAAK,UAAU,YAAY,CAAC,KAAa;IAK9C,OAAO,OAAO,CAAC,gBAAgB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;AAC7C,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare function findFreePort(): Promise<number>;
|
|
2
|
+
export interface CLIAuthResult {
|
|
3
|
+
token: string;
|
|
4
|
+
refresh_token: string;
|
|
5
|
+
expires_in: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Starts a local HTTP server that waits for the web-app to redirect back
|
|
9
|
+
* with tokens in the query string.
|
|
10
|
+
*/
|
|
11
|
+
export declare function waitForCLIAuthCallback(port: number): {
|
|
12
|
+
promise: Promise<CLIAuthResult>;
|
|
13
|
+
cancel: () => void;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAGA,wBAAgB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAc9C;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG;IACpD,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;IAC/B,MAAM,EAAE,MAAM,IAAI,CAAA;CACnB,CAmDA"}
|
package/dist/lib/auth.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.findFreePort = findFreePort;
|
|
7
|
+
exports.waitForCLIAuthCallback = waitForCLIAuthCallback;
|
|
8
|
+
const node_http_1 = __importDefault(require("node:http"));
|
|
9
|
+
const node_net_1 = __importDefault(require("node:net"));
|
|
10
|
+
function findFreePort() {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
const server = node_net_1.default.createServer();
|
|
13
|
+
server.listen(0, () => {
|
|
14
|
+
const addr = server.address();
|
|
15
|
+
if (!addr || typeof addr === 'string') {
|
|
16
|
+
reject(new Error('Could not find free port'));
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const port = addr.port;
|
|
20
|
+
server.close(() => resolve(port));
|
|
21
|
+
});
|
|
22
|
+
server.on('error', reject);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Starts a local HTTP server that waits for the web-app to redirect back
|
|
27
|
+
* with tokens in the query string.
|
|
28
|
+
*/
|
|
29
|
+
function waitForCLIAuthCallback(port) {
|
|
30
|
+
let serverRef = null;
|
|
31
|
+
const promise = new Promise((resolve, reject) => {
|
|
32
|
+
const server = node_http_1.default.createServer((req, res) => {
|
|
33
|
+
const url = new URL(req.url ?? '/', `http://localhost:${port}`);
|
|
34
|
+
const token = url.searchParams.get('token');
|
|
35
|
+
const refresh_token = url.searchParams.get('refresh_token') ?? '';
|
|
36
|
+
const expires_in = Number(url.searchParams.get('expires_in') ?? '3600');
|
|
37
|
+
const error = url.searchParams.get('error');
|
|
38
|
+
if (error) {
|
|
39
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
40
|
+
res.end('<html><body><h2>Login failed</h2><p>You can close this tab and return to the terminal.</p></body></html>');
|
|
41
|
+
server.close();
|
|
42
|
+
reject(new Error(`Auth error: ${error}`));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (!token) {
|
|
46
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
47
|
+
res.end('<html><body><h2>Login failed</h2><p>No token received. You can close this tab.</p></body></html>');
|
|
48
|
+
server.close();
|
|
49
|
+
reject(new Error('No token received'));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
53
|
+
res.end('<html><body><h2>Login successful!</h2><p>You can close this tab and return to the terminal.</p></body></html>');
|
|
54
|
+
server.close();
|
|
55
|
+
resolve({ token, refresh_token, expires_in });
|
|
56
|
+
});
|
|
57
|
+
serverRef = server;
|
|
58
|
+
server.listen(port, () => { });
|
|
59
|
+
server.unref(); // don't prevent process exit once auth completes
|
|
60
|
+
server.on('error', reject);
|
|
61
|
+
});
|
|
62
|
+
return {
|
|
63
|
+
promise,
|
|
64
|
+
cancel: () => {
|
|
65
|
+
serverRef?.close();
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface Config {
|
|
2
|
+
token: string;
|
|
3
|
+
refresh_token?: string;
|
|
4
|
+
expires_at?: number;
|
|
5
|
+
apiUrl?: string;
|
|
6
|
+
lastUpdateCheck?: number;
|
|
7
|
+
latestVersion?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function getConfigPath(): string;
|
|
10
|
+
export declare function readConfig(): Config | null;
|
|
11
|
+
export declare function writeConfig(config: Config): void;
|
|
12
|
+
export declare function clearConfig(): void;
|
|
13
|
+
export declare function getApiUrl(): string;
|
|
14
|
+
export declare function getValidToken(): Promise<string>;
|
|
15
|
+
export declare function requireToken(): Promise<string>;
|
|
16
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAgB,UAAU,IAAI,MAAM,GAAG,IAAI,CAS1C;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAIhD;AAED,wBAAgB,WAAW,IAAI,IAAI,CAKlC;AAED,wBAAgB,SAAS,IAAI,MAAM,CAGlC;AAGD,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAwCrD;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAOpD"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getConfigPath = getConfigPath;
|
|
7
|
+
exports.readConfig = readConfig;
|
|
8
|
+
exports.writeConfig = writeConfig;
|
|
9
|
+
exports.clearConfig = clearConfig;
|
|
10
|
+
exports.getApiUrl = getApiUrl;
|
|
11
|
+
exports.getValidToken = getValidToken;
|
|
12
|
+
exports.requireToken = requireToken;
|
|
13
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
14
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
15
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
16
|
+
function getConfigPath() {
|
|
17
|
+
return node_path_1.default.join(node_os_1.default.homedir(), '.config', 'amulets', 'config.json');
|
|
18
|
+
}
|
|
19
|
+
function readConfig() {
|
|
20
|
+
const configPath = getConfigPath();
|
|
21
|
+
if (!node_fs_1.default.existsSync(configPath))
|
|
22
|
+
return null;
|
|
23
|
+
try {
|
|
24
|
+
const raw = node_fs_1.default.readFileSync(configPath, 'utf-8');
|
|
25
|
+
return JSON.parse(raw);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function writeConfig(config) {
|
|
32
|
+
const configPath = getConfigPath();
|
|
33
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(configPath), { recursive: true });
|
|
34
|
+
node_fs_1.default.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
35
|
+
}
|
|
36
|
+
function clearConfig() {
|
|
37
|
+
const configPath = getConfigPath();
|
|
38
|
+
if (node_fs_1.default.existsSync(configPath)) {
|
|
39
|
+
node_fs_1.default.unlinkSync(configPath);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function getApiUrl() {
|
|
43
|
+
const config = readConfig();
|
|
44
|
+
return process.env.AMULETS_API_URL ?? config?.apiUrl ?? 'https://www.amulets.dev';
|
|
45
|
+
}
|
|
46
|
+
// Returns a valid access token, refreshing via the web app if it expires within 60 seconds.
|
|
47
|
+
async function getValidToken() {
|
|
48
|
+
const config = readConfig();
|
|
49
|
+
if (!config?.token) {
|
|
50
|
+
console.error('Not logged in. Run `amulets login` first.');
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
const expiresAt = config.expires_at ?? 0;
|
|
54
|
+
const needsRefresh = Date.now() >= expiresAt - 60_000;
|
|
55
|
+
if (needsRefresh && config.refresh_token) {
|
|
56
|
+
try {
|
|
57
|
+
const apiUrl = getApiUrl();
|
|
58
|
+
const res = await fetch(`${apiUrl}/api/auth/refresh`, {
|
|
59
|
+
method: 'POST',
|
|
60
|
+
headers: { 'Content-Type': 'application/json' },
|
|
61
|
+
body: JSON.stringify({ refresh_token: config.refresh_token }),
|
|
62
|
+
});
|
|
63
|
+
if (res.ok) {
|
|
64
|
+
const refreshed = (await res.json());
|
|
65
|
+
const updated = {
|
|
66
|
+
...config,
|
|
67
|
+
token: refreshed.access_token,
|
|
68
|
+
refresh_token: refreshed.refresh_token,
|
|
69
|
+
expires_at: Date.now() + refreshed.expires_in * 1000,
|
|
70
|
+
};
|
|
71
|
+
writeConfig(updated);
|
|
72
|
+
return updated.token;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Refresh failed — fall through and try with existing token.
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return config.token;
|
|
80
|
+
}
|
|
81
|
+
async function requireToken() {
|
|
82
|
+
const config = readConfig();
|
|
83
|
+
if (!config?.token) {
|
|
84
|
+
console.error('Not logged in. Run `amulets login` first.');
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
return getValidToken();
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":";;;;;AAaA,sCAEC;AAED,gCASC;AAED,kCAIC;AAED,kCAKC;AAED,8BAGC;AAGD,sCAwCC;AAED,oCAOC;AAhGD,sDAAwB;AACxB,sDAAwB;AACxB,0DAA4B;AAW5B,SAAgB,aAAa;IAC3B,OAAO,mBAAI,CAAC,IAAI,CAAC,iBAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,CAAC,CAAA;AACrE,CAAC;AAED,SAAgB,UAAU;IACxB,MAAM,UAAU,GAAG,aAAa,EAAE,CAAA;IAClC,IAAI,CAAC,iBAAE,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAA;IAC3C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,iBAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;QAChD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAW,CAAA;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,SAAgB,WAAW,CAAC,MAAc;IACxC,MAAM,UAAU,GAAG,aAAa,EAAE,CAAA;IAClC,iBAAE,CAAC,SAAS,CAAC,mBAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC3D,iBAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;AAC/D,CAAC;AAED,SAAgB,WAAW;IACzB,MAAM,UAAU,GAAG,aAAa,EAAE,CAAA;IAClC,IAAI,iBAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,iBAAE,CAAC,UAAU,CAAC,UAAU,CAAC,CAAA;IAC3B,CAAC;AACH,CAAC;AAED,SAAgB,SAAS;IACvB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;IAC3B,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,MAAM,EAAE,MAAM,IAAI,yBAAyB,CAAA;AACnF,CAAC;AAED,4FAA4F;AACrF,KAAK,UAAU,aAAa;IACjC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;IAC3B,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;QACnB,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAA;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,IAAI,CAAC,CAAA;IACxC,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,SAAS,GAAG,MAAM,CAAA;IAErD,IAAI,YAAY,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;QACzC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;YAC1B,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,mBAAmB,EAAE;gBACpD,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,aAAa,EAAE,MAAM,CAAC,aAAa,EAAE,CAAC;aAC9D,CAAC,CAAA;YAEF,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;gBACX,MAAM,SAAS,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAIlC,CAAA;gBACD,MAAM,OAAO,GAAW;oBACtB,GAAG,MAAM;oBACT,KAAK,EAAE,SAAS,CAAC,YAAY;oBAC7B,aAAa,EAAE,SAAS,CAAC,aAAa;oBACtC,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,UAAU,GAAG,IAAI;iBACrD,CAAA;gBACD,WAAW,CAAC,OAAO,CAAC,CAAA;gBACpB,OAAO,OAAO,CAAC,KAAK,CAAA;YACtB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,6DAA6D;QAC/D,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC,KAAK,CAAA;AACrB,CAAC;AAEM,KAAK,UAAU,YAAY;IAChC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;IAC3B,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;QACnB,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAA;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IACD,OAAO,aAAa,EAAE,CAAA;AACxB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-check.d.ts","sourceRoot":"","sources":["../../src/lib/update-check.ts"],"names":[],"mappings":"AA4CA,wBAAsB,gBAAgB,CACpC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAChC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoBxB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAO1E"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.startUpdateCheck = startUpdateCheck;
|
|
7
|
+
exports.formatUpdateNotice = formatUpdateNotice;
|
|
8
|
+
const node_https_1 = __importDefault(require("node:https"));
|
|
9
|
+
const config_js_1 = require("./config.js");
|
|
10
|
+
const CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
11
|
+
const FETCH_TIMEOUT_MS = 5_000;
|
|
12
|
+
function fetchLatestVersion(packageName) {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
const req = node_https_1.default.get(`https://registry.npmjs.org/${packageName}/latest`, { headers: { Accept: 'application/json' } }, (res) => {
|
|
15
|
+
let body = '';
|
|
16
|
+
res.on('data', (chunk) => {
|
|
17
|
+
body += chunk;
|
|
18
|
+
});
|
|
19
|
+
res.on('end', () => {
|
|
20
|
+
try {
|
|
21
|
+
const data = JSON.parse(body);
|
|
22
|
+
resolve(data.version);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
reject(new Error('Failed to parse npm registry response'));
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
req.setTimeout(FETCH_TIMEOUT_MS, () => {
|
|
30
|
+
req.destroy();
|
|
31
|
+
reject(new Error('npm registry request timed out'));
|
|
32
|
+
});
|
|
33
|
+
req.on('error', reject);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function isNewer(current, latest) {
|
|
37
|
+
const parse = (v) => v.split('.').map(Number);
|
|
38
|
+
const [cMaj, cMin, cPat] = parse(current);
|
|
39
|
+
const [lMaj, lMin, lPat] = parse(latest);
|
|
40
|
+
if ([cMaj, cMin, cPat, lMaj, lMin, lPat].some((n) => !Number.isFinite(n)))
|
|
41
|
+
return false;
|
|
42
|
+
if (lMaj !== cMaj)
|
|
43
|
+
return lMaj > cMaj;
|
|
44
|
+
if (lMin !== cMin)
|
|
45
|
+
return lMin > cMin;
|
|
46
|
+
return lPat > cPat;
|
|
47
|
+
}
|
|
48
|
+
async function startUpdateCheck(currentVersion, options = {}) {
|
|
49
|
+
try {
|
|
50
|
+
const config = (0, config_js_1.readConfig)();
|
|
51
|
+
const now = Date.now();
|
|
52
|
+
const stale = !config?.lastUpdateCheck || now - config.lastUpdateCheck > CACHE_TTL_MS;
|
|
53
|
+
if (!options.force && !stale && config?.latestVersion) {
|
|
54
|
+
return isNewer(currentVersion, config.latestVersion) ? config.latestVersion : null;
|
|
55
|
+
}
|
|
56
|
+
const latest = await fetchLatestVersion('amulets-cli');
|
|
57
|
+
if (config?.token) {
|
|
58
|
+
(0, config_js_1.writeConfig)({ ...config, lastUpdateCheck: now, latestVersion: latest });
|
|
59
|
+
}
|
|
60
|
+
return isNewer(currentVersion, latest) ? latest : null;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function formatUpdateNotice(current, latest) {
|
|
67
|
+
return [
|
|
68
|
+
'',
|
|
69
|
+
` Update available: ${current} → ${latest}`,
|
|
70
|
+
` Run: npm install -g amulets-cli@latest`,
|
|
71
|
+
'',
|
|
72
|
+
].join('\n');
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=update-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-check.js","sourceRoot":"","sources":["../../src/lib/update-check.ts"],"names":[],"mappings":";;;;;AA4CA,4CAuBC;AAED,gDAOC;AA5ED,4DAA8B;AAC9B,2CAAqD;AAErD,MAAM,YAAY,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA,CAAC,WAAW;AACpD,MAAM,gBAAgB,GAAG,KAAK,CAAA;AAE9B,SAAS,kBAAkB,CAAC,WAAmB;IAC7C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,GAAG,GAAG,oBAAK,CAAC,GAAG,CACnB,8BAA8B,WAAW,SAAS,EAClD,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,EAC3C,CAAC,GAAG,EAAE,EAAE;YACN,IAAI,IAAI,GAAG,EAAE,CAAA;YACb,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;gBAC/B,IAAI,IAAI,KAAK,CAAA;YACf,CAAC,CAAC,CAAA;YACF,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;gBACjB,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAwB,CAAA;oBACpD,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;gBACvB,CAAC;gBAAC,MAAM,CAAC;oBACP,MAAM,CAAC,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC,CAAA;gBAC5D,CAAC;YACH,CAAC,CAAC,CAAA;QACJ,CAAC,CACF,CAAA;QACD,GAAG,CAAC,UAAU,CAAC,gBAAgB,EAAE,GAAG,EAAE;YACpC,GAAG,CAAC,OAAO,EAAE,CAAA;YACb,MAAM,CAAC,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC,CAAA;QACrD,CAAC,CAAC,CAAA;QACF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;IACzB,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,OAAO,CAAC,OAAe,EAAE,MAAc;IAC9C,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACrD,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,CAAA;IACzC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAA;IACxC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAA;IACvF,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,GAAG,IAAI,CAAA;IACrC,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,GAAG,IAAI,CAAA;IACrC,OAAO,IAAI,GAAG,IAAI,CAAA;AACpB,CAAC;AAEM,KAAK,UAAU,gBAAgB,CACpC,cAAsB,EACtB,UAA+B,EAAE;IAEjC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAA,sBAAU,GAAE,CAAA;QAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACtB,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,eAAe,IAAI,GAAG,GAAG,MAAM,CAAC,eAAe,GAAG,YAAY,CAAA;QAErF,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,KAAK,IAAI,MAAM,EAAE,aAAa,EAAE,CAAC;YACtD,OAAO,OAAO,CAAC,cAAc,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAA;QACpF,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,aAAa,CAAC,CAAA;QAEtD,IAAI,MAAM,EAAE,KAAK,EAAE,CAAC;YAClB,IAAA,uBAAW,EAAC,EAAE,GAAG,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,CAAA;QACzE,CAAC;QAED,OAAO,OAAO,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,SAAgB,kBAAkB,CAAC,OAAe,EAAE,MAAc;IAChE,OAAO;QACL,EAAE;QACF,uBAAuB,OAAO,MAAM,MAAM,EAAE;QAC5C,0CAA0C;QAC1C,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACd,CAAC"}
|