@freeappstore/cli 0.4.37 → 0.4.39

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 CHANGED
@@ -19,10 +19,11 @@ cd my-app
19
19
  pnpm install && pnpm dev
20
20
  fas check # compliance checks
21
21
  fas publish # provisions repo + hosting + DNS
22
- git push upstream main # auto-deploys via CI
22
+ git remote add upstream https://github.com/freeappstore-online/my-app.git
23
+ git push upstream main # follow the commands printed by fas publish
23
24
  ```
24
25
 
25
- Live in 30 seconds at `https://my-app.freeappstore.online`.
26
+ After the first successful code push and deploy, live at `https://my-app.freeappstore.online`.
26
27
 
27
28
  ## Commands
28
29
 
@@ -33,14 +34,14 @@ Live in 30 seconds at `https://my-app.freeappstore.online`.
33
34
  | `fas logout` | Clear the cached session. |
34
35
  | `fas whoami` | Print the currently signed-in GitHub login. |
35
36
  | `fas doctor` | Health check — Node version, git, pnpm, config, signed-in state, API reachability. |
36
- | `fas init <app-id>` | Scaffold a new free app or game from a platform template. Replaces `APPNAME` placeholders, runs `git init`, makes the first commit. |
37
+ | `fas init <app-id>` | Scaffold an app from a platform template. Game templates remain available; games are published with the separate fgs CLI. Replaces `APPNAME` placeholders, runs `git init`, makes the first commit. |
37
38
  | `fas check` | Run compliance checks (no-tracking, brand fonts, manifest, bundle size). Exits non-zero on hard failures. |
38
39
  | `fas publish` | Provisions repo + hosting route + storefront entry, injects `deploy.yml` if missing, then prints `git remote add` and `git push` instructions. Auto-runs `fas check` first. |
39
40
  | `fas list` (alias `fas ls`) | List apps and games you have published. `--json` for scripting, `-v` for recent commits. |
40
- | `fas logs <app-id>` | Tail live deployment logs for an app (GitHub Actions workflow runs). |
41
+ | `fas logs <app-id>` | Show recent deployment runs and links for an app (GitHub Actions). |
41
42
  | `fas secret set\|list\|rm` | Manage server-side encrypted API keys for an app. |
42
43
  | `fas proxy allow\|list\|deny` | Manage the URL allowlist for the per-app secret-injecting proxy. |
43
- | `fas screencheck` | Build the app and run a headless browser at every reference viewport to verify the layout fits without scrolling. |
44
+ | `fas screencheck` | Build the app and run a browser at the manifest-declared minimum width in portrait and landscape to verify the layout fits without scrolling. |
44
45
  | `fas quality [app-id]` | Show the VCQA code quality report (score + grade) for an app. |
45
46
  | `fas admin transfer-owner <app>` | Admin-only. Move an app to a new owner when `--from` matches the current one, and write an audit record. |
46
47
 
@@ -81,7 +82,7 @@ fas doctor
81
82
 
82
83
  ### `fas init <app-id>`
83
84
 
84
- Scaffold a new free app or game from a platform template. Clones the template repo, substitutes all `APPNAME` placeholders with the given id, and creates the first git commit.
85
+ Scaffold an app from a platform template. Game templates remain available; games are published with the separate fgs CLI. Clones the template repo, substitutes all `APPNAME` placeholders with the given id, and creates the first git commit.
85
86
 
86
87
  ```bash
87
88
  fas init my-app # default: standalone template
@@ -108,13 +109,13 @@ fas check --dir ../my-app
108
109
 
109
110
  ### `fas publish`
110
111
 
111
- Provision and publish an app to FreeAppStore (or FreeGameStore). Runs compliance checks, authenticates, creates a GitHub repo + R2 hosting route + storefront registry entry via the admin Worker, and injects a deploy workflow.
112
+ Provision and publish an app to FreeAppStore. Runs compliance checks, authenticates, creates a GitHub repo + R2 hosting route + storefront registry entry via the admin Worker, and injects a deploy workflow.
112
113
 
113
114
  By default, `publish` is interactive — it asks for category, type, oneliner, and demo URL. Skip prompts by passing flag values; combine with `--yes` to fail fast in CI rather than hang on a missing field.
114
115
 
115
116
  ```bash
116
117
  fas publish # interactive
117
- fas publish --store games # publish to FreeGameStore instead
118
+ fgs publish # FreeGameStore projects use their own CLI
118
119
  fas publish \
119
120
  --name my-app \
120
121
  --category Utilities \
@@ -125,13 +126,13 @@ fas publish \
125
126
 
126
127
  | Flag | Purpose |
127
128
  |---|---|
129
+ | `--store apps` | Legacy selector; the FAS backend rejects games with 410. Use the separate `fgs` CLI for FreeGameStore. |
128
130
  | `--name <id>` | App id (lowercase, used as subdomain). Defaults to `package.json#name`. |
129
131
  | `--category <name>` | Storefront category. Case-insensitive (e.g. `utilities`, `brain training`). |
130
132
  | `--type standalone\|connected` | Standalone (localStorage only) or Connected (uses platform backend). |
131
133
  | `--oneliner <text>` | One-line description shown on the storefront. |
132
134
  | `--demo <url>` | Optional demo URL. Pass `""` to clear. |
133
135
  | `--yes` | Non-interactive: missing required fields abort instead of prompting. |
134
- | `--issue` | Skip auto-provision; open the GitHub Issue submission form instead. |
135
136
  | `--skip-checks` | Skip `fas check` before publish (not recommended). |
136
137
 
137
138
  ### `fas list` (alias `fas ls`)
@@ -292,7 +293,7 @@ Every app and game on the platform shares the same visual language — colors, f
292
293
  5. **Ownership**: records the app in the platform DB so `fas list` returns it.
293
294
  6. **Output**: prints the live URL, repo URL, storefront listing URL, and the `git remote add` + `git push` commands to populate the new repo.
294
295
 
295
- If auto-provision is unavailable (503 from the API), `publish` falls back to opening a prefilled GitHub Issue form for maintainer review. Use `--issue` to force this path.
296
+ If provisioning is unavailable, the command reports the error and exits. Nothing is queued and no submission form opens. Retry after checking the platform status; `--issue` is not a supported flag.
296
297
 
297
298
  ## For AI Agents
298
299
 
@@ -1,3 +1,8 @@
1
1
  import { Command } from 'commander';
2
2
  export declare const logsCommand: Command;
3
+ /**
4
+ * Success only on exit code 0. A process killed by a signal exits with code
5
+ * null, which used to count as success (#283).
6
+ */
7
+ export declare function ghExitError(code: number | null, signal: NodeJS.Signals | null): Error | null;
3
8
  //# sourceMappingURL=logs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,eAAO,MAAM,WAAW,SAyBpB,CAAC"}
1
+ {"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,eAAO,MAAM,WAAW,SA0BpB,CAAC;AAEL;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,CAK5F"}
@@ -20,12 +20,22 @@ export const logsCommand = new Command('logs')
20
20
  rejectFn(err);
21
21
  }
22
22
  });
23
- child.on('exit', (code) => {
24
- if (code === 0 || code === null)
25
- resolveFn();
23
+ child.on('exit', (code, signal) => {
24
+ const err = ghExitError(code, signal);
25
+ if (err)
26
+ rejectFn(err);
26
27
  else
27
- rejectFn(new Error(`gh exited with code ${code}`));
28
+ resolveFn();
28
29
  });
29
30
  });
30
31
  });
32
+ /**
33
+ * Success only on exit code 0. A process killed by a signal exits with code
34
+ * null, which used to count as success (#283).
35
+ */
36
+ export function ghExitError(code, signal) {
37
+ if (code === 0)
38
+ return null;
39
+ return new Error(code === null ? `gh was stopped by ${signal ?? 'a signal'}` : `gh exited with code ${code}`);
40
+ }
31
41
  //# sourceMappingURL=logs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC3C,WAAW,CAAC,sDAAsD,CAAC;KACnE,QAAQ,CAAC,UAAU,EAAE,kCAAkC,CAAC;KACxD,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,EAAE;IAC9B,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAExB,MAAM,IAAI,GAAG,uBAAuB,KAAK,EAAE,CAAC;IAC5C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,IAAI,OAAO,CAAC,CAAC;IAEhE,MAAM,IAAI,OAAO,CAAO,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE;QAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE;YAC1E,KAAK,EAAE,SAAS;SACjB,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACrD,QAAQ,CAAC,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC,CAAC;YACrF,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,GAAG,CAAC,CAAC;YAChB,CAAC;QACH,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,IAAI;gBAAE,SAAS,EAAE,CAAC;;gBACxC,QAAQ,CAAC,IAAI,KAAK,CAAC,uBAAuB,IAAI,EAAE,CAAC,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC3C,WAAW,CAAC,sDAAsD,CAAC;KACnE,QAAQ,CAAC,UAAU,EAAE,kCAAkC,CAAC;KACxD,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,EAAE;IAC9B,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAExB,MAAM,IAAI,GAAG,uBAAuB,KAAK,EAAE,CAAC;IAC5C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,IAAI,OAAO,CAAC,CAAC;IAEhE,MAAM,IAAI,OAAO,CAAO,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE;QAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE;YAC1E,KAAK,EAAE,SAAS;SACjB,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACrD,QAAQ,CAAC,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC,CAAC;YACrF,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,GAAG,CAAC,CAAC;YAChB,CAAC;QACH,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;YAChC,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACtC,IAAI,GAAG;gBAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;;gBAClB,SAAS,EAAE,CAAC;QACnB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEL;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,IAAmB,EAAE,MAA6B;IAC5E,IAAI,IAAI,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5B,OAAO,IAAI,KAAK,CACd,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,qBAAqB,MAAM,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,uBAAuB,IAAI,EAAE,CAC5F,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=logs.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.test.d.ts","sourceRoot":"","sources":["../../src/commands/logs.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,15 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { ghExitError } from './logs.js';
3
+ // #283: a gh killed by a signal (exit code null) counted as success.
4
+ describe('ghExitError', () => {
5
+ it('is null only for exit code 0', () => {
6
+ expect(ghExitError(0, null)).toBeNull();
7
+ });
8
+ it('fails on a non-zero code', () => {
9
+ expect(ghExitError(1, null)?.message).toBe('gh exited with code 1');
10
+ });
11
+ it('fails when gh was killed by a signal', () => {
12
+ expect(ghExitError(null, 'SIGTERM')?.message).toBe('gh was stopped by SIGTERM');
13
+ });
14
+ });
15
+ //# sourceMappingURL=logs.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.test.js","sourceRoot":"","sources":["../../src/commands/logs.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,qEAAqE;AACrE,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1,3 +1,10 @@
1
1
  import { Command } from 'commander';
2
+ import { type FasConfig } from '../lib/config.js';
2
3
  export declare const whoamiCommand: Command;
4
+ /**
5
+ * The session line. sessionDaysRemaining() is null both when there's no
6
+ * session token and when an older CLI saved one without a timestamp; only
7
+ * the second is active (#283).
8
+ */
9
+ export declare function sessionStatus(config: FasConfig): string;
3
10
  //# sourceMappingURL=whoami.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"whoami.d.ts","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,eAAO,MAAM,aAAa,SAsBtB,CAAC"}
1
+ {"version":3,"file":"whoami.d.ts","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,KAAK,SAAS,EAAoC,MAAM,kBAAkB,CAAC;AAEpF,eAAO,MAAM,aAAa,SAatB,CAAC;AAEL;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAMvD"}
@@ -11,15 +11,21 @@ export const whoamiCommand = new Command('whoami')
11
11
  process.stdout.write(`@${config.github.login}\n`);
12
12
  // Surface session health so an expired token is self-diagnosable here
13
13
  // rather than as a surprise 401 mid-publish.
14
- const daysLeft = sessionDaysRemaining(config);
15
- if (daysLeft === null) {
16
- process.stdout.write('Session: active\n');
17
- }
18
- else if (daysLeft <= 0) {
19
- process.stdout.write('Session: expired — run `fas login` to refresh.\n');
20
- }
21
- else {
22
- process.stdout.write(`Session: active, expires in ${daysLeft} day${daysLeft === 1 ? '' : 's'}.\n`);
23
- }
14
+ process.stdout.write(`${sessionStatus(config)}\n`);
24
15
  });
16
+ /**
17
+ * The session line. sessionDaysRemaining() is null both when there's no
18
+ * session token and when an older CLI saved one without a timestamp; only
19
+ * the second is active (#283).
20
+ */
21
+ export function sessionStatus(config) {
22
+ if (!config.session?.token)
23
+ return 'Session: none — run `fas login` to sign in to the API.';
24
+ const daysLeft = sessionDaysRemaining(config);
25
+ if (daysLeft === null)
26
+ return 'Session: active (expiry unknown)';
27
+ if (daysLeft <= 0)
28
+ return 'Session: expired — run `fas login` to refresh.';
29
+ return `Session: active, expires in ${daysLeft} day${daysLeft === 1 ? '' : 's'}.`;
30
+ }
25
31
  //# sourceMappingURL=whoami.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAEpE,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,uDAAuD,CAAC;KACpE,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;QAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;IAElD,sEAAsE;IACtE,6CAA6C;IAC7C,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC9C,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IAC5C,CAAC;SAAM,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;IAC3E,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,+BAA+B,QAAQ,OAAO,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,CAC7E,CAAC;IACJ,CAAC;AACH,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAkB,UAAU,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAEpF,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,uDAAuD,CAAC;KACpE,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;QAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;IAElD,sEAAsE;IACtE,6CAA6C;IAC7C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACrD,CAAC,CAAC,CAAC;AAEL;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,MAAiB;IAC7C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK;QAAE,OAAO,wDAAwD,CAAC;IAC5F,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC9C,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,kCAAkC,CAAC;IACjE,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,gDAAgD,CAAC;IAC3E,OAAO,+BAA+B,QAAQ,OAAO,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;AACpF,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=whoami.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.test.d.ts","sourceRoot":"","sources":["../../src/commands/whoami.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { sessionStatus } from './whoami.js';
3
+ const DAY = 24 * 60 * 60 * 1000;
4
+ const github = { login: 'alice', token: 'gh' };
5
+ // #283: a missing session token used to print "Session: active".
6
+ describe('sessionStatus', () => {
7
+ it('says there is no session when the token is missing', () => {
8
+ expect(sessionStatus({ github })).toBe('Session: none — run `fas login` to sign in to the API.');
9
+ });
10
+ it('is active with unknown expiry for a token saved without a timestamp', () => {
11
+ expect(sessionStatus({ github, session: { token: 't' } })).toBe('Session: active (expiry unknown)');
12
+ });
13
+ it('counts down and reports expiry', () => {
14
+ expect(sessionStatus({ github, session: { token: 't', obtainedAt: Date.now() - DAY } })).toMatch(/^Session: active, expires in \d+ days\.$/);
15
+ expect(sessionStatus({
16
+ github,
17
+ session: { token: 't', obtainedAt: Date.now() - 400 * DAY },
18
+ })).toBe('Session: expired — run `fas login` to refresh.');
19
+ });
20
+ });
21
+ //# sourceMappingURL=whoami.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.test.js","sourceRoot":"","sources":["../../src/commands/whoami.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAChC,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AAE/C,iEAAiE;AACjE,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,CAAC,aAAa,CAAC,EAAE,MAAM,EAAW,CAAC,CAAC,CAAC,IAAI,CAC7C,wDAAwD,CACzD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,MAAM,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,EAAW,CAAC,CAAC,CAAC,IAAI,CACtE,kCAAkC,CACnC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CACJ,aAAa,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,EAAE,EAAW,CAAC,CAC1F,CAAC,OAAO,CAAC,0CAA0C,CAAC,CAAC;QACtD,MAAM,CACJ,aAAa,CAAC;YACZ,MAAM;YACN,OAAO,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,EAAE;SACnD,CAAC,CACZ,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@freeappstore/cli",
3
- "version": "0.4.37",
3
+ "version": "0.4.39",
4
4
  "description": "fas — CLI for publishing free apps to freeappstore.online",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -21,7 +21,7 @@
21
21
  "cli",
22
22
  "scaffold",
23
23
  "publish",
24
- "cloudflare-pages"
24
+ "cloudflare-r2"
25
25
  ],
26
26
  "files": [
27
27
  "dist",
@@ -37,8 +37,8 @@
37
37
  "ink-spinner": "^5.0.0",
38
38
  "prompts": "^2.4.2",
39
39
  "react": "^19.3.0",
40
- "@freeappstore/quality": "0.1.4",
41
- "@freeappstore/compliance": "0.7.15"
40
+ "@freeappstore/compliance": "0.7.16",
41
+ "@freeappstore/quality": "0.1.5"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/node": "^22.20.2",