@shoplifter/cli 0.1.1 → 0.1.2
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 +4 -1
- package/dist/auth.js +9 -4
- package/dist/index.js +2 -1
- package/dist/release-manifest.json +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Shoplifter CLI
|
|
2
2
|
|
|
3
|
-
Requires Node 24. Install with `npm install --global @shoplifter/cli@0.1.
|
|
3
|
+
Requires Node 24. Install with `npm install --global @shoplifter/cli@0.1.2`.
|
|
4
4
|
It continues using SDK and contract `0.1.0`; CLI patches do not upgrade runtime inputs.
|
|
5
5
|
|
|
6
6
|
## Authoring
|
|
@@ -44,6 +44,9 @@ Only channels accessible to your dashboard account can be selected; publishing m
|
|
|
44
44
|
be enabled for the channel. Switching channels clears the reviewed request.
|
|
45
45
|
One-hour credentials
|
|
46
46
|
are stored with private permissions outside the project. Use `shoplifter logout` to revoke.
|
|
47
|
+
CLI `0.1.2` tolerates up to five minutes of server clock lead when validating a
|
|
48
|
+
new one-hour credential; server-side token expiry remains one hour. This fixes
|
|
49
|
+
approved logins rejected by `0.1.1` when server and developer clocks differ slightly.
|
|
47
50
|
`shoplifter publication upload <channel-code>` uploads source; `stage`, `preview`,
|
|
48
51
|
`build`, `activate`, `publish`, `status`, `logs`, `retry`, `retry-deployment` and
|
|
49
52
|
`rollback` operate on channel-scoped revisions. `preview-link` requests protected
|
package/dist/auth.js
CHANGED
|
@@ -14,6 +14,8 @@ export function apiOrigin() {
|
|
|
14
14
|
}
|
|
15
15
|
const directory = () => resolve(process.env.SHOPLIFTER_CONFIG_DIRECTORY ?? resolve(homedir(), '.config/shoplifter'));
|
|
16
16
|
const filename = () => resolve(directory(), createHash('sha256').update(apiOrigin().origin).digest('hex') + '.json');
|
|
17
|
+
// The server enforces token lifetime. Allow bounded clock skew when checking its expiry locally.
|
|
18
|
+
const credentialClockSkewMs = 5 * 60 * 1000;
|
|
17
19
|
export async function credentials(required = true) {
|
|
18
20
|
try {
|
|
19
21
|
if (process.platform !== 'win32' && (await stat(filename())).mode & 0o077)
|
|
@@ -63,10 +65,13 @@ export async function login(channelCode) {
|
|
|
63
65
|
continue;
|
|
64
66
|
if (result.status !== 'approved')
|
|
65
67
|
throw new Error('CLI authorization denied or expired');
|
|
66
|
-
if (!/^slw_[A-Za-z0-9_-]{43}$/.test(result.token) || !/^\d+$/.test(result.channelId)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
if (!/^slw_[A-Za-z0-9_-]{43}$/.test(result.token) || !/^\d+$/.test(result.channelId))
|
|
69
|
+
throw new Error('Invalid CLI credential response (session format)');
|
|
70
|
+
const expiresAt = Date.parse(result.expiresAt), now = Date.now();
|
|
71
|
+
if (!Number.isFinite(expiresAt) || expiresAt <= now)
|
|
72
|
+
throw new Error('Invalid CLI credential response (invalid or expired session)');
|
|
73
|
+
if (expiresAt > now + 3600000 + credentialClockSkewMs)
|
|
74
|
+
throw new Error('Invalid CLI credential response (expiry exceeds one hour plus clock tolerance; check your system clock)');
|
|
70
75
|
const approvedCode = await sessionChannel(result.token);
|
|
71
76
|
if (channelCode && approvedCode !== channelCode) {
|
|
72
77
|
await response(await fetch(new URL('/shoplifter-cli/logout', origin), { method: 'POST', headers: { authorization: 'Bearer ' + result.token }, signal: AbortSignal.timeout(15000) }));
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
13
13
|
};
|
|
14
14
|
import { program, command, requiredArg, optionalArg, description, version } from 'commander-ts';
|
|
15
15
|
import { spawn } from 'node:child_process';
|
|
16
|
+
import { readFileSync } from 'node:fs';
|
|
16
17
|
import { initialize, editProject, scaffold } from './author.js';
|
|
17
18
|
import { generate, validateImages } from './files.js';
|
|
18
19
|
import { publication, previewUpload } from './publication.js';
|
|
@@ -207,7 +208,7 @@ __decorate([
|
|
|
207
208
|
], Shoplifter.prototype, "publication", null);
|
|
208
209
|
Shoplifter = __decorate([
|
|
209
210
|
program(),
|
|
210
|
-
version('
|
|
211
|
+
version(JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version),
|
|
211
212
|
description('Author and publish independent Shoplifter presentations')
|
|
212
213
|
], Shoplifter);
|
|
213
214
|
if (Number(process.versions.node.split('.')[0]) !== 24)
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
{
|
|
13
13
|
"path": "auth.js",
|
|
14
|
-
"sha256": "
|
|
14
|
+
"sha256": "848d11a0471e0e82cfd759b82b5a927517bcb6ff89b47e12f4b588995bd32077"
|
|
15
15
|
},
|
|
16
16
|
{
|
|
17
17
|
"path": "author.d.ts",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
37
|
"path": "index.js",
|
|
38
|
-
"sha256": "
|
|
38
|
+
"sha256": "d8a1ef1be4575a581f63ca1c51f71327b91728dfda1ddf77ece556b8f7847899"
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
"path": "publication.d.ts",
|