@instafy/cli 0.1.11 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,27 +1,29 @@
1
1
  {
2
2
  "name": "@instafy/cli",
3
- "version": "0.1.11",
4
- "description": "Run Instafy projects locally, link folders to Studio, and share previews/webhooks via tunnels.",
3
+ "version": "0.2.1",
4
+ "license": "AGPL-3.0-only",
5
+ "description": "Run Instafy spaces locally, link folders to Studio, and share previews/webhooks via tunnels.",
5
6
  "private": false,
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/instafy-dev/instafy.git",
10
+ "directory": "packages/instafy-cli"
11
+ },
6
12
  "publishConfig": {
7
13
  "access": "public"
8
14
  },
9
15
  "files": [
10
16
  "bin",
11
- "dist",
17
+ "dist/cli.js",
18
+ "LICENSE",
12
19
  "README.md"
13
20
  ],
14
21
  "bin": {
15
22
  "instafy": "bin/instafy.js"
16
23
  },
17
24
  "type": "module",
18
- "scripts": {
19
- "build": "tsc -p tsconfig.json",
20
- "prepack": "tsc -p tsconfig.json",
21
- "dev": "ts-node src/index.ts",
22
- "test": "pnpm test:unit",
23
- "test:unit": "pnpm build && vitest run",
24
- "test:live": "pnpm build && TUNNEL_E2E_LIVE=1 vitest run test/tunnel-live.e2e.spec.ts"
25
+ "engines": {
26
+ "node": ">=18"
25
27
  },
26
28
  "dependencies": {
27
29
  "@clack/prompts": "^0.11.0",
@@ -31,7 +33,16 @@
31
33
  "devDependencies": {
32
34
  "@types/node": "^22.8.1",
33
35
  "ts-node": "^10.9.2",
36
+ "tsup": "^7.3.0",
34
37
  "typescript": "^5.4.5",
35
38
  "vitest": "^1.6.0"
39
+ },
40
+ "scripts": {
41
+ "build": "tsc -p tsconfig.json && tsup --config tsup.config.ts",
42
+ "dev": "ts-node src/index.ts",
43
+ "test": "pnpm test:unit",
44
+ "test:unit": "pnpm build && vitest run",
45
+ "test:package": "pnpm build && node --test test/package-artifact.test.mjs",
46
+ "test:live": "pnpm build && TUNNEL_E2E_LIVE=1 vitest run test/tunnel-live.e2e.spec.ts"
36
47
  }
37
- }
48
+ }
package/dist/api.js DELETED
@@ -1,166 +0,0 @@
1
- import fs from "node:fs";
2
- import { resolveActiveProfileName, resolveConfiguredAccessToken } from "./config.js";
3
- import { formatAuthRejectedError } from "./errors.js";
4
- import { fetchWithControllerAuth } from "./controller-fetch.js";
5
- function normalizeUrl(raw) {
6
- const value = (raw ?? "").trim();
7
- if (!value)
8
- return "http://127.0.0.1:8788";
9
- return value.replace(/\/$/, "");
10
- }
11
- function normalizeToken(raw) {
12
- if (!raw)
13
- return null;
14
- const trimmed = raw.trim();
15
- return trimmed.length ? trimmed : null;
16
- }
17
- function resolveBearerTokenWithSource(options) {
18
- const cwd = process.cwd();
19
- const profile = resolveActiveProfileName({ cwd });
20
- const stored = resolveConfiguredAccessToken({ profile, cwd });
21
- const explicit = normalizeToken(options.accessToken) ?? normalizeToken(options.serviceToken);
22
- if (explicit) {
23
- return { token: explicit, source: "explicit", profile };
24
- }
25
- const envKeys = [
26
- "CONTROLLER_ACCESS_TOKEN",
27
- "INSTAFY_ACCESS_TOKEN",
28
- "INSTAFY_SERVICE_TOKEN",
29
- "CONTROLLER_TOKEN",
30
- "SUPABASE_ACCESS_TOKEN",
31
- ];
32
- for (const key of envKeys) {
33
- const value = normalizeToken(process.env[key]);
34
- if (value) {
35
- return { token: value, source: "env", profile };
36
- }
37
- }
38
- if (stored) {
39
- return { token: stored, source: "config", profile };
40
- }
41
- return { token: null, source: "none", profile };
42
- }
43
- function parseKeyValue(raw) {
44
- const trimmed = raw.trim();
45
- if (!trimmed) {
46
- throw new Error("Key/value pair cannot be empty");
47
- }
48
- const equals = trimmed.indexOf("=");
49
- if (equals === -1) {
50
- return { key: trimmed, value: "" };
51
- }
52
- const key = trimmed.slice(0, equals).trim();
53
- const value = trimmed.slice(equals + 1).trim();
54
- if (!key) {
55
- throw new Error(`Invalid pair "${raw}" (missing key)`);
56
- }
57
- return { key, value };
58
- }
59
- function parseHeader(raw) {
60
- const trimmed = raw.trim();
61
- if (!trimmed) {
62
- throw new Error("Header cannot be empty");
63
- }
64
- const colon = trimmed.indexOf(":");
65
- if (colon !== -1) {
66
- const key = trimmed.slice(0, colon).trim();
67
- const value = trimmed.slice(colon + 1).trim();
68
- if (!key) {
69
- throw new Error(`Invalid header "${raw}" (missing name)`);
70
- }
71
- return { key, value };
72
- }
73
- return parseKeyValue(trimmed);
74
- }
75
- function parseJsonBody(options) {
76
- if (options.jsonFile) {
77
- const raw = fs.readFileSync(options.jsonFile, "utf8");
78
- const parsed = JSON.parse(raw);
79
- return JSON.stringify(parsed);
80
- }
81
- if (options.json) {
82
- const parsed = JSON.parse(options.json);
83
- return JSON.stringify(parsed);
84
- }
85
- return undefined;
86
- }
87
- function buildRequestUrl(options) {
88
- const base = normalizeUrl(options.controllerUrl ??
89
- process.env["INSTAFY_SERVER_URL"] ??
90
- process.env["CONTROLLER_BASE_URL"] ??
91
- "http://127.0.0.1:8788");
92
- const rawPath = options.path.trim();
93
- if (!rawPath) {
94
- throw new Error("Path is required");
95
- }
96
- const url = rawPath.startsWith("http://") || rawPath.startsWith("https://")
97
- ? new URL(rawPath)
98
- : new URL(rawPath.startsWith("/") ? rawPath : `/${rawPath}`, `${base}/`);
99
- for (const pair of options.query ?? []) {
100
- const { key, value } = parseKeyValue(pair);
101
- url.searchParams.set(key, value);
102
- }
103
- return url;
104
- }
105
- function maybePrettyPrintJson(text, pretty) {
106
- if (!pretty)
107
- return text;
108
- if (!text.trim())
109
- return text;
110
- try {
111
- return JSON.stringify(JSON.parse(text), null, 2);
112
- }
113
- catch {
114
- return text;
115
- }
116
- }
117
- export async function requestControllerApi(options) {
118
- const url = buildRequestUrl(options);
119
- const resolved = resolveBearerTokenWithSource(options);
120
- const bearer = resolved.token;
121
- const headers = new Headers();
122
- headers.set("accept", "application/json");
123
- for (const header of options.headers ?? []) {
124
- const { key, value } = parseHeader(header);
125
- headers.set(key, value);
126
- }
127
- const body = parseJsonBody(options);
128
- if (body !== undefined && !headers.has("content-type")) {
129
- headers.set("content-type", "application/json");
130
- }
131
- const init = {
132
- method: options.method,
133
- headers,
134
- body,
135
- };
136
- const response = bearer
137
- ? (await fetchWithControllerAuth({
138
- url: url.toString(),
139
- init,
140
- accessToken: bearer,
141
- tokenSource: resolved.source,
142
- profile: resolved.profile,
143
- cwd: process.cwd(),
144
- })).response
145
- : await fetch(url, init);
146
- const responseText = await response.text().catch(() => "");
147
- const contentType = response.headers.get("content-type") ?? "";
148
- const isJson = contentType.includes("application/json") || contentType.includes("+json");
149
- const pretty = options.pretty !== false;
150
- const formattedBody = isJson ? maybePrettyPrintJson(responseText, pretty) : responseText;
151
- if (!response.ok) {
152
- if (response.status === 401 || response.status === 403) {
153
- throw formatAuthRejectedError({
154
- status: response.status,
155
- responseBody: responseText,
156
- retryCommand: "instafy login",
157
- advancedHint: "pass --access-token / --service-token, or set INSTAFY_ACCESS_TOKEN / INSTAFY_SERVICE_TOKEN",
158
- });
159
- }
160
- const prefix = `Request failed (${response.status} ${response.statusText})`;
161
- const suffix = formattedBody.trim() ? `: ${formattedBody}` : "";
162
- throw new Error(`${prefix}${suffix}`);
163
- }
164
- if (formattedBody)
165
- console.log(formattedBody);
166
- }