create-zuplo-api 1.0.0 → 1.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/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) Zuplo, Inc. All rights reserved.
2
+
3
+ This software and associated documentation files (the "Software") is intended to be used
4
+ only by Zuplo customers solely to develop and test applications that will be deployed
5
+ to Zuplo hosted services. You and others in your organization may use these files on your
6
+ Development Devices solely for the above stated purpose.
7
+
8
+ Outside of uses stated above, no license is granted for any other purpose including
9
+ without limitation the rights to use, copy, modify, merge, publish, distribute,
10
+ sublicense, host, and/or sell copies of the Software.
11
+
12
+ The software may include third party components with separate legal notices or governed by
13
+ other agreements, as described in licenses either embedded in or accompanying the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16
+ INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
17
+ PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
18
+ FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20
+ DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # create-zuplo-api
2
+
3
+ The official way to create a new Zuplo API Gateway.
4
+
5
+ <p align="center">
6
+ <img src="https://github.com/zuplo/zuplo/blob/main/media/screenshot-cli.png?raw=true" width="800">
7
+ </p>
8
+
9
+ ## Usage
10
+
11
+ ```sh
12
+ npm create zuplo-api@latest
13
+ ```
14
+
15
+ Do not omit the @latest tag, otherwise `npm` may resolve to a cached and
16
+ outdated version of this package.
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable */
3
+ process.removeAllListeners("warning");
4
+ import "./dist/cli.js";
package/dist/cli.js ADDED
@@ -0,0 +1,50 @@
1
+ import * as dotenv from "dotenv";
2
+ dotenv.config();
3
+ import * as Sentry from "@sentry/node";
4
+ import { logger } from "./common/logger.js";
5
+ import { printCriticalFailureToConsoleAndExit, printDiagnosticsToConsole, } from "./common/output.js";
6
+ import { gte } from "semver";
7
+ import { readFileSync } from "node:fs";
8
+ import { fileURLToPath } from "node:url";
9
+ import { MAX_WAIT_PENDING_TIME_MS, SENTRY_DSN } from "./common/constants.js";
10
+ import { shutdownAnalytics } from "./common/analytics/lib.js";
11
+ import { create } from "./create/handler.js";
12
+ const MIN_NODE_VERSION = "18.0.0";
13
+ if (gte(process.versions.node, MIN_NODE_VERSION)) {
14
+ let packageJson;
15
+ try {
16
+ packageJson = JSON.parse(readFileSync(fileURLToPath(new URL("../package.json", import.meta.url)), "utf-8"));
17
+ }
18
+ catch (e) {
19
+ logger.error(e);
20
+ printCriticalFailureToConsoleAndExit(`Unable to load create-zuplo-api package. The package.json is missing or malformed.`);
21
+ }
22
+ Sentry.init({
23
+ dsn: SENTRY_DSN,
24
+ release: packageJson?.version,
25
+ });
26
+ try {
27
+ printDiagnosticsToConsole("");
28
+ printDiagnosticsToConsole("Zuplo: The Programmable API Gateway");
29
+ printDiagnosticsToConsole("");
30
+ await create();
31
+ void Sentry.close(MAX_WAIT_PENDING_TIME_MS).then(() => {
32
+ process.exit(0);
33
+ });
34
+ }
35
+ catch (err) {
36
+ if (err instanceof Error) {
37
+ Sentry.captureException(err);
38
+ }
39
+ printCriticalFailureToConsoleAndExit(err.message ?? err);
40
+ }
41
+ finally {
42
+ await shutdownAnalytics();
43
+ }
44
+ }
45
+ else {
46
+ printCriticalFailureToConsoleAndExit(`The create-zuplo-api package requires at least node.js v${MIN_NODE_VERSION}. You are using v${process.versions.node}. Please update your version of node.js.
47
+
48
+ Consider using a Node.js version manager such as https://github.com/nvm-sh/nvm.`);
49
+ }
50
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1,54 @@
1
+ import { defaultIntegrations } from "@sentry/node";
2
+ import { PostHog } from "posthog-node";
3
+ import { POST_HOG_CAPTURE_KEY, ZUPLO_USER_ID_ARGV_KEY } from "../constants.js";
4
+ import { machineId } from "../machine-id/lib.js";
5
+ let _postHog;
6
+ let _context;
7
+ function init() {
8
+ if (process.env.ZUPLO_DO_NOT_TRACK) {
9
+ return undefined;
10
+ }
11
+ _postHog = new PostHog(POST_HOG_CAPTURE_KEY, {
12
+ host: "https://app.posthog.com",
13
+ flushAt: 1,
14
+ flushInterval: 1,
15
+ });
16
+ _context = defaultIntegrations.filter((integration) => integration.name == "Context")[0];
17
+ return _postHog;
18
+ }
19
+ export async function captureEvent({ argv, event, properties, groups, sendFeatureFlags, timestamp, disableGeoip, }) {
20
+ if (_postHog === undefined) {
21
+ init();
22
+ }
23
+ if (_postHog) {
24
+ properties = properties ?? {};
25
+ properties.$set_once = properties.$set_once ?? {};
26
+ if (argv[ZUPLO_USER_ID_ARGV_KEY] &&
27
+ typeof argv[ZUPLO_USER_ID_ARGV_KEY] === "string") {
28
+ properties.$set_once["user-id"] = argv[ZUPLO_USER_ID_ARGV_KEY];
29
+ }
30
+ if (argv.account && typeof argv.account === "string") {
31
+ properties.$set_once["account"] = argv["account"];
32
+ }
33
+ if (argv.project && typeof argv.project === "string") {
34
+ properties.$set_once["project"] = argv["project"];
35
+ }
36
+ if (process.env.CI) {
37
+ properties["ci"] = process.env.CI;
38
+ }
39
+ await _context?.addContext(properties);
40
+ _postHog?.capture({
41
+ distinctId: argv[ZUPLO_USER_ID_ARGV_KEY] || machineId(),
42
+ event,
43
+ properties,
44
+ groups,
45
+ sendFeatureFlags,
46
+ timestamp,
47
+ disableGeoip,
48
+ });
49
+ }
50
+ }
51
+ export async function shutdownAnalytics() {
52
+ return _postHog?.shutdownAsync();
53
+ }
54
+ //# sourceMappingURL=lib.js.map
@@ -0,0 +1,5 @@
1
+ export const ZUPLO_USER_ID_ARGV_KEY = "zuplo-user-id";
2
+ export const SENTRY_DSN = "https://e98d81e78b23b65fa607473823a9957a@o1036703.ingest.sentry.io/4505953760313344";
3
+ export const MAX_WAIT_PENDING_TIME_MS = 1000;
4
+ export const POST_HOG_CAPTURE_KEY = "phc_LDSwSTOvIjiDDZql2g54Q7xEXoQ0EN9RMYb3STbdz1V";
5
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1,14 @@
1
+ import * as Pino from "pino";
2
+ export const logger = Pino.pino({
3
+ level: process.env.LOG_LEVEL || "info",
4
+ transport: {
5
+ targets: [
6
+ {
7
+ target: "@zuplo/pino-pretty-configurations",
8
+ level: process.env.LOG_LEVEL || "info",
9
+ options: {},
10
+ },
11
+ ],
12
+ },
13
+ });
14
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1,65 @@
1
+ import { execSync } from "node:child_process";
2
+ import { createHash } from "node:crypto";
3
+ const win32RegBinPath = {
4
+ skipped: "",
5
+ native: "%windir%\\System32",
6
+ mixed: "%windir%\\sysnative\\cmd.exe /c %windir%\\System32",
7
+ };
8
+ const guid = {
9
+ darwin: "ioreg -rd1 -c IOPlatformExpertDevice",
10
+ win32: `${win32RegBinPath[isWindowsProcessMixedOrNativeArchitecture()]}\\REG.exe ` +
11
+ "QUERY HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography " +
12
+ "/v MachineGuid",
13
+ linux: "( cat /var/lib/dbus/machine-id /etc/machine-id 2> /dev/null || hostname ) | head -n 1 || :",
14
+ };
15
+ function isWindowsProcessMixedOrNativeArchitecture() {
16
+ if (process.platform !== "win32") {
17
+ return "skipped";
18
+ }
19
+ if (process.arch === "ia32" && process.env["PROCESSOR_ARCHITEW6432"]) {
20
+ return "mixed";
21
+ }
22
+ return "native";
23
+ }
24
+ function hash(guid) {
25
+ return createHash("sha256").update(guid).digest("hex");
26
+ }
27
+ function expose(result) {
28
+ switch (process.platform) {
29
+ case "darwin":
30
+ return result
31
+ .split("IOPlatformUUID")[1]
32
+ .split("\n")[0]
33
+ .replace(/=|\s+]"/gi, "")
34
+ .toLowerCase();
35
+ case "win32":
36
+ return result
37
+ .toString()
38
+ .split("REG_SZ")[1]
39
+ .replace(/\r+|\n+|\s+/gi, "")
40
+ .toLowerCase();
41
+ case "linux":
42
+ return result
43
+ .toString()
44
+ .replace(/\r+|\n+|\s+/gi, "")
45
+ .toLowerCase();
46
+ case "freebsd":
47
+ return result
48
+ .toString()
49
+ .replace(/\r+|\n+|\s+/gi, "")
50
+ .toLowerCase();
51
+ default:
52
+ throw new Error(`Unsupported platform: ${process.platform}`);
53
+ }
54
+ }
55
+ export function machineId() {
56
+ switch (process.platform) {
57
+ case "darwin":
58
+ case "win32":
59
+ case "linux":
60
+ return hash(expose(execSync(guid[process.platform]).toString()));
61
+ default:
62
+ return "e16fc483-5593-4d71-b485-a6533693da9b";
63
+ }
64
+ }
65
+ //# sourceMappingURL=lib.js.map
@@ -0,0 +1,51 @@
1
+ import * as Sentry from "@sentry/node";
2
+ import chalk from "chalk";
3
+ import { MAX_WAIT_PENDING_TIME_MS } from "./constants.js";
4
+ export function printDiagnosticsToConsole(message) {
5
+ console.error(chalk.bold.blue(message));
6
+ }
7
+ export function printCriticalFailureToConsoleAndExit(message) {
8
+ console.error(chalk.bold.red(message));
9
+ void Sentry.close(MAX_WAIT_PENDING_TIME_MS).then(() => {
10
+ process.exit(1);
11
+ });
12
+ }
13
+ export function printResultToConsole(message) {
14
+ console.log(chalk.bold.green(message));
15
+ }
16
+ export function printTableToConsole(table) {
17
+ console.table(table);
18
+ }
19
+ export function printResultToConsoleAndExitGracefully(message) {
20
+ printResultToConsole(message);
21
+ void Sentry.close(MAX_WAIT_PENDING_TIME_MS).then(() => {
22
+ process.exit(0);
23
+ });
24
+ }
25
+ export function printTableToConsoleAndExitGracefully(table) {
26
+ printTableToConsole(table);
27
+ void Sentry.close(MAX_WAIT_PENDING_TIME_MS).then(() => {
28
+ process.exit(0);
29
+ });
30
+ }
31
+ export default function setBlocking() {
32
+ if (typeof process === "undefined")
33
+ return;
34
+ [process.stdout, process.stderr].forEach((_stream) => {
35
+ const stream = _stream;
36
+ if (stream._handle &&
37
+ stream.isTTY &&
38
+ typeof stream._handle.setBlocking === "function") {
39
+ stream._handle.setBlocking(true);
40
+ }
41
+ });
42
+ }
43
+ export function textOrJson(text) {
44
+ try {
45
+ return JSON.parse(text);
46
+ }
47
+ catch (e) {
48
+ return text;
49
+ }
50
+ }
51
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1,36 @@
1
+ import input from "@inquirer/input";
2
+ import { printCriticalFailureToConsoleAndExit, printDiagnosticsToConsole, printResultToConsole, } from "../common/output.js";
3
+ import { logger } from "../common/logger.js";
4
+ import { captureEvent } from "../common/analytics/lib.js";
5
+ export async function create() {
6
+ await captureEvent({ argv: {}, event: "create-zuplo-api" });
7
+ const name = await input({
8
+ message: "What do you want to name your project?",
9
+ });
10
+ if (name) {
11
+ const core = await import("@zuplo/core");
12
+ try {
13
+ const rootDirectory = process.cwd();
14
+ printDiagnosticsToConsole("");
15
+ printDiagnosticsToConsole(`Scaffolding project in ${rootDirectory}/${name}...`);
16
+ const _result = await core.default.create({
17
+ rootDirectory,
18
+ name,
19
+ logger,
20
+ });
21
+ printDiagnosticsToConsole("");
22
+ printDiagnosticsToConsole("Done. Now run:");
23
+ printDiagnosticsToConsole("");
24
+ printResultToConsole(` cd ${name}`);
25
+ printResultToConsole(` npm install`);
26
+ printResultToConsole(` npm run dev`);
27
+ }
28
+ catch (err) {
29
+ printDiagnosticsToConsole(err.message ?? err);
30
+ }
31
+ }
32
+ else {
33
+ printCriticalFailureToConsoleAndExit("Please enter a name for your project");
34
+ }
35
+ }
36
+ //# sourceMappingURL=handler.js.map
package/package.json CHANGED
@@ -1,12 +1,61 @@
1
1
  {
2
2
  "name": "create-zuplo-api",
3
- "version": "1.0.0",
4
- "description": "",
5
- "main": "index.js",
3
+ "version": "1.4.0",
4
+ "type": "module",
5
+ "repository": "https://github.com/zuplo/create-zuplo-api",
6
+ "description": "The official way to create a new Zuplo API Gateway",
7
+ "author": "Zuplo, Inc.",
8
+ "license": "See LICENSE in LICENSE.txt",
6
9
  "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
10
+ "build": "tsc --build",
11
+ "sentry:sourcemaps": "sentry-cli sourcemaps inject --org zuplo --project create-zuplo-api ./dist"
8
12
  },
9
- "keywords": [],
10
- "author": "",
11
- "license": "ISC"
13
+ "engines": {
14
+ "node": ">=18.0.0"
15
+ },
16
+ "bin": {
17
+ "create-zuplo-api": "create-zuplo-api.js"
18
+ },
19
+ "lint-staged": {
20
+ "**/*.{ts,json,md,yml,js,css,html}": [
21
+ "prettier --write"
22
+ ],
23
+ "**/*.{ts,js}": [
24
+ "eslint --cache --fix --ignore-path .eslintignore"
25
+ ]
26
+ },
27
+ "devDependencies": {
28
+ "@sentry/cli": "^2.21.1",
29
+ "@types/node": "^18.5.3",
30
+ "@types/semver": "^7.5.3",
31
+ "@typescript-eslint/eslint-plugin": "^6.7.3",
32
+ "@typescript-eslint/parser": "^6.7.3",
33
+ "eslint": "^8.50.0",
34
+ "eslint-config-prettier": "^9.0.0",
35
+ "eslint-plugin-import": "^2.28.1",
36
+ "eslint-plugin-node": "^11.1.0",
37
+ "eslint-plugin-unicorn": "^48.0.1",
38
+ "husky": "^8.0.3",
39
+ "lint-staged": "^14.0.1",
40
+ "prettier-plugin-organize-imports": "^3.2.3",
41
+ "typescript": "^5.2.2"
42
+ },
43
+ "dependencies": {
44
+ "@inquirer/prompts": "^3.1.2",
45
+ "@sentry/node": "^7.72.0",
46
+ "@swc/core": "^1.3.90",
47
+ "@zuplo/core": "^5.1327.0",
48
+ "@zuplo/pino-pretty-configurations": "^1.5.0",
49
+ "@zuplo/runtime": "^5.1327.0",
50
+ "chalk": "^5.3.0",
51
+ "dotenv": "^16.3.1",
52
+ "esbuild": "^0.19.3",
53
+ "jsonc-parser": "^3.2.0",
54
+ "pino": "^8.15.1",
55
+ "pino-pretty": "^10.2.0",
56
+ "posthog-node": "^3.1.2",
57
+ "prettier": "^3.0.3",
58
+ "rollup-plugin-node-polyfills": "^0.2.1",
59
+ "semver": "^7.5.4"
60
+ }
12
61
  }