shiply-cli 0.7.1 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +104 -47
- package/dist/claim.js +32 -0
- package/dist/data-init.js +33 -0
- package/dist/data.js +99 -0
- package/dist/db.js +225 -0
- package/dist/detect.js +35 -0
- package/dist/domain.js +56 -0
- package/dist/framework.js +110 -0
- package/dist/index.js +327 -55
- package/dist/login.js +60 -0
- package/dist/publish.js +2 -0
- package/package.json +38 -23
- package/skill/SKILL.md +371 -129
package/dist/login.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { hostname } from 'node:os';
|
|
2
|
+
import { api, ApiError } from './publish.js';
|
|
3
|
+
/** RFC 8628 client. The default for `shiply login`: no email round-trip,
|
|
4
|
+
* no manual code paste — just open a URL, click Allow, return to the
|
|
5
|
+
* terminal. The user can override the displayed agent name with --name
|
|
6
|
+
* (otherwise we synthesize from hostname). */
|
|
7
|
+
export async function loginViaDeviceFlow(base, agentNameOverride) {
|
|
8
|
+
const agentName = (agentNameOverride ?? `shiply-cli on ${hostname()}`).trim().slice(0, 80);
|
|
9
|
+
const start = await api(`${base}/api/v1/auth/device/start`, {
|
|
10
|
+
method: 'POST',
|
|
11
|
+
headers: { 'content-type': 'application/json' },
|
|
12
|
+
body: JSON.stringify({ agent_name: agentName }),
|
|
13
|
+
});
|
|
14
|
+
// Print the URL prominently — the user must open it. We don't auto-launch
|
|
15
|
+
// a browser because the CLI runs in headless contexts (CI, SSH, containers)
|
|
16
|
+
// where opening a local browser would either fail silently or open in the
|
|
17
|
+
// wrong machine. Showing the URL is the predictable thing.
|
|
18
|
+
console.log('');
|
|
19
|
+
console.log(` → Open this URL to authorize ${agentName}:`);
|
|
20
|
+
console.log('');
|
|
21
|
+
console.log(` ${start.verification_url}`);
|
|
22
|
+
console.log('');
|
|
23
|
+
console.log(` Code shown there: ${start.user_code}`);
|
|
24
|
+
console.log(` Waiting up to ${Math.round(start.expires_in / 60)} minutes…`);
|
|
25
|
+
const deadline = Date.now() + start.expires_in * 1000;
|
|
26
|
+
const intervalMs = Math.max(start.interval, 1) * 1000;
|
|
27
|
+
while (Date.now() < deadline) {
|
|
28
|
+
await sleep(intervalMs);
|
|
29
|
+
let poll;
|
|
30
|
+
try {
|
|
31
|
+
poll = await api(`${base}/api/v1/auth/device/poll`, {
|
|
32
|
+
method: 'POST',
|
|
33
|
+
headers: { 'content-type': 'application/json' },
|
|
34
|
+
body: JSON.stringify({ device_code: start.device_code }),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
// Transient network blip — don't kill the whole flow, the user has time.
|
|
39
|
+
if (e instanceof ApiError && e.status >= 500)
|
|
40
|
+
continue;
|
|
41
|
+
throw e;
|
|
42
|
+
}
|
|
43
|
+
if (poll.status === 'approved' && poll.api_key) {
|
|
44
|
+
return { ok: true, apiKey: poll.api_key, slug: poll.slug_claimed ?? null };
|
|
45
|
+
}
|
|
46
|
+
if (poll.status === 'denied')
|
|
47
|
+
return { ok: false, reason: 'denied by you in the browser' };
|
|
48
|
+
if (poll.status === 'expired')
|
|
49
|
+
return { ok: false, reason: 'authorization request expired' };
|
|
50
|
+
if (poll.status === 'consumed') {
|
|
51
|
+
// Another process already collected the key for this device_code; we
|
|
52
|
+
// can't recover it. Tell the user to retry.
|
|
53
|
+
return { ok: false, reason: 'this authorization was already collected elsewhere — retry to mint a fresh one' };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return { ok: false, reason: 'authorization timed out — re-run `shiply login` to try again' };
|
|
57
|
+
}
|
|
58
|
+
function sleep(ms) {
|
|
59
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
60
|
+
}
|
package/dist/publish.js
CHANGED
|
@@ -40,6 +40,8 @@ export async function publish(dir, opts = {}) {
|
|
|
40
40
|
...(opts.spaMode ? { spaMode: true } : {}),
|
|
41
41
|
...(opts.claimToken ? { claimToken: opts.claimToken } : {}),
|
|
42
42
|
...(opts.slug ? { slug: opts.slug } : {}),
|
|
43
|
+
...(opts.attachDatabaseId ? { attachDatabaseId: opts.attachDatabaseId } : {}),
|
|
44
|
+
...(opts.previewBranchDbId ? { previewBranchDbId: opts.previewBranchDbId } : {}),
|
|
43
45
|
}),
|
|
44
46
|
});
|
|
45
47
|
await uploadAll(dir, created.upload.uploads);
|
package/package.json
CHANGED
|
@@ -1,23 +1,38 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "shiply-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Publish static sites to shiply.now from the command line — instant web hosting for agents.",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"bin": {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "shiply-cli",
|
|
3
|
+
"version": "0.12.1",
|
|
4
|
+
"description": "Publish static sites to shiply.now from the command line — instant web hosting for agents.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"shiply": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"skill",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc -p tsconfig.build.json",
|
|
17
|
+
"prepublishOnly": "pnpm build",
|
|
18
|
+
"test": "vitest run",
|
|
19
|
+
"typecheck": "tsc --noEmit"
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"shiply",
|
|
26
|
+
"hosting",
|
|
27
|
+
"static",
|
|
28
|
+
"deploy",
|
|
29
|
+
"agents",
|
|
30
|
+
"publish"
|
|
31
|
+
],
|
|
32
|
+
"homepage": "https://shiply.now",
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"typescript": "^5.8.0",
|
|
35
|
+
"vitest": "^3.1.0",
|
|
36
|
+
"@types/node": "^22.15.0"
|
|
37
|
+
}
|
|
38
|
+
}
|