@saastemly/voidcommerce 0.1.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/README.md +271 -0
- package/bin/vc +2 -0
- package/dist/catalog.d.ts +69 -0
- package/dist/catalog.js +34 -0
- package/dist/cli.d.ts +24 -0
- package/dist/cli.js +544 -0
- package/dist/deploy/cloudflare.d.ts +25 -0
- package/dist/deploy/index.d.ts +16 -0
- package/dist/deploy/jsonc.d.ts +8 -0
- package/dist/deploy/preflight.d.ts +29 -0
- package/dist/deploy/wrangler.d.ts +37 -0
- package/dist/dist.d.ts +22 -0
- package/dist/generate/auth.d.ts +2 -0
- package/dist/generate/ci.d.ts +24 -0
- package/dist/generate/env.d.ts +13 -0
- package/dist/generate/frontend.d.ts +47 -0
- package/dist/generate/index.d.ts +28 -0
- package/dist/generate/requirements.d.ts +13 -0
- package/dist/generate/strict.d.ts +72 -0
- package/dist/generate/support.d.ts +23 -0
- package/dist/help.d.ts +31 -0
- package/dist/import.d.ts +2 -0
- package/dist/index-s7sq41qs.js +590 -0
- package/dist/index-ssv3a6wc.js +172 -0
- package/dist/index-wzy1xtr1.js +3155 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +190 -0
- package/dist/init.d.ts +1 -0
- package/dist/manifest.d.ts +131 -0
- package/dist/manifest.js +41 -0
- package/dist/project.d.ts +20 -0
- package/dist/regenerate.d.ts +9 -0
- package/dist/scripts.d.ts +12 -0
- package/dist/void.d.ts +30 -0
- package/dist/wizard.d.ts +7 -0
- package/package.json +50 -0
- package/src/catalog.ts +673 -0
- package/src/cli.ts +78 -0
- package/src/deploy/cloudflare.ts +166 -0
- package/src/deploy/index.ts +101 -0
- package/src/deploy/jsonc.ts +148 -0
- package/src/deploy/preflight.ts +137 -0
- package/src/deploy/wrangler.ts +111 -0
- package/src/dist.ts +157 -0
- package/src/generate/auth.ts +386 -0
- package/src/generate/ci.ts +208 -0
- package/src/generate/env.ts +164 -0
- package/src/generate/frontend.ts +275 -0
- package/src/generate/index.ts +390 -0
- package/src/generate/requirements.ts +48 -0
- package/src/generate/strict.ts +692 -0
- package/src/generate/support.ts +252 -0
- package/src/help.ts +172 -0
- package/src/import.ts +237 -0
- package/src/index.ts +37 -0
- package/src/init.ts +187 -0
- package/src/manifest.ts +303 -0
- package/src/project.ts +63 -0
- package/src/regenerate.ts +51 -0
- package/src/scripts.ts +53 -0
- package/src/void.ts +115 -0
- package/src/wizard.ts +234 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CHOICES,
|
|
3
|
+
GROUPS
|
|
4
|
+
} from "./index-s7sq41qs.js";
|
|
5
|
+
|
|
6
|
+
// src/manifest.ts
|
|
7
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
var MANIFEST_FILE = "voidcommerce.json";
|
|
10
|
+
var LAYOUTS = [
|
|
11
|
+
{
|
|
12
|
+
id: "app",
|
|
13
|
+
label: "One app",
|
|
14
|
+
hint: "the API and the generated storefront and panel in one Void app on Cloudflare Workers, at your domain"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: "monorepo",
|
|
18
|
+
label: "Monorepo: api + frontend",
|
|
19
|
+
hint: "api/ on Workers at api.<domain> with the panel; frontend/ a static site on GitHub Pages at <domain>"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: "strict",
|
|
23
|
+
label: "Strict (experimental)",
|
|
24
|
+
hint: "the root IS the storefront, sharing one package.json; the worker is generated under .vc/app from the manifest and never hand-edited"
|
|
25
|
+
}
|
|
26
|
+
];
|
|
27
|
+
var isSingleApp = (layout) => layout === "app";
|
|
28
|
+
var hasFrontend = (layout) => layout !== "app";
|
|
29
|
+
var TWO_LABEL_SUFFIXES = new Set(["co", "com", "net", "org", "ac", "gov", "edu", "or", "ne", "in"]);
|
|
30
|
+
function zoneOf(domain) {
|
|
31
|
+
const labels = domain.trim().toLowerCase().replace(/\.$/, "").split(".");
|
|
32
|
+
if (labels.length <= 2)
|
|
33
|
+
return labels.join(".");
|
|
34
|
+
const take = TWO_LABEL_SUFFIXES.has(labels[labels.length - 2] ?? "") && (labels[labels.length - 1] ?? "").length <= 3 ? 3 : 2;
|
|
35
|
+
return labels.slice(-take).join(".");
|
|
36
|
+
}
|
|
37
|
+
function zone(manifest) {
|
|
38
|
+
return manifest.shop.zone || zoneOf(manifest.shop.domain);
|
|
39
|
+
}
|
|
40
|
+
function isApex(manifest) {
|
|
41
|
+
return manifest.shop.domain === zone(manifest);
|
|
42
|
+
}
|
|
43
|
+
function workerHosts(manifest) {
|
|
44
|
+
const { domain } = manifest.shop;
|
|
45
|
+
if (!isSingleApp(manifest.layout))
|
|
46
|
+
return [`api.${domain}`];
|
|
47
|
+
return isApex(manifest) ? [domain, `www.${domain}`] : [domain];
|
|
48
|
+
}
|
|
49
|
+
var LAYOUT_IMPLIES = {
|
|
50
|
+
app: {},
|
|
51
|
+
monorepo: { ui: ["custom"] },
|
|
52
|
+
strict: { ui: ["admin", "custom"] }
|
|
53
|
+
};
|
|
54
|
+
function withRequired(chosen, layout = "app") {
|
|
55
|
+
const out = {};
|
|
56
|
+
for (const group of GROUPS) {
|
|
57
|
+
const picked = new Set([...chosen[group.id] ?? [], ...LAYOUT_IMPLIES[layout][group.id] ?? []]);
|
|
58
|
+
for (const choice of group.choices) {
|
|
59
|
+
if (choice.required)
|
|
60
|
+
picked.add(choice.id);
|
|
61
|
+
}
|
|
62
|
+
for (const id of [...picked]) {
|
|
63
|
+
for (const dependency of CHOICES.get(id)?.requires ?? [])
|
|
64
|
+
picked.add(dependency);
|
|
65
|
+
}
|
|
66
|
+
out[group.id] = group.choices.filter((choice) => picked.has(choice.id)).map((c) => c.id);
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
function has(manifest, id) {
|
|
71
|
+
return Object.values(withRequired(manifest.chosen, manifest.layout)).some((ids) => ids.includes(id));
|
|
72
|
+
}
|
|
73
|
+
function chosenIn(manifest, groupId) {
|
|
74
|
+
return withRequired(manifest.chosen, manifest.layout)[groupId] ?? [];
|
|
75
|
+
}
|
|
76
|
+
function envKeysOf(manifest) {
|
|
77
|
+
const seen = new Set;
|
|
78
|
+
const keys = [];
|
|
79
|
+
for (const ids of Object.values(withRequired(manifest.chosen, manifest.layout))) {
|
|
80
|
+
for (const id of ids) {
|
|
81
|
+
for (const key of CHOICES.get(id)?.env ?? []) {
|
|
82
|
+
if (seen.has(key.key))
|
|
83
|
+
continue;
|
|
84
|
+
seen.add(key.key);
|
|
85
|
+
keys.push(key);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return keys;
|
|
90
|
+
}
|
|
91
|
+
var OWN_PACKAGES = [
|
|
92
|
+
"@saastemly/better-admin-ui",
|
|
93
|
+
"@saastemly/better-blogs",
|
|
94
|
+
"@saastemly/better-commerce",
|
|
95
|
+
"@saastemly/better-commerce-ui",
|
|
96
|
+
"@saastemly/better-dns",
|
|
97
|
+
"@saastemly/better-email",
|
|
98
|
+
"@saastemly/better-faqs",
|
|
99
|
+
"@saastemly/better-system-user",
|
|
100
|
+
"@saastemly/voidcommerce"
|
|
101
|
+
];
|
|
102
|
+
function specifier(manifest, name, version = "latest") {
|
|
103
|
+
if (!manifest.link || !OWN_PACKAGES.includes(name))
|
|
104
|
+
return version;
|
|
105
|
+
const base = manifest.link.replace(/\/+$/, "");
|
|
106
|
+
const directory = name.replace(/^@[^/]+\//, "");
|
|
107
|
+
return `file:${base}/${directory}`;
|
|
108
|
+
}
|
|
109
|
+
function packagesOf(manifest) {
|
|
110
|
+
const out = new Set(["better-auth", "@saastemly/better-commerce"]);
|
|
111
|
+
for (const ids of Object.values(withRequired(manifest.chosen, manifest.layout))) {
|
|
112
|
+
for (const id of ids)
|
|
113
|
+
for (const pkg of CHOICES.get(id)?.packages ?? [])
|
|
114
|
+
out.add(pkg);
|
|
115
|
+
}
|
|
116
|
+
if (manifest.layout === "monorepo") {
|
|
117
|
+
for (const pkg of CHOICES.get("custom")?.packages ?? [])
|
|
118
|
+
out.delete(pkg);
|
|
119
|
+
}
|
|
120
|
+
return [...out].sort();
|
|
121
|
+
}
|
|
122
|
+
async function readManifest(root) {
|
|
123
|
+
try {
|
|
124
|
+
const parsed = JSON.parse(await readFile(join(root, MANIFEST_FILE), "utf8"));
|
|
125
|
+
if (parsed.version !== 1)
|
|
126
|
+
throw new Error(`unknown manifest version ${String(parsed.version)}`);
|
|
127
|
+
parsed.layout ??= parsed.shop.pagesHost ? "monorepo" : "app";
|
|
128
|
+
return parsed;
|
|
129
|
+
} catch (error) {
|
|
130
|
+
if (error.code === "ENOENT")
|
|
131
|
+
return null;
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async function writeManifest(root, manifest) {
|
|
136
|
+
await writeFile(join(root, MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}
|
|
137
|
+
`, "utf8");
|
|
138
|
+
}
|
|
139
|
+
function validate(manifest) {
|
|
140
|
+
const problems = [];
|
|
141
|
+
const chosen = withRequired(manifest.chosen, manifest.layout);
|
|
142
|
+
for (const group of GROUPS) {
|
|
143
|
+
const ids = chosen[group.id] ?? [];
|
|
144
|
+
if (group.kind === "select" && ids.length !== 1) {
|
|
145
|
+
problems.push(`${group.title}: exactly one choice is needed, got ${ids.length}`);
|
|
146
|
+
}
|
|
147
|
+
for (const id of ids) {
|
|
148
|
+
for (const conflict of CHOICES.get(id)?.conflicts ?? []) {
|
|
149
|
+
if (ids.includes(conflict))
|
|
150
|
+
problems.push(`${group.title}: ${id} cannot be used with ${conflict}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (!/^[a-z0-9.-]+\.[a-z]{2,}$/i.test(manifest.shop.domain)) {
|
|
155
|
+
problems.push(`domain "${manifest.shop.domain}" does not look like a hostname`);
|
|
156
|
+
} else if (manifest.shop.zone && manifest.shop.domain !== manifest.shop.zone && !manifest.shop.domain.endsWith(`.${manifest.shop.zone}`)) {
|
|
157
|
+
problems.push(`domain "${manifest.shop.domain}" is not inside the zone "${manifest.shop.zone}" — records would be written to a zone that does not contain it`);
|
|
158
|
+
}
|
|
159
|
+
if (!/^[A-Z]{2}$/.test(manifest.shop.country)) {
|
|
160
|
+
problems.push(`country "${manifest.shop.country}" must be an ISO-3166 alpha-2 code`);
|
|
161
|
+
}
|
|
162
|
+
const dns = chosen["dns"] ?? [];
|
|
163
|
+
if (dns.includes("simply")) {
|
|
164
|
+
problems.push(`DNS at Simply.com cannot host ${workerHosts(manifest)[0]} — a Worker custom domain is created by Cloudflare, in a zone on Cloudflare`);
|
|
165
|
+
}
|
|
166
|
+
if (hasFrontend(manifest.layout) && manifest.shop.pagesHost && !/^[a-z0-9-]+\.github\.io$/i.test(manifest.shop.pagesHost)) {
|
|
167
|
+
problems.push(`Pages host "${manifest.shop.pagesHost}" should be <owner>.github.io`);
|
|
168
|
+
}
|
|
169
|
+
return problems;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export { MANIFEST_FILE, LAYOUTS, isSingleApp, hasFrontend, zoneOf, zone, isApex, workerHosts, withRequired, has, chosenIn, envKeysOf, OWN_PACKAGES, specifier, packagesOf, readManifest, writeManifest, validate };
|