nowebcli 0.2.9 → 0.2.10
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/lib/customizations.ts +0 -13
- package/package.json +1 -4
- package/scripts/noweb.mjs +23 -7
- package/templates/templateRuntime.tsx +10 -3
package/lib/customizations.ts
CHANGED
|
@@ -67,19 +67,6 @@ export function normalizeCustomizationValues(value: unknown): CustomizationValue
|
|
|
67
67
|
: null;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
export function restoreCustomizationValues(
|
|
71
|
-
current: CustomizationValues,
|
|
72
|
-
previous: CustomizationValues,
|
|
73
|
-
fieldIds: string[],
|
|
74
|
-
) {
|
|
75
|
-
const restored = { ...current };
|
|
76
|
-
for (const fieldId of fieldIds) {
|
|
77
|
-
if (Object.hasOwn(previous, fieldId)) restored[fieldId] = previous[fieldId];
|
|
78
|
-
else delete restored[fieldId];
|
|
79
|
-
}
|
|
80
|
-
return restored;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
70
|
export function normalizeCustomizationValue(
|
|
84
71
|
field: TemplateCustomization,
|
|
85
72
|
value: unknown,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nowebcli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.10",
|
|
4
4
|
"description": "Create, preview and publish community templates for Noweb",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -43,8 +43,6 @@
|
|
|
43
43
|
"ci": "npm audit --omit=dev --audit-level=high && npm run typecheck && npm run lint && npm run test && npm run build && npm run test:e2e"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@ai-sdk/openai": "^4.0.24",
|
|
47
|
-
"@ai-sdk/react": "^4.0.45",
|
|
48
46
|
"@aws-sdk/client-s3": "^3.1055.0",
|
|
49
47
|
"@heroicons/react": "^2.2.0",
|
|
50
48
|
"@monaco-editor/react": "^4.7.0",
|
|
@@ -57,7 +55,6 @@
|
|
|
57
55
|
"@tailwindcss/postcss": "^4",
|
|
58
56
|
"@types/pg": "^8.20.0",
|
|
59
57
|
"@uiw/react-textarea-code-editor": "^3.1.1",
|
|
60
|
-
"ai": "^7.0.42",
|
|
61
58
|
"better-auth": "1.7.2",
|
|
62
59
|
"clsx": "^2.1.1",
|
|
63
60
|
"esbuild": "^0.28.1",
|
package/scripts/noweb.mjs
CHANGED
|
@@ -36,9 +36,9 @@ function usage() {
|
|
|
36
36
|
login connect the CLI to your Noweb account
|
|
37
37
|
list list your uploaded templates
|
|
38
38
|
download <slug> restore one into the current folder
|
|
39
|
-
upload
|
|
39
|
+
upload save this template without publishing
|
|
40
40
|
delete [slug] delete one of your templates
|
|
41
|
-
publish
|
|
41
|
+
publish make the uploaded template public`);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
async function createTemplate(value) {
|
|
@@ -184,6 +184,20 @@ async function upload() {
|
|
|
184
184
|
if (!response.ok) throw new Error(result.error || `Upload failed (${response.status}).`);
|
|
185
185
|
if (!Number.isInteger(result.id) || result.id < 1) throw new Error("Upload returned an invalid template ID.");
|
|
186
186
|
await writeFile(join(root, "template.json"), `${JSON.stringify({ id: result.id, slug: template.slug, type: template.type }, null, 2)}\n`);
|
|
187
|
+
console.log(`Uploaded ${template.slug} (unpublished): ${new URL(result.url, apiBase)}`);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async function publishUploadedTemplate() {
|
|
191
|
+
const template = JSON.parse(await readFile(join(root, "template.json"), "utf8"));
|
|
192
|
+
if (!Number.isInteger(template.id) || template.id < 1) throw new Error("Upload this template first: npx nowebcli upload");
|
|
193
|
+
const credentials = await requireCredentials();
|
|
194
|
+
const response = await fetch(`${apiBase}/api/templates/visibility`, {
|
|
195
|
+
method: "PATCH",
|
|
196
|
+
headers: { Authorization: `Bearer ${credentials.token}`, "Content-Type": "application/json" },
|
|
197
|
+
body: JSON.stringify({ id: template.id, published: true }),
|
|
198
|
+
});
|
|
199
|
+
const result = await response.json().catch(() => ({}));
|
|
200
|
+
if (!response.ok) throw new Error(result.error || `Publish failed (${response.status}).`);
|
|
187
201
|
console.log(`Published ${template.slug}: ${new URL(result.url, apiBase)}`);
|
|
188
202
|
}
|
|
189
203
|
|
|
@@ -226,7 +240,7 @@ async function listTemplates() {
|
|
|
226
240
|
}
|
|
227
241
|
if (templates.length) {
|
|
228
242
|
console.log("Templates");
|
|
229
|
-
for (const template of templates) console.log(template.slug || template.id);
|
|
243
|
+
for (const template of templates) console.log(`${template.slug || template.id}\t${template.is_published ? "public" : "unpublished"}`);
|
|
230
244
|
}
|
|
231
245
|
if (projects.length) {
|
|
232
246
|
if (templates.length) console.log();
|
|
@@ -396,22 +410,24 @@ async function publish(value) {
|
|
|
396
410
|
await uploadTemplateAssets(template, storageApi.createObjectStorageClient(storage), storage.bucketName);
|
|
397
411
|
const [published] = await sql`
|
|
398
412
|
INSERT INTO templates (
|
|
399
|
-
slug, type, component, compiled_js, compiled_css, customizations, author_id
|
|
413
|
+
slug, type, component, compiled_js, compiled_css, customizations, author_id, is_published
|
|
400
414
|
) VALUES (
|
|
401
415
|
${template.slug}, ${template.type}, ${template.source}, ${template.js},
|
|
402
|
-
${template.css}, ${sql.json(template.customizations)}, 'github'
|
|
416
|
+
${template.css}, ${sql.json(template.customizations)}, 'github', true
|
|
403
417
|
)
|
|
404
418
|
ON CONFLICT (slug) DO UPDATE SET
|
|
405
419
|
type = EXCLUDED.type,
|
|
406
420
|
component = EXCLUDED.component,
|
|
407
421
|
compiled_js = EXCLUDED.compiled_js,
|
|
408
422
|
compiled_css = EXCLUDED.compiled_css,
|
|
409
|
-
customizations = EXCLUDED.customizations
|
|
423
|
+
customizations = EXCLUDED.customizations,
|
|
424
|
+
is_published = true
|
|
410
425
|
WHERE templates.type IS DISTINCT FROM EXCLUDED.type
|
|
411
426
|
OR templates.component IS DISTINCT FROM EXCLUDED.component
|
|
412
427
|
OR templates.compiled_js IS DISTINCT FROM EXCLUDED.compiled_js
|
|
413
428
|
OR templates.compiled_css IS DISTINCT FROM EXCLUDED.compiled_css
|
|
414
429
|
OR templates.customizations::jsonb IS DISTINCT FROM EXCLUDED.customizations::jsonb
|
|
430
|
+
OR templates.is_published IS DISTINCT FROM true
|
|
415
431
|
RETURNING id
|
|
416
432
|
`;
|
|
417
433
|
if (!published) {
|
|
@@ -646,7 +662,7 @@ try {
|
|
|
646
662
|
else if (command === "download") await downloadTemplate(slug);
|
|
647
663
|
else if (command === "upload") await upload();
|
|
648
664
|
else if (command === "delete") await deleteTemplate(slug);
|
|
649
|
-
else if (command === "publish") await publish(slug);
|
|
665
|
+
else if (command === "publish") await (engineRoot === root ? publish(slug) : publishUploadedTemplate());
|
|
650
666
|
else if (command === "help" || command === "--help" || command === "-h") usage();
|
|
651
667
|
else throw new Error(`Unknown command: ${command}`);
|
|
652
668
|
} catch (error) {
|
|
@@ -51,14 +51,21 @@ function loadFont(family: string, fallback: string) {
|
|
|
51
51
|
const stylesheet = document.createElement("link");
|
|
52
52
|
stylesheet.id = "noweb-template-fonts";
|
|
53
53
|
stylesheet.rel = "stylesheet";
|
|
54
|
-
stylesheet.href =
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
stylesheet.href = templateFontStylesheetHref(
|
|
55
|
+
currentTemplateRuntime.dataApiBase,
|
|
56
|
+
window.location.hostname,
|
|
57
|
+
);
|
|
57
58
|
document.head.append(stylesheet);
|
|
58
59
|
}
|
|
59
60
|
return `"${family}", ${fallback}`;
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
export function templateFontStylesheetHref(appBase: string | undefined, hostname: string) {
|
|
64
|
+
const base = appBase?.replace(/\/$/, "")
|
|
65
|
+
|| (hostname === "storage.noweb.app" ? "https://noweb.app" : "");
|
|
66
|
+
return `${base}/fonts/templates/fonts.css`;
|
|
67
|
+
}
|
|
68
|
+
|
|
62
69
|
export const font = fontStyles;
|
|
63
70
|
|
|
64
71
|
export function TemplateRuntimeProvider({
|