shiply-cli 0.21.0 → 0.23.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/bundle.js +4 -2
- package/dist/functions.js +38 -6
- package/dist/index.js +17 -1
- package/dist/publish.js +1 -0
- package/package.json +42 -42
- package/skill/SKILL.md +1 -1
package/dist/bundle.js
CHANGED
|
@@ -18,8 +18,10 @@ const WORKER_EXTERNALS = [
|
|
|
18
18
|
...builtinModules.flatMap((m) => [m, `${m}/*`]),
|
|
19
19
|
];
|
|
20
20
|
/** esbuild-bundle a worker entry into one self-contained ESM module, optionally
|
|
21
|
-
* wrapping it (named-fetch → default, and/or asset-first) via a synthetic entry.
|
|
22
|
-
|
|
21
|
+
* wrapping it (named-fetch → default, and/or asset-first) via a synthetic entry.
|
|
22
|
+
* Also used by `function deploy` to compile worker.ts → JS and inline npm deps
|
|
23
|
+
* (e.g. `@neondatabase/serverless`) before upload. */
|
|
24
|
+
export async function bundleWorker(entryAbs, opts = {}) {
|
|
23
25
|
const common = {
|
|
24
26
|
bundle: true,
|
|
25
27
|
format: 'esm',
|
package/dist/functions.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* `parseArgs` in index.ts doesn't have to know about each one. */
|
|
6
6
|
import { readFile } from 'node:fs/promises';
|
|
7
7
|
import { join } from 'node:path';
|
|
8
|
+
import { bundleWorker } from './bundle.js';
|
|
8
9
|
import { loadApiKey } from './config.js';
|
|
9
10
|
import { api, resolveBase } from './publish.js';
|
|
10
11
|
const headers = (apiKey) => ({
|
|
@@ -96,19 +97,48 @@ async function deployCmd(argv, inherited) {
|
|
|
96
97
|
}
|
|
97
98
|
const apiKey = await getApiKey(flags, 'function');
|
|
98
99
|
const base = resolveBase(flags.base);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
// Collect repeatable `--secret NAME=VALUE` — set on the worker as part of this
|
|
101
|
+
// deploy so first-time setup doesn't hit "deploy a function first".
|
|
102
|
+
const secrets = [];
|
|
103
|
+
for (let i = 0; i < argv.length; i++) {
|
|
104
|
+
let pair;
|
|
105
|
+
if (argv[i] === '--secret') {
|
|
106
|
+
pair = argv[i + 1];
|
|
107
|
+
i++;
|
|
108
|
+
}
|
|
109
|
+
else if (argv[i].startsWith('--secret=')) {
|
|
110
|
+
pair = argv[i].slice('--secret='.length);
|
|
111
|
+
}
|
|
112
|
+
if (pair) {
|
|
113
|
+
const eq = pair.indexOf('=');
|
|
114
|
+
if (eq < 1)
|
|
115
|
+
throw new Error(`--secret must be NAME=VALUE (got "${pair}")`);
|
|
116
|
+
secrets.push({ name: pair.slice(0, eq), value: pair.slice(eq + 1) });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const filename = flags.ts ? 'worker.ts' : 'worker.js';
|
|
120
|
+
const entryAbs = join(process.cwd(), filename);
|
|
121
|
+
// Pre-read for a friendly "file not found" message (esbuild's is cryptic).
|
|
102
122
|
try {
|
|
103
|
-
|
|
123
|
+
await readFile(entryAbs, 'utf8');
|
|
104
124
|
}
|
|
105
125
|
catch (e) {
|
|
106
126
|
throw new Error(`couldn't read ${filename} from ${process.cwd()} — ${e.message}\n hint: cd into the directory containing your ${filename}, or pass --ts if the file is worker.ts`);
|
|
107
127
|
}
|
|
128
|
+
// Compile (TS→JS) + bundle npm deps client-side via esbuild so imports like
|
|
129
|
+
// `@neondatabase/serverless` work; cloudflare:*/node:* stay external. We then
|
|
130
|
+
// upload plain JS — the platform can't run esbuild on workerd.
|
|
131
|
+
let source;
|
|
132
|
+
try {
|
|
133
|
+
source = await bundleWorker(entryAbs);
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
throw new Error(`couldn't bundle ${filename}: ${e.message}`);
|
|
137
|
+
}
|
|
108
138
|
const row = await api(`${base}/api/v1/sites/${slug}/function`, {
|
|
109
139
|
method: 'POST',
|
|
110
140
|
headers: headers(apiKey),
|
|
111
|
-
body: JSON.stringify({ source, lang }),
|
|
141
|
+
body: JSON.stringify({ source, lang: 'js', ...(secrets.length ? { secrets } : {}) }),
|
|
112
142
|
});
|
|
113
143
|
if (flags.json) {
|
|
114
144
|
console.log(JSON.stringify(row, null, 2));
|
|
@@ -117,7 +147,9 @@ async function deployCmd(argv, inherited) {
|
|
|
117
147
|
console.log(`✔ deployed worker for ${slug}`);
|
|
118
148
|
console.log(` script: ${row.cfScriptName}`);
|
|
119
149
|
console.log(` version: ${row.version.slice(0, 12)}`);
|
|
120
|
-
console.log(` source: ${filename} (
|
|
150
|
+
console.log(` source: ${filename} (bundled → js)`);
|
|
151
|
+
if (secrets.length)
|
|
152
|
+
console.log(` secrets: set ${secrets.map((s) => s.name).join(', ')}`);
|
|
121
153
|
console.log(` routes: requests to https://${slug}.shiply.now/* now hit your worker first`);
|
|
122
154
|
}
|
|
123
155
|
async function getFnCmd(argv, inherited) {
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
4
|
import { createInterface } from 'node:readline/promises';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
@@ -318,6 +318,17 @@ async function main() {
|
|
|
318
318
|
if (resolved.hint && publishDir !== dir && !bareJsonFlag) {
|
|
319
319
|
console.log(`✔ ${resolved.hint.framework} project detected — publishing ${publishDir}${resolved.hint.spa ? ' with SPA mode' : ''}`);
|
|
320
320
|
}
|
|
321
|
+
// A bare worker.{ts,js} at the publish root ships as a STATIC asset here
|
|
322
|
+
// (downloadable source, never runs). Warn — it deploys separately as a
|
|
323
|
+
// per-site Worker via `shiply function deploy`.
|
|
324
|
+
if (!bareJsonFlag) {
|
|
325
|
+
for (const wf of ['worker.ts', 'worker.js']) {
|
|
326
|
+
if (existsSync(join(publishDir, wf))) {
|
|
327
|
+
console.log(`⚠ ${wf} will be uploaded as a STATIC file (its source is downloadable) and will NOT run as a worker.\n` +
|
|
328
|
+
` Deploy it as a per-site Worker instead: shiply function deploy <slug>${wf.endsWith('.ts') ? ' --ts' : ''}`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
321
332
|
}
|
|
322
333
|
try {
|
|
323
334
|
// same command, same URL: reuse this directory's site automatically
|
|
@@ -337,6 +348,10 @@ async function main() {
|
|
|
337
348
|
throw new Error('nothing to update here — publish first (shiply remembers the site in .shiply.json), or pass --claim-token');
|
|
338
349
|
}
|
|
339
350
|
const updating = Boolean(claimToken || slug);
|
|
351
|
+
// Send the stable siteId so a publish self-heals after a handle rename
|
|
352
|
+
// left state.slug stale. Only for the normal state-based update path —
|
|
353
|
+
// never with --as (alias has its own slug) or --new-site.
|
|
354
|
+
const siteId = !aliasName && !values['new-site'] && state?.owned && apiKey ? state?.siteId : undefined;
|
|
340
355
|
// Auto-attach a previously-created database on publish. Anonymous
|
|
341
356
|
// publishes can't attach (no auth subject) — silently skipped server-side.
|
|
342
357
|
const attachDatabaseId = state?.databaseId && apiKey ? state.databaseId : undefined;
|
|
@@ -350,6 +365,7 @@ async function main() {
|
|
|
350
365
|
spaMode: spa,
|
|
351
366
|
claimToken,
|
|
352
367
|
slug,
|
|
368
|
+
siteId,
|
|
353
369
|
attachDatabaseId,
|
|
354
370
|
previewBranchDbId,
|
|
355
371
|
// Group under a client (owned publishes only). --client "<name|email>"
|
package/dist/publish.js
CHANGED
|
@@ -40,6 +40,7 @@ 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.siteId ? { siteId: opts.siteId } : {}),
|
|
43
44
|
...(opts.attachDatabaseId ? { attachDatabaseId: opts.attachDatabaseId } : {}),
|
|
44
45
|
...(opts.previewBranchDbId ? { previewBranchDbId: opts.previewBranchDbId } : {}),
|
|
45
46
|
...(opts.client ? { client: opts.client } : {}),
|
package/package.json
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "shiply-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Publish static sites to shiply.now from the command line
|
|
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
|
-
"@types/node": "^22.15.0",
|
|
35
|
-
"typescript": "^5.8.0",
|
|
36
|
-
"vitest": "^3.1.0"
|
|
37
|
-
},
|
|
38
|
-
"dependencies": {
|
|
39
|
-
"esbuild": "^0.25.12",
|
|
40
|
-
"smol-toml": "^1.7.0"
|
|
41
|
-
}
|
|
42
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "shiply-cli",
|
|
3
|
+
"version": "0.23.0",
|
|
4
|
+
"description": "Publish static sites to shiply.now from the command line \u00e2\u20ac\u201d 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
|
+
"@types/node": "^22.15.0",
|
|
35
|
+
"typescript": "^5.8.0",
|
|
36
|
+
"vitest": "^3.1.0"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"esbuild": "^0.25.12",
|
|
40
|
+
"smol-toml": "^1.7.0"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/skill/SKILL.md
CHANGED
|
@@ -26,7 +26,7 @@ description: "shiply is the production backend for anything an agent builds —
|
|
|
26
26
|
|
|
27
27
|
**What it is.** Not static hosting. shiply takes whatever you build — a static page or a full-stack app in any framework — and gives it a live URL, a custom domain, a SQL database, server functions, email (send + receive), and a marketplace to sell it. One call. No account needed to start: anonymous sites are live immediately, last 24 hours, and can be claimed to keep.
|
|
28
28
|
|
|
29
|
-
**Why use it.** Ship a complete, working product without stitching together a host + database + email + registrar + payments — it's one agent-native platform (MCP / CLI / REST parity). Hard-ceiling pricing ($0/$8/$24, no usage meter), so a spike or DDoS can never become a surprise bill for the owner.
|
|
29
|
+
**Why use it.** Ship a complete, working product without stitching together a host + database + email + registrar + payments — it's one agent-native platform (MCP / CLI / REST parity). Hard-ceiling pricing ($0/$8/$24, plus a $49 Studio tier for client delivery — no usage meter on any tier), so a spike or DDoS can never become a surprise bill for the owner.
|
|
30
30
|
|
|
31
31
|
**How (quickstart).** `shiply publish ./dir` (CLI) — or POST /api/v1/publish → PUT each file → POST finalize — returns a live URL + claimToken.
|
|
32
32
|
|