proto-plugin 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/AGENTS.md +350 -0
- package/README.md +279 -0
- package/components.json +18 -0
- package/package.json +73 -0
- package/scripts/download-mobbin-reference-images.mjs +112 -0
- package/scripts/lib/host-config.example.sh +48 -0
- package/scripts/lib/host-config.sh +25 -0
- package/scripts/lib/resolve-host-root.mjs +18 -0
- package/scripts/lib/source-path.sh +49 -0
- package/scripts/link-source-db.sh +128 -0
- package/scripts/link-source.sh +40 -0
- package/scripts/publish-package.sh +147 -0
- package/scripts/share-prototype.sh +279 -0
- package/scripts/sync-from-source.sh +74 -0
- package/scripts/verify-prototype-component-ids.mjs +151 -0
- package/scripts/verify-prototype-preview-states.mjs +135 -0
- package/src/app.ts +4 -0
- package/src/components/platform-ui/code-block.tsx +21 -0
- package/src/components/platform-ui/controls-panel-options.tsx +71 -0
- package/src/components/platform-ui/controls-panel-select.tsx +438 -0
- package/src/components/platform-ui/empty-state.tsx +15 -0
- package/src/components/platform-ui/icon-button.tsx +18 -0
- package/src/components/platform-ui/panel-select.tsx +123 -0
- package/src/components/platform-ui/panel.tsx +97 -0
- package/src/components/platform-ui/review-dropdown-menu.tsx +35 -0
- package/src/components/platform-ui/sidebar.tsx +293 -0
- package/src/components/platform-ui/toolbar-icon-button.tsx +34 -0
- package/src/components/platform-ui/toolbar.tsx +37 -0
- package/src/components/prototype-gallery-client.tsx +57 -0
- package/src/components/prototype-provider.tsx +20 -0
- package/src/components/prototypes/mini-pill-label.tsx +37 -0
- package/src/components/prototypes/prototype-change-log-panel.tsx +207 -0
- package/src/components/prototypes/prototype-comment-provider.tsx +61 -0
- package/src/components/prototypes/prototype-comment-toolbar.tsx +65 -0
- package/src/components/prototypes/prototype-control.tsx +31 -0
- package/src/components/prototypes/prototype-controls.tsx +553 -0
- package/src/components/prototypes/prototype-create-exploration-modal.tsx +117 -0
- package/src/components/prototypes/prototype-create-state-modal.tsx +117 -0
- package/src/components/prototypes/prototype-default-state-map-page.tsx +66 -0
- package/src/components/prototypes/prototype-design-brief-modal.tsx +128 -0
- package/src/components/prototypes/prototype-design-brief-panel.tsx +525 -0
- package/src/components/prototypes/prototype-design-context-panel.tsx +65 -0
- package/src/components/prototypes/prototype-floating-pill.module.scss +1341 -0
- package/src/components/prototypes/prototype-mobbin-gallery.tsx +330 -0
- package/src/components/prototypes/prototype-reference-docs.tsx +222 -0
- package/src/components/prototypes/prototype-review-chrome.module.scss +630 -0
- package/src/components/prototypes/prototype-review-chrome.tsx +1241 -0
- package/src/components/prototypes/prototype-review-dropdown-menu-item.tsx +1 -0
- package/src/components/prototypes/prototype-review-dropdown-menu-separator.tsx +1 -0
- package/src/components/prototypes/prototype-review-panel-menu-item.tsx +1 -0
- package/src/components/prototypes/prototype-review-panel-menu-separator.tsx +1 -0
- package/src/components/prototypes/prototype-review-panel-select.tsx +4 -0
- package/src/components/prototypes/prototype-review-sidebar.tsx +167 -0
- package/src/components/prototypes/prototype-share-link-restore.tsx +75 -0
- package/src/components/prototypes/prototype-share-mode.tsx +206 -0
- package/src/components/prototypes/prototype-spec-panel-content.tsx +538 -0
- package/src/components/prototypes/prototype-state-canvas-overlay.module.scss +336 -0
- package/src/components/prototypes/prototype-state-canvas-overlay.tsx +1023 -0
- package/src/components/prototypes/prototype-state-canvas.tsx +38 -0
- package/src/components/prototypes/prototype-state-screenshot-preview.tsx +47 -0
- package/src/components/prototypes/prototype-target.tsx +120 -0
- package/src/components/prototypes/prototype-tweak-highlight.tsx +132 -0
- package/src/components/prototypes/prototype-tweaks.tsx +48 -0
- package/src/components/prototypes/prototype-variant-explorer.tsx +347 -0
- package/src/components/prototypes/prototype-variant-rationale-panel.tsx +49 -0
- package/src/components/prototypes/prototype-variant-tabs.tsx +207 -0
- package/src/components/prototypes/prototype-vercel-preview-modal.tsx +120 -0
- package/src/components/prototypes/state-map-annotation-tooltip.module.scss +89 -0
- package/src/components/prototypes/state-map-annotation-tooltip.tsx +137 -0
- package/src/components/prototypes/state-map-wireframe-highlight.module.scss +25 -0
- package/src/components/prototypes/state-map-wireframe-highlight.tsx +82 -0
- package/src/components/shell/prototype-gallery-shell.tsx +79 -0
- package/src/components/shell/prototype-screenshot-capture.tsx +45 -0
- package/src/components/shell/prototype-shell.module.scss +194 -0
- package/src/components/shell/prototype-shell.tsx +160 -0
- package/src/components/shell/prototype-state-screenshot-capture.tsx +68 -0
- package/src/components/ui/button.tsx +58 -0
- package/src/components/ui/dialog.module.scss +81 -0
- package/src/components/ui/dialog.tsx +127 -0
- package/src/components/ui/dropdown-menu.tsx +200 -0
- package/src/components/ui/input.tsx +22 -0
- package/src/components/ui/label.tsx +26 -0
- package/src/components/ui/option-select.tsx +81 -0
- package/src/components/ui/scroll-area.tsx +48 -0
- package/src/components/ui/separator.tsx +31 -0
- package/src/components/ui/slider.tsx +28 -0
- package/src/components/ui/switch.tsx +29 -0
- package/src/components/ui/tabs.tsx +55 -0
- package/src/components/ui/toggle-group.tsx +80 -0
- package/src/components/ui/tooltip.tsx +32 -0
- package/src/config/create-prototype-gallery-page.tsx +65 -0
- package/src/config/create-prototype-host-app.tsx +121 -0
- package/src/config/create-prototype-page.tsx +41 -0
- package/src/config/create-prototype-site-layout.tsx +28 -0
- package/src/config/define-prototype-config.ts +7 -0
- package/src/config/prototype-icon.tsx +25 -0
- package/src/config/prototype-site-layout-client.tsx +35 -0
- package/src/config/with-prototype.ts +20 -0
- package/src/index.ts +303 -0
- package/src/lib/pr-split/build-pr-agent-prompt.ts +68 -0
- package/src/lib/pr-split/build-pr-split-prototype-url.ts +12 -0
- package/src/lib/pr-split/pr-split-highlight.ts +6 -0
- package/src/lib/pr-split/pr-split-types.ts +58 -0
- package/src/lib/pr-split/resolve-source-preview-url.ts +45 -0
- package/src/lib/pr-split/use-pr-vercel-previews.ts +69 -0
- package/src/lib/prototype-comments/core/annotation-channel.ts +41 -0
- package/src/lib/prototype-comments/core/annotation-status.ts +60 -0
- package/src/lib/prototype-comments/core/annotation-target.ts +567 -0
- package/src/lib/prototype-comments/core/capture-theme.ts +41 -0
- package/src/lib/prototype-comments/core/capture.ts +11 -0
- package/src/lib/prototype-comments/core/comment-capture-blocked.ts +47 -0
- package/src/lib/prototype-comments/core/comment-threads.ts +52 -0
- package/src/lib/prototype-comments/core/element-identification.ts +615 -0
- package/src/lib/prototype-comments/core/export.ts +35 -0
- package/src/lib/prototype-comments/core/freeze-animations.ts +266 -0
- package/src/lib/prototype-comments/core/identify-element.ts +76 -0
- package/src/lib/prototype-comments/core/normalize-viewport.ts +35 -0
- package/src/lib/prototype-comments/core/react-detection.ts +704 -0
- package/src/lib/prototype-comments/core/restore.ts +7 -0
- package/src/lib/prototype-comments/core/screenshot.ts +428 -0
- package/src/lib/prototype-comments/core/source-location.ts +906 -0
- package/src/lib/prototype-comments/core/storage.ts +80 -0
- package/src/lib/prototype-comments/core/types.ts +79 -0
- package/src/lib/prototype-comments/core/validation.ts +17 -0
- package/src/lib/prototype-comments/hooks/useLayoutShift.ts +61 -0
- package/src/lib/prototype-comments/index.ts +58 -0
- package/src/lib/prototype-comments/react/CommentCaptureToolbar.tsx +1398 -0
- package/src/lib/prototype-comments/react/CommentProvider.tsx +298 -0
- package/src/lib/prototype-comments/scss.d.ts +10 -0
- package/src/lib/prototype-comments/ui/CommentAnnotationOverlay.tsx +253 -0
- package/src/lib/prototype-comments/ui/CommentDetailPage.tsx +56 -0
- package/src/lib/prototype-comments/ui/CommentHeaderCount.tsx +28 -0
- package/src/lib/prototype-comments/ui/CommentThread.tsx +331 -0
- package/src/lib/prototype-comments/ui/CommentsGrid.tsx +780 -0
- package/src/lib/prototype-comments/ui/CommentsListPage.tsx +25 -0
- package/src/lib/prototype-comments/ui/CommentsSidebar.tsx +77 -0
- package/src/lib/prototype-comments/ui/annotation-marker/index.tsx +200 -0
- package/src/lib/prototype-comments/ui/annotation-marker/styles.module.scss +194 -0
- package/src/lib/prototype-comments/ui/annotation-popup/index.tsx +335 -0
- package/src/lib/prototype-comments/ui/annotation-popup/styles.module.scss +469 -0
- package/src/lib/prototype-comments/ui/capture-styles.module.scss +2225 -0
- package/src/lib/prototype-comments/ui/comment-highlight.ts +48 -0
- package/src/lib/prototype-comments/ui/comment-thread.module.scss +203 -0
- package/src/lib/prototype-comments/ui/comments-grid-card.module.scss +253 -0
- package/src/lib/prototype-comments/ui/comments-sidebar.module.scss +123 -0
- package/src/lib/prototype-comments/ui/icon-transitions.module.scss +51 -0
- package/src/lib/prototype-comments/ui/icons.tsx +1086 -0
- package/src/lib/prototype-comments/ui/is-comment-detail-path.ts +7 -0
- package/src/lib/prototypes/capture-prototype-viewport.ts +32 -0
- package/src/lib/prototypes/changelog-meta-context.tsx +162 -0
- package/src/lib/prototypes/changelog-meta-storage.ts +62 -0
- package/src/lib/prototypes/changelog-meta.ts +95 -0
- package/src/lib/prototypes/create-prototype-registry.ts +74 -0
- package/src/lib/prototypes/create-state-screenshot-thumbnail.ts +46 -0
- package/src/lib/prototypes/design-exploration-default-storage.ts +68 -0
- package/src/lib/prototypes/design-exploration-default.ts +51 -0
- package/src/lib/prototypes/design-exploration-types.ts +203 -0
- package/src/lib/prototypes/prototype-comment-registry.tsx +145 -0
- package/src/lib/prototypes/prototype-comment-review-bridge.tsx +40 -0
- package/src/lib/prototypes/prototype-comment-review-state.ts +57 -0
- package/src/lib/prototypes/prototype-component-registry.ts +40 -0
- package/src/lib/prototypes/prototype-config-types.ts +34 -0
- package/src/lib/prototypes/prototype-preview-state-registry.ts +443 -0
- package/src/lib/prototypes/prototype-preview-state-types.ts +89 -0
- package/src/lib/prototypes/prototype-review-context.tsx +905 -0
- package/src/lib/prototypes/prototype-review-url.ts +134 -0
- package/src/lib/prototypes/prototype-share-link.ts +175 -0
- package/src/lib/prototypes/prototype-state-canvas-constants.ts +118 -0
- package/src/lib/prototypes/prototype-state-canvas-types.ts +159 -0
- package/src/lib/prototypes/prototype-state-screenshot.ts +39 -0
- package/src/lib/prototypes/prototype-tweak-registry.ts +96 -0
- package/src/lib/prototypes/prototype-tweak-types.ts +31 -0
- package/src/lib/prototypes/reference-docs.ts +137 -0
- package/src/lib/prototypes/screenshot-manifest.ts +33 -0
- package/src/lib/prototypes/screenshot-src.ts +7 -0
- package/src/lib/prototypes/share-command.ts +8 -0
- package/src/lib/prototypes/state-map-annotation.ts +70 -0
- package/src/lib/prototypes/use-design-exploration-default.ts +114 -0
- package/src/lib/prototypes/use-persisted-local-state.ts +140 -0
- package/src/lib/prototypes/use-prototype-comments.ts +63 -0
- package/src/lib/prototypes/use-prototype-mobile-viewport-frame.ts +46 -0
- package/src/lib/prototypes/use-prototype-state-screenshot-src.ts +71 -0
- package/src/lib/prototypes/use-prototype-tool-theme.tsx +115 -0
- package/src/lib/prototypes/use-prototype-viewport-frame.ts +34 -0
- package/src/lib/prototypes/use-register-prototype-reference-docs.ts +16 -0
- package/src/lib/prototypes/use-snap-corner-position.ts +417 -0
- package/src/lib/prototypes/use-toolbar-hover-panel.ts +98 -0
- package/src/lib/prototypes/variant-set-lucide-icon.tsx +55 -0
- package/src/lib/tool-portal.ts +33 -0
- package/src/lib/use-copy-to-clipboard.ts +81 -0
- package/src/lib/utils.ts +6 -0
- package/src/lib/vercel-preview/parse-vercel-github-comment.ts +81 -0
- package/src/server/create-host-api-route.ts +100 -0
- package/src/server/create-prototype-api-routes.ts +428 -0
- package/src/server/gallery/create-gallery-api.ts +56 -0
- package/src/server/gallery/folders-route.ts +156 -0
- package/src/server/gallery/gallery-env.ts +39 -0
- package/src/server/gallery/gallery-route.ts +150 -0
- package/src/server/gallery/gallery-types.ts +15 -0
- package/src/server/gallery/image-route.ts +59 -0
- package/src/server/gallery/item-route.ts +92 -0
- package/src/server/pr-vercel-preview-route.ts +162 -0
- package/src/server/redis/client.ts +55 -0
- package/src/server/redis/prototype-changelog-meta.ts +31 -0
- package/src/server/redis/prototype-comments.ts +92 -0
- package/src/server/redis/prototype-design-exploration-default.ts +32 -0
- package/src/server.ts +51 -0
- package/src/styles/globals.css +624 -0
- package/tsconfig.json +19 -0
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "proto-plugin",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"registry": "https://registry.npmjs.org"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/maayanalbert/proto-plugin.git",
|
|
11
|
+
"directory": "packages/prototype"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"src",
|
|
15
|
+
"scripts",
|
|
16
|
+
"README.md",
|
|
17
|
+
"AGENTS.md",
|
|
18
|
+
"components.json",
|
|
19
|
+
"tsconfig.json"
|
|
20
|
+
],
|
|
21
|
+
"main": "./src/index.ts",
|
|
22
|
+
"types": "./src/index.ts",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": "./src/index.ts",
|
|
25
|
+
"./config": "./src/config/define-prototype-config.ts",
|
|
26
|
+
"./config/prototype-icon": "./src/config/prototype-icon.tsx",
|
|
27
|
+
"./app": "./src/app.ts",
|
|
28
|
+
"./with-prototype": "./src/config/with-prototype.ts",
|
|
29
|
+
"./server": "./src/server.ts",
|
|
30
|
+
"./styles/globals.css": "./src/styles/globals.css"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"verify:prototype-ids": "node scripts/verify-prototype-component-ids.mjs",
|
|
34
|
+
"verify:prototype-preview-states": "node scripts/verify-prototype-preview-states.mjs",
|
|
35
|
+
"link-source": "./scripts/link-source.sh",
|
|
36
|
+
"sync-from-source": "./scripts/sync-from-source.sh",
|
|
37
|
+
"link-source-db": "./scripts/link-source-db.sh",
|
|
38
|
+
"share-prototype": "./scripts/share-prototype.sh",
|
|
39
|
+
"download-mobbin-references": "node scripts/download-mobbin-reference-images.mjs",
|
|
40
|
+
"publish-package": "./scripts/publish-package.sh"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"next": ">=15",
|
|
44
|
+
"react": ">=19",
|
|
45
|
+
"react-dom": ">=19"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@radix-ui/react-dialog": "^1.1.15",
|
|
49
|
+
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
50
|
+
"@radix-ui/react-label": "^2.1.8",
|
|
51
|
+
"@radix-ui/react-scroll-area": "^1.2.10",
|
|
52
|
+
"@radix-ui/react-select": "^2.2.6",
|
|
53
|
+
"@radix-ui/react-separator": "^1.1.8",
|
|
54
|
+
"@radix-ui/react-slider": "^1.3.6",
|
|
55
|
+
"@radix-ui/react-slot": "^1.2.4",
|
|
56
|
+
"@radix-ui/react-switch": "^1.2.6",
|
|
57
|
+
"@radix-ui/react-tabs": "^1.1.13",
|
|
58
|
+
"@radix-ui/react-toggle-group": "^1.1.11",
|
|
59
|
+
"@radix-ui/react-tooltip": "^1.2.8",
|
|
60
|
+
"@upstash/redis": "^1.38.0",
|
|
61
|
+
"@vercel/blob": "^2.0.0",
|
|
62
|
+
"@vercel/kv": "^2.0.0",
|
|
63
|
+
"class-variance-authority": "^0.7.1",
|
|
64
|
+
"clsx": "^2.1.0",
|
|
65
|
+
"html-to-image": "^1.11.13",
|
|
66
|
+
"lucide-react": "^0.543.0",
|
|
67
|
+
"modern-screenshot": "^4.6.0",
|
|
68
|
+
"sass": "^1.86.0",
|
|
69
|
+
"server-only": "^0.0.1",
|
|
70
|
+
"sonner": "^1.7.4",
|
|
71
|
+
"tailwind-merge": "^2.5.2"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetches full-resolution (1920w) Mobbin screen images for prototype references.
|
|
3
|
+
* MCP short URLs are ~768px — too small for the overview modal grid.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* pnpm download-mobbin-references -- --ids=id1,id2,id3
|
|
7
|
+
* pnpm download-mobbin-references -- --config=path/to/ids.json
|
|
8
|
+
*
|
|
9
|
+
* Config JSON shape: { "screenIds": ["uuid", ...] }
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
13
|
+
import path from "node:path";
|
|
14
|
+
import {
|
|
15
|
+
resolveHostRoot,
|
|
16
|
+
resolveToolRoot,
|
|
17
|
+
} from "./lib/resolve-host-root.mjs";
|
|
18
|
+
|
|
19
|
+
const toolRoot = resolveToolRoot(import.meta.url);
|
|
20
|
+
const hostRoot = resolveHostRoot(toolRoot);
|
|
21
|
+
const OUT_DIR = path.join(hostRoot, "public/prototypes/mobbin-references");
|
|
22
|
+
|
|
23
|
+
function parseArgs(argv) {
|
|
24
|
+
const idsFlag = argv.find((arg) => arg.startsWith("--ids="));
|
|
25
|
+
if (idsFlag) {
|
|
26
|
+
const ids = idsFlag
|
|
27
|
+
.slice("--ids=".length)
|
|
28
|
+
.split(",")
|
|
29
|
+
.map((id) => id.trim())
|
|
30
|
+
.filter(Boolean);
|
|
31
|
+
if (ids.length === 0) {
|
|
32
|
+
throw new Error("--ids requires at least one screen id");
|
|
33
|
+
}
|
|
34
|
+
return ids;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const configFlag = argv.find((arg) => arg.startsWith("--config="));
|
|
38
|
+
if (configFlag) {
|
|
39
|
+
return { configPath: configFlag.slice("--config=".length) };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
throw new Error(
|
|
43
|
+
"No screen ids provided. Pass --ids=id1,id2 or --config=path/to/ids.json",
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function loadScreenIds(argv) {
|
|
48
|
+
const parsed = parseArgs(argv);
|
|
49
|
+
if (Array.isArray(parsed)) return parsed;
|
|
50
|
+
|
|
51
|
+
const raw = await readFile(parsed.configPath, "utf8");
|
|
52
|
+
const config = JSON.parse(raw);
|
|
53
|
+
const ids = config.screenIds ?? config.ids;
|
|
54
|
+
if (!Array.isArray(ids) || ids.length === 0) {
|
|
55
|
+
throw new Error("Config must include a non-empty screenIds (or ids) array");
|
|
56
|
+
}
|
|
57
|
+
return ids;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function extractLargestSrcSetUrl(html) {
|
|
61
|
+
const srcSetMatch = html.match(/imageSrcSet="([^"]+)"/);
|
|
62
|
+
if (!srcSetMatch) return null;
|
|
63
|
+
|
|
64
|
+
const candidates = [];
|
|
65
|
+
const parts = srcSetMatch[1].split(/\s+/);
|
|
66
|
+
for (let i = 0; i < parts.length - 1; i += 2) {
|
|
67
|
+
const url = parts[i];
|
|
68
|
+
const width = parts[i + 1];
|
|
69
|
+
if (url?.startsWith("https://") && width?.endsWith("w")) {
|
|
70
|
+
candidates.push({ url, width: Number.parseInt(width, 10) });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
candidates.sort((a, b) => b.width - a.width);
|
|
75
|
+
return candidates[0]?.url ?? null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function downloadScreen(screenId) {
|
|
79
|
+
const pageUrl = `https://mobbin.com/explore/screens/${screenId}`;
|
|
80
|
+
const response = await fetch(pageUrl, {
|
|
81
|
+
headers: { "User-Agent": "prototype-tool/1.0" },
|
|
82
|
+
});
|
|
83
|
+
if (!response.ok) {
|
|
84
|
+
throw new Error(`${screenId}: page fetch failed (${response.status})`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const html = await response.text();
|
|
88
|
+
const imageUrl = extractLargestSrcSetUrl(html);
|
|
89
|
+
if (!imageUrl) {
|
|
90
|
+
throw new Error(`${screenId}: no srcset image found`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const imageResponse = await fetch(imageUrl);
|
|
94
|
+
if (!imageResponse.ok) {
|
|
95
|
+
throw new Error(`${screenId}: image fetch failed (${imageResponse.status})`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const buffer = Buffer.from(await imageResponse.arrayBuffer());
|
|
99
|
+
const outPath = path.join(OUT_DIR, `${screenId}.webp`);
|
|
100
|
+
await writeFile(outPath, buffer);
|
|
101
|
+
console.log(`Saved ${outPath} (${buffer.length} bytes)`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const screenIds = await loadScreenIds(process.argv.slice(2));
|
|
105
|
+
|
|
106
|
+
await mkdir(OUT_DIR, { recursive: true });
|
|
107
|
+
|
|
108
|
+
for (const screenId of screenIds) {
|
|
109
|
+
await downloadScreen(screenId);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
console.log("Done.");
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Host-owned sync/link config (TEMPLATE).
|
|
4
|
+
#
|
|
5
|
+
# Copy this to the host repo root as `prototype.sync.config.sh` and fill in
|
|
6
|
+
# the values for YOUR app. The prototype package reads this file so that no
|
|
7
|
+
# host-specific file names, component customizations, or source-app env var
|
|
8
|
+
# names ever live inside the package itself.
|
|
9
|
+
#
|
|
10
|
+
# All paths are relative to the repo root and are mirrored 1:1 between the
|
|
11
|
+
# source app and this host (e.g. source `src/lib/utils.ts` -> host
|
|
12
|
+
# `src/lib/utils.ts`).
|
|
13
|
+
|
|
14
|
+
# --- pnpm sync-from-source -------------------------------------------------
|
|
15
|
+
|
|
16
|
+
# Single files to copy from the source app into this host.
|
|
17
|
+
SYNC_FILES=(
|
|
18
|
+
"src/app/globals.css"
|
|
19
|
+
# "src/lib/utils.ts"
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
# Directories to copy recursively (contents merged into the host dir).
|
|
23
|
+
SYNC_DIRS=(
|
|
24
|
+
# "src/components/ui"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# Globs to copy (each glob's parent dir is the destination).
|
|
28
|
+
SYNC_GLOBS=(
|
|
29
|
+
# "public/fonts/*.woff2"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# Reminder list printed after a sync: files this host has customized beyond
|
|
33
|
+
# the source version, which the blanket copy overwrites and you must re-apply.
|
|
34
|
+
# Leave empty if the host does not diverge from source.
|
|
35
|
+
SYNC_LOCAL_EXTENSIONS=(
|
|
36
|
+
# "my-component (local variant + semantic token classes)"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# --- pnpm link-source-db ---------------------------------------------------
|
|
40
|
+
|
|
41
|
+
# Env var names to copy from the source app's .env.local into this host's.
|
|
42
|
+
SOURCE_DB_ENV_VARS=(
|
|
43
|
+
# "MY_SERVICE_URL"
|
|
44
|
+
# "MY_SERVICE_KEY"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# Optional: console URL printed after a successful link.
|
|
48
|
+
SOURCE_DB_CONSOLE_URL=""
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Locate and source the host-owned sync/link config.
|
|
4
|
+
#
|
|
5
|
+
# The prototype package is host-agnostic: it must not name host files,
|
|
6
|
+
# host component customizations, or source-app env vars. All of that lives
|
|
7
|
+
# in a host-root config file owned by the consuming app.
|
|
8
|
+
#
|
|
9
|
+
# Resolution: PROTOTYPE_SYNC_CONFIG (env) > $HOST_ROOT/prototype.sync.config.sh
|
|
10
|
+
#
|
|
11
|
+
# See scripts/lib/host-config.example.sh for the expected shape.
|
|
12
|
+
load_host_config() {
|
|
13
|
+
local host_root="$1"
|
|
14
|
+
local config="${PROTOTYPE_SYNC_CONFIG:-$host_root/prototype.sync.config.sh}"
|
|
15
|
+
|
|
16
|
+
if [[ ! -f "$config" ]]; then
|
|
17
|
+
echo "Host sync config not found at: $config" >&2
|
|
18
|
+
echo "Create it in the host repo root. Template:" >&2
|
|
19
|
+
echo " packages/prototype/scripts/lib/host-config.example.sh" >&2
|
|
20
|
+
return 1
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
# shellcheck disable=SC1090
|
|
24
|
+
source "$config"
|
|
25
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
export function resolveHostRoot(toolRootPath) {
|
|
6
|
+
let dir = path.resolve(toolRootPath, "..");
|
|
7
|
+
while (dir !== path.dirname(dir)) {
|
|
8
|
+
if (fs.existsSync(path.join(dir, "prototype.config.ts"))) {
|
|
9
|
+
return dir;
|
|
10
|
+
}
|
|
11
|
+
dir = path.dirname(dir);
|
|
12
|
+
}
|
|
13
|
+
return path.resolve(toolRootPath, "..", "..");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function resolveToolRoot(importMetaUrl) {
|
|
17
|
+
return path.resolve(path.dirname(fileURLToPath(importMetaUrl)), "..");
|
|
18
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Walk up from the plugin root until we find prototype.config.ts (host repo root).
|
|
4
|
+
resolve_host_root() {
|
|
5
|
+
local tool_root="$1"
|
|
6
|
+
local dir
|
|
7
|
+
|
|
8
|
+
dir="$(cd "$tool_root/.." && pwd)"
|
|
9
|
+
while [[ "$dir" != "/" ]]; do
|
|
10
|
+
if [[ -f "$dir/prototype.config.ts" ]]; then
|
|
11
|
+
printf '%s' "$dir"
|
|
12
|
+
return 0
|
|
13
|
+
fi
|
|
14
|
+
dir="$(dirname "$dir")"
|
|
15
|
+
done
|
|
16
|
+
|
|
17
|
+
# Fallback for the standard workspace layout: host/packages/prototype
|
|
18
|
+
(cd "$tool_root/../.." && pwd)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# Resolve source app path: SOURCE (shell) > SOURCE_PATH (env) > .env.local > source/ symlink
|
|
22
|
+
resolve_source_path() {
|
|
23
|
+
local root="$1"
|
|
24
|
+
local raw="${SOURCE:-${SOURCE_PATH:-}}"
|
|
25
|
+
|
|
26
|
+
if [[ -z "$raw" && -f "$root/.env.local" ]]; then
|
|
27
|
+
raw="$(
|
|
28
|
+
grep -E '^SOURCE_PATH=' "$root/.env.local" | tail -1 | cut -d= -f2- \
|
|
29
|
+
| sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' \
|
|
30
|
+
-e 's/^"//' -e 's/"$//' -e "s/^'//" -e "s/'$//"
|
|
31
|
+
)"
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
if [[ -z "$raw" && -L "$root/source" ]]; then
|
|
35
|
+
raw="$(readlink "$root/source")"
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
if [[ -z "$raw" ]]; then
|
|
39
|
+
return 1
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
raw="${raw/#\~/$HOME}"
|
|
43
|
+
|
|
44
|
+
if [[ "$raw" != /* ]]; then
|
|
45
|
+
raw="$root/$raw"
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
(cd "$raw" 2>/dev/null && pwd) || return 1
|
|
49
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
TOOL_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
5
|
+
# shellcheck source=lib/source-path.sh
|
|
6
|
+
source "$TOOL_ROOT/scripts/lib/source-path.sh"
|
|
7
|
+
# shellcheck source=lib/host-config.sh
|
|
8
|
+
source "$TOOL_ROOT/scripts/lib/host-config.sh"
|
|
9
|
+
HOST_ROOT="$(resolve_host_root "$TOOL_ROOT")"
|
|
10
|
+
|
|
11
|
+
if ! load_host_config "$HOST_ROOT"; then
|
|
12
|
+
exit 1
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
if [[ "${SOURCE_DB_ENV_VARS+set}" != set || "${#SOURCE_DB_ENV_VARS[@]}" -eq 0 ]]; then
|
|
16
|
+
echo "No SOURCE_DB_ENV_VARS configured in the host sync config." >&2
|
|
17
|
+
echo "Add the env var names to copy from the source app to prototype.sync.config.sh." >&2
|
|
18
|
+
exit 1
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
TARGET="${1:-}"
|
|
22
|
+
if [[ -z "$TARGET" ]]; then
|
|
23
|
+
if ! TARGET="$(resolve_source_path "$HOST_ROOT")"; then
|
|
24
|
+
echo "Set SOURCE_PATH in .env.local (see .env.example), or pass a path:" >&2
|
|
25
|
+
echo " pnpm link-source-db /path/to/source-app" >&2
|
|
26
|
+
exit 1
|
|
27
|
+
fi
|
|
28
|
+
elif [[ "$TARGET" != /* ]]; then
|
|
29
|
+
TARGET="$HOST_ROOT/$TARGET"
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
SOURCE_ENV="$TARGET/.env.local"
|
|
33
|
+
LOCAL_ENV="$HOST_ROOT/.env.local"
|
|
34
|
+
|
|
35
|
+
if [[ ! -d "$TARGET" ]]; then
|
|
36
|
+
echo "Source app not found at: $TARGET" >&2
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
if [[ ! -f "$SOURCE_ENV" ]]; then
|
|
41
|
+
echo "Source env file not found at: $SOURCE_ENV" >&2
|
|
42
|
+
echo "Create it in the source app repo (see source app local dev docs)." >&2
|
|
43
|
+
exit 1
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
extract_env() {
|
|
47
|
+
local file="$1"
|
|
48
|
+
local key="$2"
|
|
49
|
+
local line value
|
|
50
|
+
|
|
51
|
+
line="$(grep -E "^(#\s*)?${key}=" "$file" | tail -1 || true)"
|
|
52
|
+
if [[ -z "$line" ]]; then
|
|
53
|
+
return 1
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
value="${line#"${line%%=*}"=}"
|
|
57
|
+
value="${value#"${value%%[![:space:]]*}"}"
|
|
58
|
+
value="${value%"${value##*[![:space:]]}"}"
|
|
59
|
+
value="${value#"${value%%[![:space:]]*}"}"
|
|
60
|
+
value="${value%"${value##*[![:space:]]}"}"
|
|
61
|
+
|
|
62
|
+
if [[ "$value" == \"*\" && "$value" == *\" ]]; then
|
|
63
|
+
value="${value:1:${#value}-2}"
|
|
64
|
+
elif [[ "$value" == \'*\' && "$value" == *\' ]]; then
|
|
65
|
+
value="${value:1:${#value}-2}"
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
printf '%s' "$value"
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
upsert_env() {
|
|
72
|
+
local file="$1"
|
|
73
|
+
local key="$2"
|
|
74
|
+
local value="$3"
|
|
75
|
+
local tmp escaped
|
|
76
|
+
|
|
77
|
+
escaped="${value//\\/\\\\}"
|
|
78
|
+
escaped="${escaped//\"/\\\"}"
|
|
79
|
+
|
|
80
|
+
if [[ ! -f "$file" ]]; then
|
|
81
|
+
printf '%s="%s"\n' "$key" "$escaped" >>"$file"
|
|
82
|
+
return
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
tmp="$(mktemp)"
|
|
86
|
+
if grep -q "^${key}=" "$file"; then
|
|
87
|
+
awk -v key="$key" -v value="$escaped" '
|
|
88
|
+
BEGIN { updated = 0 }
|
|
89
|
+
$0 ~ "^" key "=" {
|
|
90
|
+
print key "=\"" value "\""
|
|
91
|
+
updated = 1
|
|
92
|
+
next
|
|
93
|
+
}
|
|
94
|
+
{ print }
|
|
95
|
+
END {
|
|
96
|
+
if (!updated) {
|
|
97
|
+
print key "=\"" value "\""
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
' "$file" >"$tmp"
|
|
101
|
+
else
|
|
102
|
+
cp "$file" "$tmp"
|
|
103
|
+
printf '\n%s="%s"\n' "$key" "$escaped" >>"$tmp"
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
mv "$tmp" "$file"
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
linked=0
|
|
110
|
+
for key in "${SOURCE_DB_ENV_VARS[@]}"; do
|
|
111
|
+
if value="$(extract_env "$SOURCE_ENV" "$key")"; then
|
|
112
|
+
upsert_env "$LOCAL_ENV" "$key" "$value"
|
|
113
|
+
echo "Linked $key from $SOURCE_ENV"
|
|
114
|
+
linked=$((linked + 1))
|
|
115
|
+
fi
|
|
116
|
+
done
|
|
117
|
+
|
|
118
|
+
if [[ "$linked" -eq 0 ]]; then
|
|
119
|
+
echo "No configured vars found in $SOURCE_ENV." >&2
|
|
120
|
+
echo "Uncomment or add the SOURCE_DB_ENV_VARS entries in the source app's .env.local first." >&2
|
|
121
|
+
exit 1
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
if [[ -n "${SOURCE_DB_CONSOLE_URL:-}" ]]; then
|
|
125
|
+
echo "Updated $LOCAL_ENV ($linked vars). Console: $SOURCE_DB_CONSOLE_URL"
|
|
126
|
+
else
|
|
127
|
+
echo "Updated $LOCAL_ENV ($linked vars)."
|
|
128
|
+
fi
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
TOOL_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
5
|
+
# shellcheck source=lib/source-path.sh
|
|
6
|
+
source "$TOOL_ROOT/scripts/lib/source-path.sh"
|
|
7
|
+
HOST_ROOT="$(resolve_host_root "$TOOL_ROOT")"
|
|
8
|
+
|
|
9
|
+
LINK="$HOST_ROOT/source"
|
|
10
|
+
TARGET="${1:-}"
|
|
11
|
+
|
|
12
|
+
if [[ -z "$TARGET" ]]; then
|
|
13
|
+
if ! TARGET="$(resolve_source_path "$HOST_ROOT")"; then
|
|
14
|
+
echo "Set SOURCE_PATH in .env.local (see .env.example), or pass a path:" >&2
|
|
15
|
+
echo " pnpm link-source /path/to/source-app" >&2
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
elif [[ "$TARGET" != /* ]]; then
|
|
19
|
+
TARGET="$HOST_ROOT/$TARGET"
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
if [[ ! -d "$TARGET" ]]; then
|
|
23
|
+
echo "Source app not found at: $TARGET" >&2
|
|
24
|
+
exit 1
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
if [[ -L "$LINK" ]]; then
|
|
28
|
+
current="$(readlink "$LINK")"
|
|
29
|
+
if [[ "$current" == "$TARGET" ]] || [[ "$(cd "$HOST_ROOT" && cd "$current" 2>/dev/null && pwd)" == "$TARGET" ]]; then
|
|
30
|
+
echo "source/ already linked to: $TARGET"
|
|
31
|
+
exit 0
|
|
32
|
+
fi
|
|
33
|
+
rm "$LINK"
|
|
34
|
+
elif [[ -e "$LINK" ]]; then
|
|
35
|
+
echo "source/ exists but is not a symlink — remove it first" >&2
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
ln -s "$TARGET" "$LINK"
|
|
40
|
+
echo "Linked source/ -> $TARGET"
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
TOOL_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
5
|
+
cd "$TOOL_ROOT"
|
|
6
|
+
|
|
7
|
+
REGISTRY="https://registry.npmjs.org"
|
|
8
|
+
DRY_RUN=0
|
|
9
|
+
TAG="latest"
|
|
10
|
+
SKIP_VERIFY=0
|
|
11
|
+
OTP=""
|
|
12
|
+
|
|
13
|
+
usage() {
|
|
14
|
+
cat <<EOF
|
|
15
|
+
Usage: $(basename "$0") [options]
|
|
16
|
+
|
|
17
|
+
Publish proto-plugin to npm.
|
|
18
|
+
|
|
19
|
+
Options:
|
|
20
|
+
--dry-run Validate the tarball without publishing
|
|
21
|
+
--tag <tag> npm dist-tag (default: latest)
|
|
22
|
+
--otp <code> One-time password from your authenticator app
|
|
23
|
+
--skip-verify Skip pre-publish verification scripts
|
|
24
|
+
-h, --help Show this help message
|
|
25
|
+
|
|
26
|
+
Examples:
|
|
27
|
+
pnpm publish-package
|
|
28
|
+
pnpm publish-package --otp 123456
|
|
29
|
+
pnpm publish-package --dry-run
|
|
30
|
+
pnpm publish-package --tag next
|
|
31
|
+
|
|
32
|
+
Requires: npm login (npm whoami must succeed).
|
|
33
|
+
EOF
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
while [[ $# -gt 0 ]]; do
|
|
37
|
+
case "$1" in
|
|
38
|
+
--dry-run)
|
|
39
|
+
DRY_RUN=1
|
|
40
|
+
shift
|
|
41
|
+
;;
|
|
42
|
+
--tag)
|
|
43
|
+
TAG="${2:?Missing value for --tag}"
|
|
44
|
+
shift 2
|
|
45
|
+
;;
|
|
46
|
+
--skip-verify)
|
|
47
|
+
SKIP_VERIFY=1
|
|
48
|
+
shift
|
|
49
|
+
;;
|
|
50
|
+
--otp)
|
|
51
|
+
OTP="${2:?Missing value for --otp}"
|
|
52
|
+
shift 2
|
|
53
|
+
;;
|
|
54
|
+
-h | --help)
|
|
55
|
+
usage
|
|
56
|
+
exit 0
|
|
57
|
+
;;
|
|
58
|
+
*)
|
|
59
|
+
echo "Unknown option: $1" >&2
|
|
60
|
+
usage >&2
|
|
61
|
+
exit 1
|
|
62
|
+
;;
|
|
63
|
+
esac
|
|
64
|
+
done
|
|
65
|
+
|
|
66
|
+
if [[ "$(node -pe "require('./package.json').private === true")" == "true" ]]; then
|
|
67
|
+
echo "package.json has \"private\": true, which blocks npm publish." >&2
|
|
68
|
+
echo "Remove it or set \"private\": false before publishing." >&2
|
|
69
|
+
exit 1
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
if ! npm whoami --registry "$REGISTRY" >/dev/null 2>&1; then
|
|
73
|
+
echo "Not logged in to npm. Run: npm login" >&2
|
|
74
|
+
exit 1
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
find_host_with_prototypes() {
|
|
78
|
+
local dir="$TOOL_ROOT/.."
|
|
79
|
+
while [[ "$dir" != "/" ]]; do
|
|
80
|
+
if [[ -f "$dir/prototype.config.ts" && -d "$dir/src/prototypes" ]]; then
|
|
81
|
+
echo "$dir"
|
|
82
|
+
return 0
|
|
83
|
+
fi
|
|
84
|
+
dir="$(dirname "$dir")"
|
|
85
|
+
done
|
|
86
|
+
return 1
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if [[ "$SKIP_VERIFY" -eq 0 ]]; then
|
|
90
|
+
if host_root="$(find_host_with_prototypes)"; then
|
|
91
|
+
echo "Running verification scripts against $host_root..."
|
|
92
|
+
npm run verify:prototype-ids
|
|
93
|
+
npm run verify:prototype-preview-states
|
|
94
|
+
else
|
|
95
|
+
echo "Skipping verification (no host app with prototypes found)."
|
|
96
|
+
fi
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
PACKAGE_NAME="$(node -pe "require('./package.json').name")"
|
|
100
|
+
PACKAGE_VERSION="$(node -pe "require('./package.json').version")"
|
|
101
|
+
|
|
102
|
+
echo "Publishing ${PACKAGE_NAME}@${PACKAGE_VERSION}"
|
|
103
|
+
echo "Registry: ${REGISTRY}"
|
|
104
|
+
echo "Access: public (unscoped)"
|
|
105
|
+
|
|
106
|
+
PUBLISH_ARGS=(--registry "$REGISTRY" --tag "$TAG")
|
|
107
|
+
|
|
108
|
+
if [[ -n "$OTP" ]]; then
|
|
109
|
+
PUBLISH_ARGS+=(--otp "$OTP")
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
if [[ "$DRY_RUN" -eq 1 ]]; then
|
|
113
|
+
PUBLISH_ARGS+=(--dry-run)
|
|
114
|
+
echo "Dry run — tarball will not be uploaded."
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
env -u NPM_CONFIG_REGISTRY -u NPM_CONFIG_CAFILE \
|
|
118
|
+
npm publish "${PUBLISH_ARGS[@]}" || {
|
|
119
|
+
status=$?
|
|
120
|
+
if [[ "$DRY_RUN" -eq 0 && "$status" -ne 0 ]]; then
|
|
121
|
+
echo >&2
|
|
122
|
+
echo "Publish failed." >&2
|
|
123
|
+
if [[ "$PACKAGE_NAME" == @*/* ]]; then
|
|
124
|
+
scope="${PACKAGE_NAME%%/*}"
|
|
125
|
+
scope="${scope#@}"
|
|
126
|
+
whoami="$(npm whoami --registry "$REGISTRY" 2>/dev/null || true)"
|
|
127
|
+
echo "Logged in as: ${whoami:-unknown}" >&2
|
|
128
|
+
echo "Package scope: @${scope}" >&2
|
|
129
|
+
if [[ -n "$whoami" && "$whoami" != "$scope" ]]; then
|
|
130
|
+
echo >&2
|
|
131
|
+
echo "npm often returns 404 when your account cannot publish to this scope." >&2
|
|
132
|
+
echo "Fix one of:" >&2
|
|
133
|
+
echo " 1. npm logout && npm login # sign in as the @${scope} npm user/org owner" >&2
|
|
134
|
+
echo " 2. Add @${whoami} to the @${scope} org at https://www.npmjs.com/settings/${scope}/members" >&2
|
|
135
|
+
echo " 3. Rename the package to @${whoami}/prototype in package.json" >&2
|
|
136
|
+
fi
|
|
137
|
+
fi
|
|
138
|
+
fi
|
|
139
|
+
exit "$status"
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if [[ "$DRY_RUN" -eq 0 ]]; then
|
|
143
|
+
echo "Published successfully."
|
|
144
|
+
echo "Install with:"
|
|
145
|
+
echo " npm install ${PACKAGE_NAME}@${PACKAGE_VERSION}"
|
|
146
|
+
echo " pnpm add ${PACKAGE_NAME}@${PACKAGE_VERSION}"
|
|
147
|
+
fi
|