@proappstore/cli 2.3.0 → 2.4.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/dist/create.d.ts.map +1 -1
- package/dist/create.js +82 -207
- package/dist/create.js.map +1 -1
- package/dist/domain.d.ts +3 -0
- package/dist/domain.d.ts.map +1 -0
- package/dist/domain.js +193 -0
- package/dist/domain.js.map +1 -0
- package/dist/index.js +6 -10
- package/dist/index.js.map +1 -1
- package/dist/lib/config.d.ts +23 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +54 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/github.d.ts +11 -0
- package/dist/lib/github.d.ts.map +1 -0
- package/dist/lib/github.js +60 -0
- package/dist/lib/github.js.map +1 -0
- package/dist/login.d.ts +6 -0
- package/dist/login.d.ts.map +1 -0
- package/dist/login.js +34 -0
- package/dist/login.js.map +1 -0
- package/dist/publish.d.ts.map +1 -1
- package/dist/publish.js +37 -4
- package/dist/publish.js.map +1 -1
- package/package.json +1 -1
package/dist/create.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"AAgBA,UAAU,aAAa;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgGtF"}
|
package/dist/create.js
CHANGED
|
@@ -1,230 +1,58 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
// In published form: <pkg>/dist/create.js + <pkg>/templates/*. In dev
|
|
8
|
-
// (tsx, esno): <pkg>/src/create.ts + <pkg>/templates/*. Walk up from
|
|
9
|
-
// __dirname to the package root and append templates/.
|
|
10
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
-
const TEMPLATES_DIR = join(__dirname, '..', 'templates');
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { access, readdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { writeFileSync } from 'node:fs';
|
|
4
|
+
import { extname, join, resolve } from 'node:path';
|
|
5
|
+
import { resolveToken } from './lib/config.js';
|
|
6
|
+
const TEMPLATE_REPO = 'proappstore-online/template-app';
|
|
12
7
|
const PAS_API = 'https://api.proappstore.online';
|
|
13
|
-
const
|
|
14
|
-
'
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"engines": { "node": ">=22" },
|
|
19
|
-
"repository": { "type": "git", "url": "git+https://github.com/proappstore-online/__APP_ID__.git" },
|
|
20
|
-
"scripts": {
|
|
21
|
-
"dev": "pnpm --filter @__APP_ID__/web dev",
|
|
22
|
-
"build": "pnpm --filter @__APP_ID__/web build",
|
|
23
|
-
"preview": "pnpm --filter @__APP_ID__/web preview",
|
|
24
|
-
"typecheck": "pnpm --filter @__APP_ID__/web exec tsc -b",
|
|
25
|
-
"test": "pnpm --filter @__APP_ID__/web exec tsc -b"
|
|
26
|
-
}
|
|
27
|
-
}`,
|
|
28
|
-
'pnpm-workspace.yaml': `packages:\n - web`,
|
|
29
|
-
'tsconfig.json': `{ "references": [{ "path": "./web" }], "files": [] }`,
|
|
30
|
-
'LICENSE': `MIT License\n\nCopyright (c) ${new Date().getFullYear()} ProAppStore\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.`,
|
|
31
|
-
'CLAUDE.md': `# __APP_ID__\n\n__APP_DESCRIPTION__\n\n- Subdomain: \`__APP_ID__.proappstore.online\`\n- Dev: \`pnpm install && pnpm dev\`\n- Build: \`pnpm build\`\n- Deploy: \`git push origin main\` (auto-deploys via Cloudflare Pages)\n\nFor platform conventions, read\nhttps://proappstore.online/skills.md\nbefore writing or changing anything.`,
|
|
32
|
-
'.gitignore': `node_modules/\ndist/\n.DS_Store\n*.log\n.env\n.env.local`,
|
|
33
|
-
'web/package.json': `{
|
|
34
|
-
"name": "@__APP_ID__/web",
|
|
35
|
-
"private": true,
|
|
36
|
-
"version": "0.1.0",
|
|
37
|
-
"type": "module",
|
|
38
|
-
"scripts": {
|
|
39
|
-
"dev": "vite",
|
|
40
|
-
"build": "tsc -b && vite build",
|
|
41
|
-
"preview": "vite preview"
|
|
42
|
-
},
|
|
43
|
-
"dependencies": {
|
|
44
|
-
"@proappstore/sdk": "^1.5.0",
|
|
45
|
-
"react": "^19.2.5",
|
|
46
|
-
"react-dom": "^19.2.5"
|
|
47
|
-
},
|
|
48
|
-
"devDependencies": {
|
|
49
|
-
"@tailwindcss/vite": "^4.2.4",
|
|
50
|
-
"@types/react": "^19.2.14",
|
|
51
|
-
"@types/react-dom": "^19.2.3",
|
|
52
|
-
"@vitejs/plugin-react": "^6.0.1",
|
|
53
|
-
"tailwindcss": "^4.2.4",
|
|
54
|
-
"typescript": "~6.0.2",
|
|
55
|
-
"vite": "^8.0.10",
|
|
56
|
-
"vite-plugin-pwa": "^1.3.0"
|
|
57
|
-
}
|
|
58
|
-
}`,
|
|
59
|
-
'web/tsconfig.json': `{\n "files": [],\n "references": [\n { "path": "./tsconfig.app.json" },\n { "path": "./tsconfig.node.json" }\n ]\n}`,
|
|
60
|
-
'web/tsconfig.app.json': `{
|
|
61
|
-
"compilerOptions": {
|
|
62
|
-
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
63
|
-
"target": "es2023",
|
|
64
|
-
"lib": ["ES2023", "DOM", "DOM.Iterable"],
|
|
65
|
-
"module": "esnext",
|
|
66
|
-
"types": ["vite/client"],
|
|
67
|
-
"skipLibCheck": true,
|
|
68
|
-
"moduleResolution": "bundler",
|
|
69
|
-
"allowImportingTsExtensions": true,
|
|
70
|
-
"verbatimModuleSyntax": true,
|
|
71
|
-
"moduleDetection": "force",
|
|
72
|
-
"noEmit": true,
|
|
73
|
-
"jsx": "react-jsx",
|
|
74
|
-
"noUnusedLocals": true,
|
|
75
|
-
"noUnusedParameters": true,
|
|
76
|
-
"erasableSyntaxOnly": true,
|
|
77
|
-
"noFallthroughCasesInSwitch": true
|
|
78
|
-
},
|
|
79
|
-
"include": ["src"]
|
|
80
|
-
}`,
|
|
81
|
-
'web/tsconfig.node.json': `{
|
|
82
|
-
"compilerOptions": {
|
|
83
|
-
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
84
|
-
"target": "es2023",
|
|
85
|
-
"lib": ["ES2023"],
|
|
86
|
-
"module": "esnext",
|
|
87
|
-
"skipLibCheck": true,
|
|
88
|
-
"moduleResolution": "bundler",
|
|
89
|
-
"allowImportingTsExtensions": true,
|
|
90
|
-
"verbatimModuleSyntax": true,
|
|
91
|
-
"moduleDetection": "force",
|
|
92
|
-
"noEmit": true
|
|
93
|
-
},
|
|
94
|
-
"include": ["vite.config.ts"]
|
|
95
|
-
}`,
|
|
96
|
-
'web/vite.config.ts': `import { defineConfig } from 'vite'
|
|
97
|
-
import react from '@vitejs/plugin-react'
|
|
98
|
-
import tailwindcss from '@tailwindcss/vite'
|
|
99
|
-
import { VitePWA } from 'vite-plugin-pwa'
|
|
100
|
-
|
|
101
|
-
export default defineConfig({
|
|
102
|
-
plugins: [
|
|
103
|
-
react(),
|
|
104
|
-
tailwindcss(),
|
|
105
|
-
VitePWA({
|
|
106
|
-
registerType: 'autoUpdate',
|
|
107
|
-
workbox: {
|
|
108
|
-
globPatterns: ['**/*.{js,css,html,png,svg,ico,woff2,wasm,json}'],
|
|
109
|
-
maximumFileSizeToCacheInBytes: 10 * 1024 * 1024,
|
|
110
|
-
runtimeCaching: [
|
|
111
|
-
{
|
|
112
|
-
urlPattern: /^https:\\/\\/fonts\\.googleapis\\.com\\/.*/i,
|
|
113
|
-
handler: 'CacheFirst',
|
|
114
|
-
options: {
|
|
115
|
-
cacheName: 'google-fonts-stylesheets',
|
|
116
|
-
expiration: { maxEntries: 10, maxAgeSeconds: 60 * 60 * 24 * 365 },
|
|
117
|
-
cacheableResponse: { statuses: [0, 200] },
|
|
118
|
-
},
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
urlPattern: /^https:\\/\\/fonts\\.gstatic\\.com\\/.*/i,
|
|
122
|
-
handler: 'CacheFirst',
|
|
123
|
-
options: {
|
|
124
|
-
cacheName: 'google-fonts-webfonts',
|
|
125
|
-
expiration: { maxEntries: 30, maxAgeSeconds: 60 * 60 * 24 * 365 },
|
|
126
|
-
cacheableResponse: { statuses: [0, 200] },
|
|
127
|
-
},
|
|
128
|
-
},
|
|
129
|
-
],
|
|
130
|
-
},
|
|
131
|
-
manifest: {
|
|
132
|
-
name: '__APP_NAME__',
|
|
133
|
-
short_name: '__APP_NAME__',
|
|
134
|
-
description: '__APP_NAME__ — pro app on ProAppStore',
|
|
135
|
-
start_url: '/',
|
|
136
|
-
display: 'standalone',
|
|
137
|
-
background_color: '#ffffff',
|
|
138
|
-
theme_color: '#7c3aed',
|
|
139
|
-
orientation: 'any',
|
|
140
|
-
icons: [
|
|
141
|
-
{ src: '/icon-192.png', sizes: '192x192', type: 'image/png', purpose: 'any maskable' },
|
|
142
|
-
{ src: '/icon-512.png', sizes: '512x512', type: 'image/png', purpose: 'any maskable' },
|
|
143
|
-
],
|
|
144
|
-
},
|
|
145
|
-
}),
|
|
146
|
-
],
|
|
147
|
-
server: { host: true },
|
|
148
|
-
})`,
|
|
149
|
-
'web/index.html': `<!doctype html>\n<html lang="en">\n <head>\n <meta charset="UTF-8" />\n <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, user-scalable=no" />\n <meta name="theme-color" content="#7c3aed" />\n <link rel="preconnect" href="https://fonts.googleapis.com" />\n <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />\n <link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,500;9..144,600;9..144,700&family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet" />\n <title>__APP_NAME__ — ProAppStore</title>\n </head>\n <body>\n <div id="root"></div>\n <script type="module" src="/src/main.tsx"></script>\n </body>\n</html>`,
|
|
150
|
-
'web/src/main.tsx': `import { StrictMode } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport './index.css'\nimport App from './App.tsx'\n\ncreateRoot(document.getElementById('root')!).render(\n <StrictMode>\n <App />\n </StrictMode>,\n)`,
|
|
151
|
-
'web/src/index.css': `@import "tailwindcss";\n\n@layer base {\n:root {\n color-scheme: light;\n --paper: #ffffff;\n --ink: #111111;\n --muted: #666666;\n --accent: #7c3aed;\n --accent-soft: #f5f3ff;\n --line: rgba(0,0,0,0.08);\n --glass: rgba(255,255,255,0.72);\n --glass-hover: rgba(255,255,255,0.85);\n --error: #c74f43;\n --success: #2f8f57;\n}\n\n:root[data-theme='dark'] {\n color-scheme: dark;\n --paper: #000000;\n --ink: #f0f0f0;\n --muted: #888888;\n --accent: #a78bfa;\n --accent-soft: #1e1533;\n --line: rgba(255,255,255,0.08);\n --glass: rgba(26,26,26,0.8);\n --glass-hover: rgba(38,38,38,0.9);\n --error: #ff7a72;\n --success: #74d49a;\n}\n\nhtml { min-height: 100%; }\nbody {\n min-height: 100dvh;\n background: var(--paper);\n color: var(--ink);\n font-family: 'Manrope', -apple-system, sans-serif;\n -webkit-font-smoothing: antialiased;\n}\n#root { min-height: 100dvh; }\n.display-font { font-family: 'Fraunces', Georgia, serif; letter-spacing: -0.04em; }\n} /* end @layer base */`,
|
|
152
|
-
'web/src/App.tsx': `import { initPro } from '@proappstore/sdk'\nimport { useProGate } from '@proappstore/sdk/hooks'\n\nconst app = initPro({ appId: '__APP_ID__' })\n\nexport default function App() {\n const { gate, user, signIn } = useProGate(app, { allowFree: true })\n\n if (gate === 'loading') {\n return (\n <div className="flex min-h-[100dvh] items-center justify-center">\n <p className="text-[var(--muted)]">Loading...</p>\n </div>\n )\n }\n\n if (gate === 'signed-out') {\n return (\n <div className="flex min-h-[100dvh] flex-col items-center justify-center gap-4 px-4">\n <h1 className="display-font text-3xl font-bold text-[var(--ink)]">__APP_NAME__</h1>\n <p className="text-[var(--muted)]">Sign in to get started.</p>\n <button onClick={signIn} className="rounded-2xl bg-[var(--accent)] px-6 py-2.5 text-sm font-semibold text-white">Sign in with GitHub</button>\n </div>\n )\n }\n\n return (\n <div className="mx-auto max-w-2xl px-4 py-8">\n <h1 className="display-font text-2xl font-bold text-[var(--ink)]">__APP_NAME__</h1>\n <p className="mt-2 text-[var(--muted)]">Welcome, {user?.login}! Edit web/src/App.tsx to start building.</p>\n </div>\n )\n}`,
|
|
153
|
-
// Pre-committed privacy template — served by CF Pages at
|
|
154
|
-
// <app>.proappstore.online/privacy.md. The Console's "Use privacy.md from
|
|
155
|
-
// my app" affordance points to that URL. Fill in {{APP_NAME}}/{{DATE}}/
|
|
156
|
-
// {{CONTACT}} (or just delete this file and point Console at the platform
|
|
157
|
-
// policy if your app doesn't add anything app-specific).
|
|
158
|
-
'web/public/privacy.md': `# Privacy Policy — __APP_NAME__\n\n_Last updated: {{DATE}}_\n\nThis is the privacy policy for **__APP_NAME__**, a Pro app on\n[ProAppStore](https://proappstore.online). It covers what _this app_ does\nwith your data. For platform-wide data handling (sign-in, billing, file\nstorage, usage analytics for creator payouts, account deletion) see the\n[platform privacy policy](https://proappstore.online/privacy).\n\n---\n\n## What __APP_NAME__ stores about you\n\n> _Fill in what your app keeps. Examples below — delete the ones that don't\n> apply, add app-specific ones._\n\n- The data you explicitly enter into the app. Stored in your private\n per-user KV / database / file storage. No one else has access except you.\n\n## What __APP_NAME__ does NOT store\n\n- No contacts scraping, no background location, no microphone access, no\n behavioral analytics, no advertising IDs.\n\n## Where data lives\n\nEverything you save in __APP_NAME__ is stored on Cloudflare infrastructure\n(D1, R2, KV) under your ProAppStore account. The app developer does not\nhave access to your personal data — only daily aggregate counts (active\nusers, session-minutes, API calls) used to size their payout share.\n\n## Third-party services\n\n> _List any third-party APIs your app calls on the user's behalf. Delete\n> this section if there are none._\n\n## Cookies\n\n__APP_NAME__ uses the same session cookie as the rest of ProAppStore for\nauthentication. No tracking, advertising, or analytics cookies.\n\n## Data deletion\n\nDelete your account from [dashboard.proappstore.online](https://dashboard.proappstore.online).\nThat removes all data __APP_NAME__ stored for you, alongside the\nplatform-level deletion described in the [platform privacy policy](https://proappstore.online/privacy#data-deletion).\n\n## Contact\n\n{{CONTACT}}\n`,
|
|
159
|
-
};
|
|
8
|
+
const TEXT_EXTENSIONS = new Set([
|
|
9
|
+
'.md', '.txt', '.json', '.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
|
|
10
|
+
'.html', '.htm', '.css', '.scss', '.yaml', '.yml', '.toml', '.svg',
|
|
11
|
+
]);
|
|
12
|
+
const SKIP_DIRS = new Set(['.git', 'node_modules', 'dist', '.cache']);
|
|
160
13
|
function toTitleCase(id) {
|
|
161
14
|
return id.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
|
|
162
15
|
}
|
|
163
16
|
export async function createApp(appId, opts = {}) {
|
|
164
|
-
// Validate app ID
|
|
165
17
|
if (!/^[a-z][a-z0-9-]*$/.test(appId) || appId.length > 58) {
|
|
166
18
|
process.stderr.write(`Invalid app ID "${appId}". Use lowercase letters, numbers, hyphens. Max 58 chars.\n`);
|
|
167
19
|
process.exit(1);
|
|
168
20
|
}
|
|
169
21
|
const targetDir = resolve(appId);
|
|
170
|
-
if (
|
|
22
|
+
if (await exists(targetDir)) {
|
|
171
23
|
process.stderr.write(`Directory "${appId}" already exists.\n`);
|
|
172
24
|
process.exit(1);
|
|
173
25
|
}
|
|
174
26
|
const appName = toTitleCase(appId);
|
|
175
27
|
process.stdout.write(`\n Creating ${appName}...\n\n`);
|
|
176
|
-
// Step 1:
|
|
177
|
-
process.stdout.write(` [1/
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
.replace(/__APP_NAME__/g, appName)
|
|
185
|
-
.replace(/__APP_DESCRIPTION__/g, `A pro app on ProAppStore.`);
|
|
186
|
-
writeFileSync(fullPath, processed);
|
|
187
|
-
}
|
|
188
|
-
// Binary placeholders that can't live in the inline string map.
|
|
189
|
-
// Without these the manifest references /icon-192.png and Android
|
|
190
|
-
// would either 404 or install the app as a launcher shortcut.
|
|
191
|
-
const publicDir = join(targetDir, 'web', 'public');
|
|
192
|
-
mkdirSync(publicDir, { recursive: true });
|
|
193
|
-
for (const iconName of ['icon-192.png', 'icon-512.png']) {
|
|
194
|
-
cpSync(join(TEMPLATES_DIR, iconName), join(publicDir, iconName));
|
|
195
|
-
}
|
|
196
|
-
// Step 2: Install
|
|
28
|
+
// Step 1: Clone template
|
|
29
|
+
process.stdout.write(` [1/4] Cloning template...\n`);
|
|
30
|
+
await run('git', ['clone', '--depth=1', `https://github.com/${TEMPLATE_REPO}.git`, targetDir]);
|
|
31
|
+
await rm(join(targetDir, '.git'), { recursive: true, force: true });
|
|
32
|
+
// Step 2: Replace APPNAME placeholders
|
|
33
|
+
process.stdout.write(` [2/4] Configuring for ${appId}...\n`);
|
|
34
|
+
const substitutionCount = await substituteAppName(targetDir, appId, appName);
|
|
35
|
+
// Step 3: Install
|
|
197
36
|
if (!opts.skipInstall) {
|
|
198
|
-
process.stdout.write(` [
|
|
37
|
+
process.stdout.write(` [3/4] Installing dependencies...\n`);
|
|
199
38
|
try {
|
|
200
|
-
|
|
39
|
+
await run('pnpm', ['install'], targetDir);
|
|
201
40
|
}
|
|
202
41
|
catch {
|
|
203
|
-
process.stdout.write(` [
|
|
42
|
+
process.stdout.write(` [3/4] pnpm install failed. Run it manually.\n`);
|
|
204
43
|
}
|
|
205
44
|
}
|
|
206
45
|
else {
|
|
207
|
-
process.stdout.write(` [
|
|
46
|
+
process.stdout.write(` [3/4] Skipping install (--skip-install)\n`);
|
|
208
47
|
}
|
|
209
|
-
// Step
|
|
48
|
+
// Step 4: Init git + provision
|
|
210
49
|
if (!opts.skipGit) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
cwd: targetDir,
|
|
215
|
-
stdio: 'pipe',
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
catch {
|
|
219
|
-
process.stdout.write(` [3/3] Git init failed. Run it manually.\n`);
|
|
220
|
-
}
|
|
50
|
+
await run('git', ['init', '-q', '-b', 'main'], targetDir);
|
|
51
|
+
await run('git', ['add', '-A'], targetDir);
|
|
52
|
+
await run('git', ['commit', '-q', '-m', 'Initial commit from pas create'], targetDir);
|
|
221
53
|
}
|
|
222
|
-
else {
|
|
223
|
-
process.stdout.write(` [3/3] Skipping git init (--skip-git)\n`);
|
|
224
|
-
}
|
|
225
|
-
// Step 4: Provision platform resources (D1 + Data Worker)
|
|
226
54
|
if (!opts.skipProvision) {
|
|
227
|
-
const token = opts.token
|
|
55
|
+
const token = resolveToken(opts.token);
|
|
228
56
|
if (token) {
|
|
229
57
|
process.stdout.write(` [4/4] Provisioning platform resources...\n`);
|
|
230
58
|
try {
|
|
@@ -235,6 +63,8 @@ export async function createApp(appId, opts = {}) {
|
|
|
235
63
|
appId,
|
|
236
64
|
name: appName,
|
|
237
65
|
description: `${appName} — pro app on ProAppStore.`,
|
|
66
|
+
skipCompliance: true,
|
|
67
|
+
skipPublish: true,
|
|
238
68
|
}),
|
|
239
69
|
});
|
|
240
70
|
const data = (await res.json());
|
|
@@ -242,7 +72,6 @@ export async function createApp(appId, opts = {}) {
|
|
|
242
72
|
const icon = step.status === 'ok' ? '+' : step.status === 'skip' ? '-' : '!';
|
|
243
73
|
process.stdout.write(` [${icon}] ${step.name}: ${step.detail}\n`);
|
|
244
74
|
}
|
|
245
|
-
// Write the Data Worker URL into the app's config
|
|
246
75
|
const dbStep = data.steps.find(s => s.name === 'create_d1' && s.status === 'ok');
|
|
247
76
|
if (dbStep) {
|
|
248
77
|
const configPath = join(targetDir, '.pas.json');
|
|
@@ -259,23 +88,69 @@ export async function createApp(appId, opts = {}) {
|
|
|
259
88
|
}
|
|
260
89
|
}
|
|
261
90
|
else {
|
|
262
|
-
process.stdout.write(` [4/4] Skipping provision (no auth token).
|
|
91
|
+
process.stdout.write(` [4/4] Skipping provision (no auth token). Run \`pas login\`, set PAS_SESSION_TOKEN, or use --token.\n`);
|
|
263
92
|
}
|
|
264
93
|
}
|
|
265
94
|
else {
|
|
266
95
|
process.stdout.write(` [4/4] Skipping provision (--skip-provision)\n`);
|
|
267
96
|
}
|
|
268
97
|
process.stdout.write(`
|
|
269
|
-
Done!
|
|
98
|
+
Done! Replaced APPNAME in ${substitutionCount} files.
|
|
270
99
|
|
|
271
100
|
Next steps:
|
|
272
101
|
cd ${appId}
|
|
273
102
|
pnpm dev
|
|
274
103
|
|
|
275
|
-
|
|
276
|
-
Console:
|
|
277
|
-
Dashboard: https://dashboard.proappstore.online
|
|
104
|
+
Docs: https://proappstore.online/docs
|
|
105
|
+
Console: https://console.proappstore.online
|
|
278
106
|
|
|
279
107
|
`);
|
|
280
108
|
}
|
|
109
|
+
async function substituteAppName(dir, appId, appName) {
|
|
110
|
+
let count = 0;
|
|
111
|
+
for await (const file of walk(dir)) {
|
|
112
|
+
if (!TEXT_EXTENSIONS.has(extname(file).toLowerCase()))
|
|
113
|
+
continue;
|
|
114
|
+
const content = await readFile(file, 'utf8');
|
|
115
|
+
if (!content.includes('APPNAME'))
|
|
116
|
+
continue;
|
|
117
|
+
await writeFile(file, content.split('APPNAME').join(appId));
|
|
118
|
+
count++;
|
|
119
|
+
}
|
|
120
|
+
return count;
|
|
121
|
+
}
|
|
122
|
+
async function* walk(dir) {
|
|
123
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
124
|
+
for (const entry of entries) {
|
|
125
|
+
if (entry.isDirectory()) {
|
|
126
|
+
if (SKIP_DIRS.has(entry.name))
|
|
127
|
+
continue;
|
|
128
|
+
yield* walk(join(dir, entry.name));
|
|
129
|
+
}
|
|
130
|
+
else if (entry.isFile()) {
|
|
131
|
+
yield join(dir, entry.name);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async function exists(path) {
|
|
136
|
+
try {
|
|
137
|
+
await access(path);
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function run(cmd, args, cwd) {
|
|
145
|
+
return new Promise((resolveFn, rejectFn) => {
|
|
146
|
+
const child = spawn(cmd, args, { stdio: 'inherit', cwd });
|
|
147
|
+
child.on('exit', (code) => {
|
|
148
|
+
if (code === 0)
|
|
149
|
+
resolveFn();
|
|
150
|
+
else
|
|
151
|
+
rejectFn(new Error(`${cmd} exited with code ${code}`));
|
|
152
|
+
});
|
|
153
|
+
child.on('error', rejectFn);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
281
156
|
//# sourceMappingURL=create.js.map
|
package/dist/create.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.js","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"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"}
|
package/dist/domain.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain.d.ts","sourceRoot":"","sources":["../src/domain.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0NpC,eAAO,MAAM,aAAa,SAA8E,CAAC"}
|
package/dist/domain.js
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { resolveToken } from './lib/config.js';
|
|
5
|
+
const PAS_API = 'https://api.proappstore.online';
|
|
6
|
+
const isTTY = Boolean(process.stdout.isTTY) && process.env.NO_COLOR !== '1';
|
|
7
|
+
const ansi = (open) => (s) => (isTTY ? `\x1b[${open}m${s}\x1b[39m` : s);
|
|
8
|
+
const green = ansi('32');
|
|
9
|
+
const yellow = ansi('33');
|
|
10
|
+
const red = ansi('31');
|
|
11
|
+
const dim = (s) => (isTTY ? `\x1b[2m${s}\x1b[22m` : s);
|
|
12
|
+
const bold = (s) => (isTTY ? `\x1b[1m${s}\x1b[22m` : s);
|
|
13
|
+
function readJsonIfExists(path) {
|
|
14
|
+
if (!existsSync(path))
|
|
15
|
+
return null;
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(readFileSync(path, 'utf8'));
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function getAppId() {
|
|
24
|
+
const pkg = readJsonIfExists(resolve(process.cwd(), 'package.json'));
|
|
25
|
+
if (!pkg?.name) {
|
|
26
|
+
process.stderr.write('pas domain: no package.json with a `name` field in the current directory.\n' +
|
|
27
|
+
'Run this from the root of a pas-scaffolded app.\n');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
if (!/^[a-z][a-z0-9-]*$/.test(pkg.name) || pkg.name.length > 58) {
|
|
31
|
+
process.stderr.write(`pas domain: package.json name "${pkg.name}" is not a valid app id.\n`);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
return pkg.name;
|
|
35
|
+
}
|
|
36
|
+
function getToken(opts) {
|
|
37
|
+
const token = resolveToken(opts.token);
|
|
38
|
+
if (!token) {
|
|
39
|
+
process.stderr.write('pas domain: no auth token. Run `pas login` first, or use --token.\n');
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
return token;
|
|
43
|
+
}
|
|
44
|
+
async function api(method, path, token, body) {
|
|
45
|
+
const init = {
|
|
46
|
+
method,
|
|
47
|
+
headers: {
|
|
48
|
+
Authorization: `Bearer ${token}`,
|
|
49
|
+
...(body ? { 'Content-Type': 'application/json' } : {}),
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
if (body !== undefined)
|
|
53
|
+
init.body = JSON.stringify(body);
|
|
54
|
+
const res = await fetch(`${PAS_API}${path}`, init);
|
|
55
|
+
let data = null;
|
|
56
|
+
try {
|
|
57
|
+
data = await res.json();
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
data = { error: await res.text().catch(() => '') };
|
|
61
|
+
}
|
|
62
|
+
return { status: res.status, data };
|
|
63
|
+
}
|
|
64
|
+
function statusBadge(status) {
|
|
65
|
+
if (status === 'active')
|
|
66
|
+
return green('● active');
|
|
67
|
+
if (status === 'pending')
|
|
68
|
+
return yellow('● pending DNS');
|
|
69
|
+
return red('● failed');
|
|
70
|
+
}
|
|
71
|
+
function renderDomain(d, appId) {
|
|
72
|
+
process.stdout.write(`\n ${bold(d.domain)} ${statusBadge(d.status)}\n`);
|
|
73
|
+
if (d.cfStatus)
|
|
74
|
+
process.stdout.write(` ${dim(`CF: ${d.cfStatus}`)}\n`);
|
|
75
|
+
if (d.status === 'active') {
|
|
76
|
+
process.stdout.write(` ${dim(`verified ${new Date(d.verifiedAt || d.addedAt).toLocaleString()}`)}\n`);
|
|
77
|
+
process.stdout.write(` Live at: https://${d.domain}\n`);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
// Status is cached at the time it was last attached or verified. PAS does
|
|
81
|
+
// no background polling — the owner triggers a fresh check by running
|
|
82
|
+
// `pas domain verify <domain>`. Make that contract explicit here so the
|
|
83
|
+
// owner isn't surprised when nothing changes between `pas domain list`
|
|
84
|
+
// invocations.
|
|
85
|
+
process.stdout.write(` ${dim(`status as of ${new Date(d.addedAt).toLocaleString()} — run \`pas domain verify ${d.domain}\` to refresh`)}\n`);
|
|
86
|
+
const vd = d.verificationData || {};
|
|
87
|
+
const valid = d.validationData || {};
|
|
88
|
+
process.stdout.write(`\n ${bold('Add this DNS record at your registrar:')}\n\n`);
|
|
89
|
+
process.stdout.write(` Type: CNAME\n`);
|
|
90
|
+
process.stdout.write(` Name: ${d.domain}\n`);
|
|
91
|
+
process.stdout.write(` Value: ${bold(`proappstore-${appId}.pages.dev`)}\n`);
|
|
92
|
+
process.stdout.write(`\n ${dim('Apex domains (e.g. example.com without a subdomain) can\'t use a raw CNAME')}\n` +
|
|
93
|
+
` ${dim('per RFC. Use ALIAS/ANAME if your registrar supports it, or set A/AAAA')}\n` +
|
|
94
|
+
` ${dim('records pointing to Cloudflare anycast IPs (CF will tell you which).')}\n`);
|
|
95
|
+
// CF only emits TXT validation when HTTP-01 isn't possible — usually
|
|
96
|
+
// because DNS isn't yet pointing correctly. When method is 'txt', the
|
|
97
|
+
// owner needs this record too.
|
|
98
|
+
if (valid.method === 'txt' && valid.txt_name && valid.txt_value) {
|
|
99
|
+
process.stdout.write(`\n ${dim('Plus this TXT record for SSL validation:')}\n`);
|
|
100
|
+
process.stdout.write(` Type: TXT\n`);
|
|
101
|
+
process.stdout.write(` Name: ${valid.txt_name}\n`);
|
|
102
|
+
process.stdout.write(` Value: ${valid.txt_value}\n`);
|
|
103
|
+
}
|
|
104
|
+
if (vd.error_message) {
|
|
105
|
+
process.stdout.write(`\n ${red('Last verification error:')} ${vd.error_message}\n`);
|
|
106
|
+
}
|
|
107
|
+
else if (valid.error_message) {
|
|
108
|
+
process.stdout.write(`\n ${red('Last validation error:')} ${valid.error_message}\n`);
|
|
109
|
+
}
|
|
110
|
+
process.stdout.write(`\n After adding the records, run: ${bold(`pas domain verify ${d.domain}`)}\n`);
|
|
111
|
+
}
|
|
112
|
+
async function addDomain(domain, opts) {
|
|
113
|
+
const appId = getAppId();
|
|
114
|
+
const token = getToken(opts);
|
|
115
|
+
process.stdout.write(`\n Attaching ${bold(domain)} to ${appId}...\n`);
|
|
116
|
+
const { status, data } = await api('POST', `/v1/apps/${appId}/domains`, token, { domain });
|
|
117
|
+
if (status !== 201) {
|
|
118
|
+
process.stderr.write(`\n ${red('Failed')} (${status}): ${data?.error || JSON.stringify(data)}\n\n`);
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
renderDomain(data.domain, appId);
|
|
122
|
+
process.stdout.write('\n');
|
|
123
|
+
}
|
|
124
|
+
async function listCmd(opts) {
|
|
125
|
+
const appId = getAppId();
|
|
126
|
+
const token = getToken(opts);
|
|
127
|
+
const { status, data } = await api('GET', `/v1/apps/${appId}/domains`, token);
|
|
128
|
+
if (status !== 200) {
|
|
129
|
+
process.stderr.write(` pas domain list failed (${status}): ${data?.error || JSON.stringify(data)}\n`);
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
const domains = data.domains || [];
|
|
133
|
+
if (domains.length === 0) {
|
|
134
|
+
process.stdout.write(`\n No custom domains attached to ${appId}.\n`);
|
|
135
|
+
process.stdout.write(` Add one with: ${bold('pas domain add example.com')}\n\n`);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
for (const d of domains)
|
|
139
|
+
renderDomain(d, appId);
|
|
140
|
+
process.stdout.write('\n');
|
|
141
|
+
}
|
|
142
|
+
async function verifyCmd(domain, opts) {
|
|
143
|
+
const appId = getAppId();
|
|
144
|
+
const token = getToken(opts);
|
|
145
|
+
process.stdout.write(`\n Re-checking ${bold(domain)}...\n`);
|
|
146
|
+
const { status, data } = await api('POST', `/v1/apps/${appId}/domains/${encodeURIComponent(domain)}/verify`, token);
|
|
147
|
+
if (status !== 200) {
|
|
148
|
+
process.stderr.write(` ${red('Verify failed')} (${status}): ${data?.error || JSON.stringify(data)}\n`);
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
renderDomain(data.domain, appId);
|
|
152
|
+
process.stdout.write('\n');
|
|
153
|
+
}
|
|
154
|
+
async function removeCmd(domain, opts) {
|
|
155
|
+
const appId = getAppId();
|
|
156
|
+
const token = getToken(opts);
|
|
157
|
+
if (!opts.yes) {
|
|
158
|
+
process.stderr.write(`\n Detach ${bold(domain)} from ${appId}? This will stop serving the app at this domain.\n` +
|
|
159
|
+
` Re-run with --yes to confirm.\n\n`);
|
|
160
|
+
process.exit(2);
|
|
161
|
+
}
|
|
162
|
+
const { status, data } = await api('DELETE', `/v1/apps/${appId}/domains/${encodeURIComponent(domain)}`, token);
|
|
163
|
+
if (status !== 200) {
|
|
164
|
+
process.stderr.write(` ${red('Remove failed')} (${status}): ${data?.error || JSON.stringify(data)}\n`);
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
process.stdout.write(`\n ${green('Detached')} ${domain}.\n\n`);
|
|
168
|
+
}
|
|
169
|
+
export const domainCommand = new Command('domain').description('Manage BYO custom domains for this app');
|
|
170
|
+
domainCommand
|
|
171
|
+
.command('add <domain>')
|
|
172
|
+
.description('Attach a custom domain (apex or subdomain) to the current app')
|
|
173
|
+
.option('--token <token>', 'Session token (or set PAS_SESSION_TOKEN)')
|
|
174
|
+
.action(addDomain);
|
|
175
|
+
domainCommand
|
|
176
|
+
.command('list')
|
|
177
|
+
.alias('ls')
|
|
178
|
+
.description('List custom domains attached to the current app + their verification state')
|
|
179
|
+
.option('--token <token>', 'Session token (or set PAS_SESSION_TOKEN)')
|
|
180
|
+
.action(listCmd);
|
|
181
|
+
domainCommand
|
|
182
|
+
.command('verify <domain>')
|
|
183
|
+
.description('Ask Cloudflare to re-check DNS / cert for a pending domain')
|
|
184
|
+
.option('--token <token>', 'Session token (or set PAS_SESSION_TOKEN)')
|
|
185
|
+
.action(verifyCmd);
|
|
186
|
+
domainCommand
|
|
187
|
+
.command('remove <domain>')
|
|
188
|
+
.alias('rm')
|
|
189
|
+
.description('Detach a custom domain from the current app')
|
|
190
|
+
.option('--token <token>', 'Session token (or set PAS_SESSION_TOKEN)')
|
|
191
|
+
.option('--yes', 'Skip the confirmation prompt')
|
|
192
|
+
.action(removeCmd);
|
|
193
|
+
//# sourceMappingURL=domain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain.js","sourceRoot":"","sources":["../src/domain.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import { checkCommand } from './check.js';
|
|
4
4
|
import { createApp } from './create.js';
|
|
5
|
+
import { domainCommand } from './domain.js';
|
|
6
|
+
import { loginCommand } from './login.js';
|
|
5
7
|
import { publishApp } from './publish.js';
|
|
6
8
|
const program = new Command();
|
|
7
9
|
program
|
|
@@ -14,18 +16,11 @@ program
|
|
|
14
16
|
.option('--skip-install', 'Skip pnpm install')
|
|
15
17
|
.option('--skip-git', 'Skip git init')
|
|
16
18
|
.option('--skip-provision', 'Skip D1 + platform provisioning')
|
|
17
|
-
.option('--token <token>', '
|
|
19
|
+
.option('--token <token>', 'Session token (or set PAS_SESSION_TOKEN env var)')
|
|
18
20
|
.action(async (appId, opts) => {
|
|
19
21
|
await createApp(appId, opts);
|
|
20
22
|
});
|
|
21
|
-
program
|
|
22
|
-
.command('login')
|
|
23
|
-
.description('Sign in with GitHub (shared identity with `fas`).')
|
|
24
|
-
.action(() => {
|
|
25
|
-
process.stdout.write('pas login is not yet implemented.\n' +
|
|
26
|
-
'For now: run `fas login` (from @freeappstore/cli) — pro shares the same identity.\n');
|
|
27
|
-
process.exit(2);
|
|
28
|
-
});
|
|
23
|
+
program.addCommand(loginCommand);
|
|
29
24
|
program
|
|
30
25
|
.command('publish')
|
|
31
26
|
.description('Publish the current repo to ProAppStore: GitHub repo, CF Pages, DNS, D1 database, registry entry.')
|
|
@@ -35,11 +30,12 @@ program
|
|
|
35
30
|
.option('--icon <icon>', 'Icon HTML entity, e.g. "📅"')
|
|
36
31
|
.option('--icon-bg <color>', 'Icon background hex color')
|
|
37
32
|
.option('--pro-features <list>', 'Comma-separated list of features the pro subscription unlocks')
|
|
38
|
-
.option('--token <token>', '
|
|
33
|
+
.option('--token <token>', 'Session token (or set PAS_SESSION_TOKEN env var)')
|
|
39
34
|
.action(async (opts) => {
|
|
40
35
|
await publishApp(opts);
|
|
41
36
|
});
|
|
42
37
|
program.addCommand(checkCommand);
|
|
38
|
+
program.addCommand(domainCommand);
|
|
43
39
|
program.parseAsync().catch((err) => {
|
|
44
40
|
const msg = err instanceof Error ? err.message : String(err);
|
|
45
41
|
process.stderr.write(`pas: ${msg}\n`);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,KAAK,CAAC;KACX,WAAW,CAAC,0DAA0D,CAAC;KACvE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,iBAAiB,CAAC;KAC1B,WAAW,CAAC,4FAA4F,CAAC;KACzG,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC;KAC7C,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC;KACrC,MAAM,CAAC,kBAAkB,EAAE,iCAAiC,CAAC;KAC7D,MAAM,CAAC,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,KAAK,CAAC;KACX,WAAW,CAAC,0DAA0D,CAAC;KACvE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,iBAAiB,CAAC;KAC1B,WAAW,CAAC,4FAA4F,CAAC;KACzG,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC;KAC7C,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC;KACrC,MAAM,CAAC,kBAAkB,EAAE,iCAAiC,CAAC;KAC7D,MAAM,CAAC,iBAAiB,EAAE,kDAAkD,CAAC;KAC7E,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,IAA2F,EAAE,EAAE;IAC3H,MAAM,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AAEjC,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,mGAAmG,CAAC;KAChH,MAAM,CAAC,eAAe,EAAE,4DAA4D,CAAC;KACrF,MAAM,CAAC,uBAAuB,EAAE,iDAAiD,CAAC;KAClF,MAAM,CAAC,6BAA6B,EAAE,8CAA8C,CAAC;KACrF,MAAM,CAAC,eAAe,EAAE,oCAAoC,CAAC;KAC7D,MAAM,CAAC,mBAAmB,EAAE,2BAA2B,CAAC;KACxD,MAAM,CAAC,uBAAuB,EAAE,+DAA+D,CAAC;KAChG,MAAM,CAAC,iBAAiB,EAAE,kDAAkD,CAAC;KAC7E,MAAM,CAAC,KAAK,EAAE,IAAsI,EAAE,EAAE;IACvJ,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAElC,OAAO,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC1C,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface CliConfig {
|
|
2
|
+
apiBase: string;
|
|
3
|
+
authApiBase: string;
|
|
4
|
+
github?: {
|
|
5
|
+
accessToken: string;
|
|
6
|
+
login: string;
|
|
7
|
+
obtainedAt: number;
|
|
8
|
+
};
|
|
9
|
+
session?: {
|
|
10
|
+
token: string;
|
|
11
|
+
obtainedAt: number;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export declare function readConfig(): Promise<CliConfig>;
|
|
15
|
+
export declare function writeConfig(config: CliConfig): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Get a session token from (in priority order):
|
|
18
|
+
* 1. --token CLI flag
|
|
19
|
+
* 2. PAS_SESSION_TOKEN env var
|
|
20
|
+
* 3. ~/.proappstore/config.json session
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveToken(cliToken?: string): string | null;
|
|
23
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE;QACP,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,OAAO,CAAC,EAAE;QACR,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAWD,wBAAsB,UAAU,IAAI,OAAO,CAAC,SAAS,CAAC,CAarD;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAIlE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAS7D"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
const CONFIG_DIR = join(homedir(), '.proappstore');
|
|
6
|
+
const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
|
|
7
|
+
const DEFAULT_CONFIG = {
|
|
8
|
+
apiBase: process.env.PAS_API_BASE ?? 'https://api.proappstore.online',
|
|
9
|
+
authApiBase: process.env.PAS_AUTH_API_BASE ?? 'https://api.freeappstore.online',
|
|
10
|
+
};
|
|
11
|
+
function normalizeApiBase(s) {
|
|
12
|
+
return s.replace(/\/+$/, '');
|
|
13
|
+
}
|
|
14
|
+
export async function readConfig() {
|
|
15
|
+
try {
|
|
16
|
+
const raw = await readFile(CONFIG_FILE, 'utf8');
|
|
17
|
+
const parsed = JSON.parse(raw);
|
|
18
|
+
const merged = { ...DEFAULT_CONFIG, ...parsed };
|
|
19
|
+
return {
|
|
20
|
+
...merged,
|
|
21
|
+
apiBase: normalizeApiBase(merged.apiBase),
|
|
22
|
+
authApiBase: normalizeApiBase(merged.authApiBase),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return { ...DEFAULT_CONFIG };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export async function writeConfig(config) {
|
|
30
|
+
await mkdir(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
31
|
+
await writeFile(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
32
|
+
await chmod(CONFIG_FILE, 0o600);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get a session token from (in priority order):
|
|
36
|
+
* 1. --token CLI flag
|
|
37
|
+
* 2. PAS_SESSION_TOKEN env var
|
|
38
|
+
* 3. ~/.proappstore/config.json session
|
|
39
|
+
*/
|
|
40
|
+
export function resolveToken(cliToken) {
|
|
41
|
+
if (cliToken)
|
|
42
|
+
return cliToken;
|
|
43
|
+
if (process.env.PAS_SESSION_TOKEN)
|
|
44
|
+
return process.env.PAS_SESSION_TOKEN;
|
|
45
|
+
try {
|
|
46
|
+
const raw = readFileSync(CONFIG_FILE, 'utf8');
|
|
47
|
+
const config = JSON.parse(raw);
|
|
48
|
+
if (config.session?.token)
|
|
49
|
+
return config.session.token;
|
|
50
|
+
}
|
|
51
|
+
catch { }
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC;AACnD,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAgBpD,MAAM,cAAc,GAAc;IAChC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,gCAAgC;IACrE,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,iCAAiC;CAChF,CAAC;AAEF,SAAS,gBAAgB,CAAC,CAAS;IACjC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAuB,CAAC;QACrD,MAAM,MAAM,GAAG,EAAE,GAAG,cAAc,EAAE,GAAG,MAAM,EAAE,CAAC;QAChD,OAAO;YACL,GAAG,MAAM;YACT,OAAO,EAAE,gBAAgB,CAAC,MAAM,CAAC,OAAO,CAAC;YACzC,WAAW,EAAE,gBAAgB,CAAC,MAAM,CAAC,WAAW,CAAC;SAClD,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC/B,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAiB;IACjD,MAAM,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1D,MAAM,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/E,MAAM,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;AAClC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,QAAiB;IAC5C,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACxE,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAc,CAAC;QAC5C,IAAI,MAAM,CAAC,OAAO,EAAE,KAAK;YAAE,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IACV,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface DeviceFlowStart {
|
|
2
|
+
userCode: string;
|
|
3
|
+
verificationUri: string;
|
|
4
|
+
expiresAt: number;
|
|
5
|
+
poll: () => Promise<{
|
|
6
|
+
accessToken: string;
|
|
7
|
+
login: string;
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
export declare function startDeviceFlow(clientId: string): Promise<DeviceFlowStart>;
|
|
11
|
+
//# sourceMappingURL=github.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/lib/github.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC7D;AAED,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CA6ChF"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// GitHub Device Authorization Grant flow.
|
|
2
|
+
// Spec: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps#device-flow
|
|
3
|
+
export async function startDeviceFlow(clientId) {
|
|
4
|
+
const codeRes = await fetch('https://github.com/login/device/code', {
|
|
5
|
+
method: 'POST',
|
|
6
|
+
headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
|
|
7
|
+
body: JSON.stringify({ client_id: clientId, scope: 'read:user' }),
|
|
8
|
+
});
|
|
9
|
+
if (!codeRes.ok) {
|
|
10
|
+
throw new Error(`GitHub device-code request failed: ${codeRes.status}`);
|
|
11
|
+
}
|
|
12
|
+
const code = (await codeRes.json());
|
|
13
|
+
let interval = code.interval;
|
|
14
|
+
const expiresAt = Date.now() + code.expires_in * 1000;
|
|
15
|
+
return {
|
|
16
|
+
userCode: code.user_code,
|
|
17
|
+
verificationUri: code.verification_uri,
|
|
18
|
+
expiresAt,
|
|
19
|
+
poll: async () => {
|
|
20
|
+
while (Date.now() < expiresAt) {
|
|
21
|
+
await sleep(interval * 1000);
|
|
22
|
+
const tokenRes = await fetch('https://github.com/login/oauth/access_token', {
|
|
23
|
+
method: 'POST',
|
|
24
|
+
headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
|
|
25
|
+
body: JSON.stringify({
|
|
26
|
+
client_id: clientId,
|
|
27
|
+
device_code: code.device_code,
|
|
28
|
+
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
|
|
29
|
+
}),
|
|
30
|
+
});
|
|
31
|
+
const token = (await tokenRes.json());
|
|
32
|
+
if (token.access_token) {
|
|
33
|
+
const login = await fetchLogin(token.access_token);
|
|
34
|
+
return { accessToken: token.access_token, login };
|
|
35
|
+
}
|
|
36
|
+
if (token.error === 'slow_down') {
|
|
37
|
+
interval = token.interval ?? interval + 5;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (token.error === 'authorization_pending')
|
|
41
|
+
continue;
|
|
42
|
+
throw new Error(`GitHub authorization failed: ${token.error ?? 'unknown'}`);
|
|
43
|
+
}
|
|
44
|
+
throw new Error('Device code expired before authorization completed.');
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async function fetchLogin(token) {
|
|
49
|
+
const res = await fetch('https://api.github.com/user', {
|
|
50
|
+
headers: { Authorization: `Bearer ${token}`, Accept: 'application/vnd.github+json' },
|
|
51
|
+
});
|
|
52
|
+
if (!res.ok)
|
|
53
|
+
throw new Error(`Failed to fetch GitHub user: ${res.status}`);
|
|
54
|
+
const user = (await res.json());
|
|
55
|
+
return user.login;
|
|
56
|
+
}
|
|
57
|
+
function sleep(ms) {
|
|
58
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=github.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/lib/github.ts"],"names":[],"mappings":"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"}
|
package/dist/login.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../src/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAsB,QAAQ,IAAI,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CA0B3D;AAED,eAAO,MAAM,YAAY,SAIrB,CAAC"}
|
package/dist/login.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { readConfig, writeConfig } from './lib/config.js';
|
|
3
|
+
import { startDeviceFlow } from './lib/github.js';
|
|
4
|
+
const DEFAULT_CLIENT_ID = process.env.PAS_GITHUB_CLIENT_ID ?? 'Ov23liuUpYPXc1ikEFm2';
|
|
5
|
+
export async function runLogin() {
|
|
6
|
+
const flow = await startDeviceFlow(DEFAULT_CLIENT_ID);
|
|
7
|
+
process.stdout.write(`\nOpen ${flow.verificationUri} and enter code: ${flow.userCode}\n\n`);
|
|
8
|
+
process.stdout.write('Waiting for authorization...\n');
|
|
9
|
+
const { accessToken, login } = await flow.poll();
|
|
10
|
+
const config = await readConfig();
|
|
11
|
+
const exchangeUrl = `${config.authApiBase}/v1/auth/exchange`;
|
|
12
|
+
const exchangeRes = await fetch(exchangeUrl, {
|
|
13
|
+
method: 'POST',
|
|
14
|
+
headers: { 'Content-Type': 'application/json' },
|
|
15
|
+
body: JSON.stringify({ githubToken: accessToken }),
|
|
16
|
+
});
|
|
17
|
+
if (!exchangeRes.ok) {
|
|
18
|
+
throw new Error(`Auth exchange failed (${exchangeRes.status}): ${await exchangeRes.text()}`);
|
|
19
|
+
}
|
|
20
|
+
const { sessionToken } = (await exchangeRes.json());
|
|
21
|
+
await writeConfig({
|
|
22
|
+
...config,
|
|
23
|
+
github: { accessToken, login, obtainedAt: Date.now() },
|
|
24
|
+
session: { token: sessionToken, obtainedAt: Date.now() },
|
|
25
|
+
});
|
|
26
|
+
process.stdout.write(`\n✓ Signed in as @${login}\n`);
|
|
27
|
+
return { login };
|
|
28
|
+
}
|
|
29
|
+
export const loginCommand = new Command('login')
|
|
30
|
+
.description('Sign in with GitHub.')
|
|
31
|
+
.action(async () => {
|
|
32
|
+
await runLogin();
|
|
33
|
+
});
|
|
34
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../src/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,sBAAsB,CAAC;AAErF,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,iBAAiB,CAAC,CAAC;IACtD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,eAAe,oBAAoB,IAAI,CAAC,QAAQ,MAAM,CAAC,CAAC;IAC5F,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;IAEvD,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;IACjD,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAElC,MAAM,WAAW,GAAG,GAAG,MAAM,CAAC,WAAW,mBAAmB,CAAC;IAC7D,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,WAAW,EAAE;QAC3C,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;KACnD,CAAC,CAAC;IACH,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,yBAAyB,WAAW,CAAC,MAAM,MAAM,MAAM,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC/F,CAAC;IACD,MAAM,EAAE,YAAY,EAAE,GAAG,CAAC,MAAM,WAAW,CAAC,IAAI,EAAE,CAA6B,CAAC;IAEhF,MAAM,WAAW,CAAC;QAChB,GAAG,MAAM;QACT,MAAM,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE;QACtD,OAAO,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE;KACzD,CAAC,CAAC;IACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qBAAqB,KAAK,IAAI,CAAC,CAAC;IACrD,OAAO,EAAE,KAAK,EAAE,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KAC7C,WAAW,CAAC,sBAAsB,CAAC;KACnC,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,QAAQ,EAAE,CAAC;AACnB,CAAC,CAAC,CAAC"}
|
package/dist/publish.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../src/publish.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../src/publish.ts"],"names":[],"mappings":"AAIA,UAAU,cAAc;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAoDD;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAgGpE"}
|
package/dist/publish.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFileSync, existsSync } from 'node:fs';
|
|
2
|
-
import { resolve } from 'node:path';
|
|
2
|
+
import { resolve, join } from 'node:path';
|
|
3
|
+
import { resolveToken } from './lib/config.js';
|
|
3
4
|
const PAS_API = 'https://api.proappstore.online';
|
|
4
5
|
function readJsonIfExists(path) {
|
|
5
6
|
if (!existsSync(path))
|
|
@@ -17,6 +18,31 @@ function toTitleCase(id) {
|
|
|
17
18
|
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
18
19
|
.join(' ');
|
|
19
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Map a failing step's detail to an actionable next-step hint. Returns
|
|
23
|
+
* null when the failure is generic ('Fix and retry' is enough). Hints are
|
|
24
|
+
* shown indented under the failing step line.
|
|
25
|
+
*/
|
|
26
|
+
function hintForStep(name, detail) {
|
|
27
|
+
const d = detail.toLowerCase();
|
|
28
|
+
if (d.includes('limit of projects') || d.includes('reached the limit')) {
|
|
29
|
+
return ('CF Pages cap: this account is at the 100-project ceiling.\n' +
|
|
30
|
+
'→ Free a slot: npx wrangler pages project list\n' +
|
|
31
|
+
' npx wrangler pages project delete <name>\n' +
|
|
32
|
+
'→ Long-term: PAS apps are scheduled to migrate to Path B\n' +
|
|
33
|
+
' (single host Worker + R2) which removes the cap.');
|
|
34
|
+
}
|
|
35
|
+
if (name.toLowerCase().includes('analytics') && d.includes('auth')) {
|
|
36
|
+
return ('CF Web Analytics token lacks the analytics scope.\n' +
|
|
37
|
+
'→ Non-blocking — your app still ships; the analytics dashboard\n' +
|
|
38
|
+
' will be empty until the platform token is widened.');
|
|
39
|
+
}
|
|
40
|
+
if (d.includes('repo') && d.includes('already exists')) {
|
|
41
|
+
return ('Repo already exists on GitHub. `pas publish` is idempotent —\n' +
|
|
42
|
+
'this step is harmless; the remaining steps still ran.');
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
20
46
|
/**
|
|
21
47
|
* Publish an existing repo to ProAppStore.
|
|
22
48
|
*
|
|
@@ -39,10 +65,9 @@ export async function publishApp(opts) {
|
|
|
39
65
|
process.stderr.write(`pas publish: package.json name "${appId}" is not a valid app id (lowercase, hyphens, max 58 chars).\n`);
|
|
40
66
|
process.exit(1);
|
|
41
67
|
}
|
|
42
|
-
const token = opts.token
|
|
68
|
+
const token = resolveToken(opts.token);
|
|
43
69
|
if (!token) {
|
|
44
|
-
process.stderr.write('pas publish: no auth token.
|
|
45
|
-
'Tokens come from `fas login` (shared identity with the free side).\n');
|
|
70
|
+
process.stderr.write('pas publish: no auth token. Run `pas login` first, or use --token.\n');
|
|
46
71
|
process.exit(1);
|
|
47
72
|
}
|
|
48
73
|
const name = opts.name || toTitleCase(appId);
|
|
@@ -85,6 +110,14 @@ export async function publishApp(opts) {
|
|
|
85
110
|
for (const step of data.steps) {
|
|
86
111
|
const icon = step.status === 'ok' ? '+' : step.status === 'skip' ? '-' : '!';
|
|
87
112
|
process.stdout.write(` [${icon}] ${step.name}: ${step.detail}\n`);
|
|
113
|
+
if (step.status === 'fail') {
|
|
114
|
+
const hint = hintForStep(step.name, step.detail);
|
|
115
|
+
if (hint) {
|
|
116
|
+
for (const line of hint.split('\n')) {
|
|
117
|
+
process.stdout.write(` ${line}\n`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
88
121
|
}
|
|
89
122
|
if (data.success) {
|
|
90
123
|
process.stdout.write(`\n Published. Push your code to deploy:\n`);
|
package/dist/publish.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../src/publish.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../src/publish.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAY/C,MAAM,OAAO,GAAG,gCAAgC,CAAC;AAEjD,SAAS,gBAAgB,CAAc,IAAY;IACjD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAM,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,EAAU;IAC7B,OAAO,EAAE;SACN,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SAClD,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,SAAS,WAAW,CAAC,IAAY,EAAE,MAAc;IAC/C,MAAM,CAAC,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IAC/B,IAAI,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACvE,OAAO,CACL,6DAA6D;YAC7D,mDAAmD;YACnD,4DAA4D;YAC5D,+DAA+D;YAC/D,kEAAkE,CACnE,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACnE,OAAO,CACL,qDAAqD;YACrD,kEAAkE;YAClE,sDAAsD,CACvD,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACvD,OAAO,CACL,gEAAgE;YAChE,uDAAuD,CACxD,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAoB;IACnD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,GAAG,GAAG,gBAAgB,CAA0C,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC;IACpG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,8EAA8E;YAC5E,8EAA8E,CACjF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC;IACvB,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QAC1D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAmC,KAAK,+DAA+D,CAAC,CAAC;QAC9H,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,sEAAsE,CACvE,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,GAAG,CAAC,WAAW,IAAI,GAAG,IAAI,4BAA4B,CAAC;IAC/F,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW;QAClC,CAAC,CAAC,IAAI,CAAC,WAAW;aACb,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,MAAM,CAAC,OAAO,CAAC;QACpB,CAAC,CAAC,SAAS,CAAC;IAEd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kBAAkB,IAAI,KAAK,KAAK,UAAU,CAAC,CAAC;IAEjE,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,eAAe,EAAE;YAC3C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YACjF,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK;gBACL,IAAI;gBACJ,WAAW;gBACX,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,WAAW;aACZ,CAAC;SACH,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,yEAAyE;IACzE,sEAAsE;IACtE,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC7C,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,GAAG,CAAC,MAAM,MAAM,IAAI,IAAI,CAAC,CAAC;QACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAM7B,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QAC7E,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;QACnE,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YACjD,IAAI,IAAI,EAAE,CAAC;gBACT,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;oBACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC;gBAC1C,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QACnE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACrD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,KAAK,uBAAuB,CAAC,CAAC;QACjF,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;QACjF,IAAI,IAAI,CAAC,aAAa;YAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,IAAI,CAAC,aAAa,IAAI,CAAC,CAAC;QAC3F,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sFAAsF,CAAC,CAAC;QAC7G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|