@sky.ui.pro/core 0.0.6 → 0.0.7

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/CHANGELOG.md ADDED
@@ -0,0 +1,26 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@sky.ui.pro/core` are documented here.
4
+
5
+ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.0.7] - 2026-07-07
10
+
11
+ ### Changed
12
+
13
+ - **Breaking install flow:** removed npm `postinstall` and the `tar` dependency from the published stub. Run `npx sky.ui.pro install` after `npm install` to download and hydrate the licensed artifact.
14
+ - Stub `package.json` no longer ships `scripts/` in the npm tarball.
15
+ - Peer dependency on `@sky.ui/core` bumped to `^0.0.7`.
16
+
17
+ ### Added
18
+
19
+ - TypeScript stub declarations at `dist/stub/index.d.ts`.
20
+ - `CHANGELOG.md` and npm metadata (`keywords`, `author`, `engines`).
21
+
22
+ ## [0.0.6]
23
+
24
+ ### Added
25
+
26
+ - Initial npm stub with postinstall-based hydration (superseded in `0.0.7`).
package/README.md CHANGED
@@ -1,96 +1,107 @@
1
- # @sky.ui.pro/core
2
-
3
- Pro-tier Lit web components for Sky UI. Extends the free catalog with advanced components such as data tables, flow editors, and rich inputs.
4
-
5
- Requires an active Sky UI Pro subscription. Install alongside `@sky.ui/core` when your app uses both tiers.
6
-
7
- ## Install
8
-
9
- ```bash
10
- npx sky.ui.pro login
11
- npm install "@sky.ui.pro/core"
12
- ```
13
-
14
- > Quote scoped names (`"@sky.ui/…"`) — required in PowerShell. See [powershell-scoped-packages.md](https://gitlab.com/sky_ui/sky-ui/-/blob/main/docs/powershell-scoped-packages.md).
15
-
16
- For CI/CD, set `SKY_UI_AUTH_TOKEN` to your account's CI/CD token before `npm ci`.
17
-
18
- Manage tokens on your [Sky UI account](https://library.sky-ui.com/account). No `.npmrc` file is required.
19
-
20
- | Token | Use |
21
- |-------|-----|
22
- | Personal (`sk_pt_…`) | Local development and MCP |
23
- | CI/CD (`sk_ci_…`) | Pipelines (`SKY_UI_AUTH_TOKEN`) |
24
-
25
- Peer dependencies match `@sky.ui/core` (`lit`, and optional `@lit-labs/motion`, `@lit-labs/virtualizer`, `@lit/context`, `d3`, `three`).
26
-
27
- ## Quick start
28
-
29
- ```js
30
- import { SkyTable, SkyFlow } from '@sky.ui.pro/core';
31
- ```
32
-
33
- ```html
34
- <sky-table></sky-table>
35
- ```
36
-
37
- Import only the Pro components you use for tree-shaken production bundles.
38
-
39
- Per-component paths are also supported:
40
-
41
- ```js
42
- import '@sky.ui.pro/core/sky-table';
43
- ```
44
-
45
- ## Auto-import resolvers
46
-
47
- Use resolvers from `@sky.ui.pro/core/auto-import` with `unplugin-vue-components` or your bundler's component plugin, alongside the free-tier setup in [`@sky.ui/core`](https://www.npmjs.com/package/@sky.ui/core).
48
-
49
- ## Bundler plugins (Vite, Webpack, Rollup)
50
-
51
- Pro packages mirror the free-tier plugin surface. Bundler plugins auto-import components and **validate your access token at build/dev time** (no runtime checks in shipped apps).
52
-
53
- **Vite** (`@sky.ui.pro/core/vite`):
54
-
55
- ```js
56
- import { SkyUIProMainVitePlugin } from '@sky.ui.pro/core/vite';
57
-
58
- export default {
59
- plugins: [
60
- SkyUIProMainVitePlugin({
61
- mode: 'auto-import', // or 'vue' with unplugin-vue-components
62
- }),
63
- ],
64
- };
65
- ```
66
-
67
- **Webpack** (`@sky.ui.pro/core/webpack`): `SkyUIProMainWebpackPlugin()`
68
-
69
- **Rollup** (`@sky.ui.pro/core/rollup`): `SkyUIProMainRollupPlugin({ mode: 'auto-import' })`
70
-
71
- Vue / React Pro wrappers expose the same three bundlers at `@sky.ui.pro/vue/vite|webpack|rollup` and `@sky.ui.pro/react/vite|webpack|rollup`.
72
-
73
- For resolver-only setup, use `@sky.ui.pro/core/auto-import` with `unplugin-vue-components`, alongside [`@sky.ui/core`](https://www.npmjs.com/package/@sky.ui/core) bundler plugins for free components.
74
-
75
- ## Framework wrappers
76
-
77
- | Package | Description |
78
- |---------|-------------|
79
- | [`@sky.ui.pro/vue`](https://www.npmjs.com/package/@sky.ui.pro/vue) | Vue 3 SFC wrappers |
80
- | [`@sky.ui.pro/react`](https://www.npmjs.com/package/@sky.ui.pro/react) | React wrappers |
81
-
82
- Free-tier equivalents: [`@sky.ui/vue`](https://www.npmjs.com/package/@sky.ui/vue), [`@sky.ui/react`](https://www.npmjs.com/package/@sky.ui/react).
83
-
84
- ## Custom Elements Manifest
85
-
86
- Component metadata is published at `@sky.ui.pro/core/custom-elements.json`.
87
-
88
- ## Updates window
89
-
90
- Annual plans include one year of updates. You keep using versions released during your active window even after it ends; renew to receive newer releases.
91
-
92
- ## License
93
-
94
- [Sky UI Pro Commercial License](https://unpkg.com/@sky.ui.pro/core/LICENSE.md) — requires an active Sky UI Pro subscription.
95
-
96
- Documentation: [library.sky-ui.com](https://library.sky-ui.com)
1
+ # @sky.ui.pro/core
2
+
3
+ Pro-tier Lit web components for Sky UI. Extends the free catalog with advanced components such as data tables, flow editors, and rich inputs.
4
+
5
+ Requires an active Sky UI Pro subscription. Install alongside `@sky.ui/core` when your app uses both tiers.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npx sky.ui.pro login
11
+ npx sky.ui.pro install
12
+ ```
13
+
14
+ Or install manually, then hydrate:
15
+
16
+ ```bash
17
+ npm install "@sky.ui.pro/core"
18
+ npx sky.ui.pro install --framework=core
19
+ ```
20
+
21
+ > Quote scoped names (`"@sky.ui/…"`) — required in PowerShell. See [powershell-scoped-packages.md](https://gitlab.com/sky_ui/sky-ui/-/blob/main/docs/powershell-scoped-packages.md).
22
+
23
+ For CI/CD:
24
+
25
+ ```bash
26
+ SKY_UI_AUTH_TOKEN=sk_ci_… npx sky.ui.pro install --yes --framework=core
27
+ ```
28
+
29
+ Manage tokens on your [Sky UI account](https://library.sky-ui.com/account). No `.npmrc` file is required.
30
+
31
+ | Token | Use |
32
+ |-------|-----|
33
+ | Personal (`sk_pt_…`) | Local development and MCP |
34
+ | CI/CD (`sk_ci_…`) | Pipelines (`SKY_UI_AUTH_TOKEN`) |
35
+
36
+ Peer dependencies match `@sky.ui/core` (`lit`, and optional `@lit-labs/motion`, `@lit-labs/virtualizer`, `@lit/context`, `d3`, `three`).
37
+
38
+ ## Quick start
39
+
40
+ ```js
41
+ import { SkyTable, SkyFlow } from '@sky.ui.pro/core';
42
+ ```
43
+
44
+ ```html
45
+ <sky-table></sky-table>
46
+ ```
47
+
48
+ Import only the Pro components you use for tree-shaken production bundles.
49
+
50
+ Per-component paths are also supported:
51
+
52
+ ```js
53
+ import '@sky.ui.pro/core/sky-table';
54
+ ```
55
+
56
+ ## Auto-import resolvers
57
+
58
+ Use resolvers from `@sky.ui.pro/core/auto-import` with `unplugin-vue-components` or your bundler's component plugin, alongside the free-tier setup in [`@sky.ui/core`](https://www.npmjs.com/package/@sky.ui/core).
59
+
60
+ ## Bundler plugins (Vite, Webpack, Rollup)
61
+
62
+ Pro packages mirror the free-tier plugin surface. Bundler plugins auto-import components and **validate your access token at build/dev time** (no runtime checks in shipped apps).
63
+
64
+ **Vite** (`@sky.ui.pro/core/vite`):
65
+
66
+ ```js
67
+ import { SkyUIProMainVitePlugin } from '@sky.ui.pro/core/vite';
68
+
69
+ export default {
70
+ plugins: [
71
+ SkyUIProMainVitePlugin({
72
+ mode: 'auto-import', // or 'vue' with unplugin-vue-components
73
+ }),
74
+ ],
75
+ };
76
+ ```
77
+
78
+ **Webpack** (`@sky.ui.pro/core/webpack`): `SkyUIProMainWebpackPlugin()`
79
+
80
+ **Rollup** (`@sky.ui.pro/core/rollup`): `SkyUIProMainRollupPlugin({ mode: 'auto-import' })`
81
+
82
+ Vue / React Pro wrappers expose the same three bundlers at `@sky.ui.pro/vue/vite|webpack|rollup` and `@sky.ui.pro/react/vite|webpack|rollup`.
83
+
84
+ For resolver-only setup, use `@sky.ui.pro/core/auto-import` with `unplugin-vue-components`, alongside [`@sky.ui/core`](https://www.npmjs.com/package/@sky.ui/core) bundler plugins for free components.
85
+
86
+ ## Framework wrappers
87
+
88
+ | Package | Description |
89
+ |---------|-------------|
90
+ | [`@sky.ui.pro/vue`](https://www.npmjs.com/package/@sky.ui.pro/vue) | Vue 3 SFC wrappers |
91
+ | [`@sky.ui.pro/react`](https://www.npmjs.com/package/@sky.ui.pro/react) | React wrappers |
92
+
93
+ Free-tier equivalents: [`@sky.ui/vue`](https://www.npmjs.com/package/@sky.ui/vue), [`@sky.ui/react`](https://www.npmjs.com/package/@sky.ui/react).
94
+
95
+ ## Custom Elements Manifest
96
+
97
+ Component metadata is published at `@sky.ui.pro/core/custom-elements.json`.
98
+
99
+ ## Updates window
100
+
101
+ Annual plans include one year of updates. You keep using versions released during your active window even after it ends; renew to receive newer releases.
102
+
103
+ ## License
104
+
105
+ [Sky UI Pro Commercial License](https://unpkg.com/@sky.ui.pro/core/LICENSE.md) — requires an active Sky UI Pro subscription.
106
+
107
+ Documentation: [library.sky-ui.com](https://library.sky-ui.com)
@@ -0,0 +1,3 @@
1
+ /** Stub entry — run `npx sky.ui.pro install` for the full Pro package. */
2
+ declare const stub: Record<string, unknown>;
3
+ export default stub;
@@ -1,2 +1,2 @@
1
- /** Placeholder until postinstall hydrates the full package from the private registry. */
2
- export default {};
1
+ /** Placeholder until sky.ui.pro CLI hydrates the full package from the private registry. */
2
+ export default {};
package/package.json CHANGED
@@ -1,27 +1,34 @@
1
1
  {
2
2
  "name": "@sky.ui.pro/core",
3
- "version": "0.0.6",
4
- "description": "Sky UI Pro web components — installs full package via postinstall (online license).",
3
+ "version": "0.0.7",
4
+ "description": "Sky UI Pro web components — run npx sky.ui.pro install after npm install.",
5
+ "keywords": [
6
+ "sky-ui",
7
+ "pro",
8
+ "web-components",
9
+ "lit",
10
+ "design-system",
11
+ "ui"
12
+ ],
13
+ "author": "Sky UI",
14
+ "engines": {
15
+ "node": ">=18"
16
+ },
5
17
  "type": "module",
6
18
  "license": "SEE LICENSE IN LICENSE.md",
7
19
  "main": "./dist/stub/index.js",
20
+ "types": "./dist/stub/index.d.ts",
8
21
  "exports": {
9
22
  ".": "./dist/stub/index.js"
10
23
  },
11
24
  "files": [
12
- "scripts",
13
25
  "dist/stub",
14
26
  "README.md",
15
- "LICENSE.md"
27
+ "LICENSE.md",
28
+ "CHANGELOG.md"
16
29
  ],
17
- "scripts": {
18
- "postinstall": "node ./scripts/postinstall.mjs"
19
- },
20
- "dependencies": {
21
- "tar": "^7.4.3"
22
- },
23
30
  "peerDependencies": {
24
- "@sky.ui/core": "^0.0.6",
31
+ "@sky.ui/core": "^0.0.7",
25
32
  "lit": ">=3 <4"
26
33
  },
27
34
  "peerDependenciesMeta": {
@@ -1,81 +0,0 @@
1
- /**
2
- * Merge public npm stub manifest with GitLab artifact manifest after postinstall hydration.
3
- */
4
-
5
- export const ARTIFACT_MANIFEST_SIDECAR = ".sky-ui-pro-artifact-manifest.json";
6
-
7
- const PRO_ARTIFACT_PREFIX = "@sky.ui.pro-artifact/";
8
- const PRO_PUBLIC_PREFIX = "@sky.ui.pro/";
9
-
10
- /** Rename @sky.ui.pro-artifact/* deps to @sky.ui.pro/* for installed packages. */
11
- export function renameProArtifactDeps(deps) {
12
- if (!deps || typeof deps !== "object") return deps;
13
- const out = { ...deps };
14
- for (const [key, value] of Object.entries(out)) {
15
- if (key.startsWith(PRO_ARTIFACT_PREFIX)) {
16
- const next = `${PRO_PUBLIC_PREFIX}${key.slice(PRO_ARTIFACT_PREFIX.length)}`;
17
- if (!(next in out)) out[next] = value;
18
- delete out[key];
19
- }
20
- }
21
- return out;
22
- }
23
-
24
- /** True when exports already point at hydrated artifact paths (not stub-only). */
25
- export function hasHydratedExports(manifest) {
26
- const exp = manifest?.exports;
27
- if (!exp || typeof exp !== "object") return false;
28
- if (exp["./vite"] || exp["./webpack"] || exp["./rollup"] || exp["./license"]) return true;
29
- const root = exp["."];
30
- if (typeof root === "string") {
31
- return root.includes("dist/index") || (root.includes("/dist/") && !root.includes("/stub/"));
32
- }
33
- if (root && typeof root === "object") {
34
- const imp = root.import ?? root.default ?? root.module;
35
- return typeof imp === "string" && imp.includes("dist/index");
36
- }
37
- return false;
38
- }
39
-
40
- /**
41
- * Build installed package.json: artifact resolution surface + public stub identity.
42
- * @param {Record<string, unknown>} stub
43
- * @param {Record<string, unknown>} artifact
44
- */
45
- export function mergeHydratedManifest(stub, artifact) {
46
- const stubDeps = stub.dependencies && typeof stub.dependencies === "object" ? stub.dependencies : {};
47
- const tarVersion = stubDeps.tar;
48
-
49
- const merged = {
50
- name: stub.name,
51
- version: stub.version,
52
- description: stub.description ?? artifact.description,
53
- type: stub.type ?? artifact.type,
54
- license: stub.license ?? artifact.license,
55
- main: artifact.main,
56
- module: artifact.module,
57
- types: artifact.types,
58
- sideEffects: artifact.sideEffects,
59
- exports: artifact.exports,
60
- peerDependencies: {
61
- ...renameProArtifactDeps(artifact.peerDependencies),
62
- ...(stub.peerDependencies ?? {}),
63
- },
64
- dependencies: {
65
- ...renameProArtifactDeps(artifact.dependencies),
66
- ...(tarVersion ? { tar: tarVersion } : {}),
67
- },
68
- scripts: stub.scripts?.postinstall ? { postinstall: stub.scripts.postinstall } : {},
69
- skyUiPro: stub.skyUiPro,
70
- publishConfig: stub.publishConfig,
71
- repository: stub.repository,
72
- bugs: stub.bugs,
73
- homepage: stub.homepage,
74
- };
75
-
76
- if (artifact.peerDependenciesMeta && typeof artifact.peerDependenciesMeta === "object") {
77
- merged.peerDependenciesMeta = artifact.peerDependenciesMeta;
78
- }
79
-
80
- return merged;
81
- }
@@ -1,150 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Unified Sky UI Pro / CLI project `.env` loading.
4
- * Source of truth — synced to @sky.ui/cli and copied into @sky.ui.pro/* stubs on sync:pro-npm.
5
- *
6
- * Loads only `SKY_UI_*` keys. Shell env always wins (existing process.env is never overwritten).
7
- * Search order: INIT_CWD → npm local prefix → SKY_UI_PROJECT_ROOT → cwd → project roots.
8
- */
9
- import { access, readFile } from "node:fs/promises";
10
- import { dirname, join } from "node:path";
11
-
12
- export const SKY_UI_ENV_PREFIX = "SKY_UI_";
13
-
14
- /** Filenames tried in each project directory (later files override earlier within the same dir). */
15
- export const SKY_UI_ENV_FILES = [".env", ".env.local"];
16
-
17
- /** Documented variables (for README / tooling — not enforced here). */
18
- export const SKY_UI_ENV_VARS = [
19
- "SKY_UI_API_URL",
20
- "SKY_UI_AUTH_TOKEN",
21
- "SKY_UI_PERSONAL_TOKEN",
22
- "SKY_UI_PROJECT_ROOT",
23
- "SKY_UI_PRO_FRAMEWORK",
24
- "SKY_UI_PRO_LENIENT",
25
- "SKY_UI_PRO_LICENSE_LENIENT",
26
- "SKY_UI_PRO_SKIP_POSTINSTALL",
27
- "SKY_UI_PRO_STRICT",
28
- "SKY_UI_NPM_REGISTRY",
29
- ];
30
-
31
- export async function pathExists(p) {
32
- try {
33
- await access(p);
34
- return true;
35
- } catch {
36
- return false;
37
- }
38
- }
39
-
40
- function normalizeDirKey(dir) {
41
- return dir.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
42
- }
43
-
44
- function shouldLoadKey(key) {
45
- return key.startsWith(SKY_UI_ENV_PREFIX);
46
- }
47
-
48
- function envAlreadySet(key) {
49
- const v = process.env[key];
50
- return typeof v === "string" && v.trim().length > 0;
51
- }
52
-
53
- function unquote(value) {
54
- if (
55
- (value.startsWith('"') && value.endsWith('"')) ||
56
- (value.startsWith("'") && value.endsWith("'"))
57
- ) {
58
- return value.slice(1, -1);
59
- }
60
- return value;
61
- }
62
-
63
- /** Parse and apply one `.env` file. Does not overwrite non-empty process.env values. */
64
- export async function loadEnvFile(envFilePath) {
65
- try {
66
- const raw = await readFile(envFilePath, "utf8");
67
- for (const line of raw.split(/\r?\n/)) {
68
- const trimmed = line.trim();
69
- if (!trimmed || trimmed.startsWith("#")) continue;
70
- const eq = trimmed.indexOf("=");
71
- if (eq <= 0) continue;
72
- const key = trimmed.slice(0, eq).trim();
73
- if (!shouldLoadKey(key)) continue;
74
- if (envAlreadySet(key)) continue;
75
- process.env[key] = unquote(trimmed.slice(eq + 1).trim());
76
- }
77
- } catch {
78
- /* missing or unreadable */
79
- }
80
- }
81
-
82
- /** Load `.env` (+ `.env.local`) from a project directory. */
83
- export async function loadProjectEnv(cwd = process.cwd()) {
84
- for (const name of SKY_UI_ENV_FILES) {
85
- await loadEnvFile(join(cwd, name));
86
- }
87
- }
88
-
89
- /** Walk up to find the nearest directory containing `package.json`. */
90
- export async function findProjectRoot(startDir, maxDepth = 12) {
91
- let dir = startDir;
92
- for (let i = 0; i < maxDepth; i++) {
93
- if (await pathExists(join(dir, "package.json"))) return dir;
94
- const parent = dirname(dir);
95
- if (parent === dir) break;
96
- dir = parent;
97
- }
98
- return startDir;
99
- }
100
-
101
- /**
102
- * Directories to scan for `.env`, in priority order (first match wins per key;
103
- * later dirs only fill keys still unset).
104
- */
105
- export async function collectEnvSearchDirs(options = {}) {
106
- const { pkgRoot, extraDirs = [] } = options;
107
- const seen = new Set();
108
- const ordered = [];
109
-
110
- const push = (dir) => {
111
- if (!dir || typeof dir !== "string") return;
112
- const key = normalizeDirKey(dir);
113
- if (seen.has(key)) return;
114
- seen.add(key);
115
- ordered.push(dir);
116
- };
117
-
118
- push(process.env.INIT_CWD);
119
- push(process.env.npm_config_local_prefix);
120
- push(process.env.SKY_UI_PROJECT_ROOT?.trim());
121
- push(process.cwd());
122
-
123
- const cwdRoot = await findProjectRoot(process.cwd());
124
- push(cwdRoot);
125
-
126
- if (pkgRoot) {
127
- push(await findProjectRoot(dirname(pkgRoot)));
128
- }
129
-
130
- for (const dir of extraDirs) {
131
- push(dir);
132
- }
133
-
134
- return ordered;
135
- }
136
-
137
- /**
138
- * Load Sky UI env from consumer project `.env` files.
139
- * @param {{ pkgRoot?: string, extraDirs?: string[] }} [options]
140
- */
141
- export async function loadConsumerProjectEnv(options = {}) {
142
- for (const dir of await collectEnvSearchDirs(options)) {
143
- await loadProjectEnv(dir);
144
- }
145
- }
146
-
147
- /** @deprecated Alias used by postinstall — prefer loadConsumerProjectEnv */
148
- export async function loadInstallProjectEnv(pkgRoot) {
149
- return loadConsumerProjectEnv({ pkgRoot });
150
- }
@@ -1,147 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Shared token resolution and online license validation for @sky.ui.pro postinstall.
4
- */
5
- import { access, readFile } from "node:fs/promises";
6
- import { homedir } from "node:os";
7
- import { join } from "node:path";
8
-
9
- export { loadConsumerProjectEnv, loadInstallProjectEnv } from "./project-env.mjs";
10
-
11
- export const SKY_UI_HOME = join(homedir(), ".sky.ui");
12
- export const LEGACY_SKY_UI_HOME = join(homedir(), ".sky-ui");
13
- export const cacheRoot = join(SKY_UI_HOME, "cache");
14
- export const legacyCacheRoot = join(LEGACY_SKY_UI_HOME, "cache");
15
- export const ENTITLEMENT_MARKER = ".sky-ui-pro-installed.json";
16
-
17
- export async function exists(p) {
18
- try {
19
- await access(p);
20
- return true;
21
- } catch {
22
- return false;
23
- }
24
- }
25
-
26
- export function resolveApiBase(pkg) {
27
- const fromEnv = process.env.SKY_UI_API_URL?.trim();
28
- if (fromEnv) return fromEnv.replace(/\/api\/?$/, "").replace(/\/$/, "");
29
- const fromPkg = pkg?.skyUiPro?.apiBase?.trim();
30
- if (fromPkg) return fromPkg.replace(/\/$/, "");
31
- return "https://library.sky-ui.com";
32
- }
33
-
34
- export function licenseValidateUrl(apiBase) {
35
- const host = String(apiBase).replace(/\/api\/?$/, "").replace(/\/$/, "");
36
- return `${host}/api/license/validate`;
37
- }
38
-
39
- export async function resolveToken() {
40
- const envCi = process.env.SKY_UI_AUTH_TOKEN?.trim();
41
- if (envCi) return envCi;
42
- const envPersonal = process.env.SKY_UI_PERSONAL_TOKEN?.trim();
43
- if (envPersonal) return envPersonal;
44
- for (const credPath of [
45
- join(SKY_UI_HOME, "credentials.json"),
46
- join(LEGACY_SKY_UI_HOME, "credentials.json"),
47
- ]) {
48
- if (!(await exists(credPath))) continue;
49
- const creds = JSON.parse(await readFile(credPath, "utf8"));
50
- if (typeof creds.personalToken === "string" && creds.personalToken.trim()) {
51
- return creds.personalToken.trim();
52
- }
53
- if (typeof creds.authToken === "string" && creds.authToken.trim()) {
54
- return creds.authToken.trim();
55
- }
56
- }
57
- return null;
58
- }
59
-
60
- export function isAccessTokenFormat(token) {
61
- return typeof token === "string" && (token.startsWith("sk_pt_") || token.startsWith("sk_ci_"));
62
- }
63
-
64
- /**
65
- * @returns {{ active: boolean, status?: string, error?: string, renewalEmailSent?: boolean }}
66
- */
67
- export async function validateAccessTokenOnline(token, apiBase) {
68
- if (!token || !isAccessTokenFormat(token)) {
69
- return { active: false, status: "missing" };
70
- }
71
- try {
72
- const res = await fetch(licenseValidateUrl(apiBase), {
73
- method: "POST",
74
- headers: {
75
- Authorization: `Bearer ${token}`,
76
- "Content-Type": "application/json",
77
- Accept: "application/json",
78
- },
79
- body: "{}",
80
- });
81
- const data = await res.json().catch(() => ({}));
82
- if (res.ok && data.active) {
83
- return { active: true, status: "active", tokenKind: data.tokenKind };
84
- }
85
- return {
86
- active: false,
87
- status: data.status ?? (res.status === 401 ? "invalid" : "inactive"),
88
- error: data.error,
89
- renewalEmailSent: Boolean(data.renewalEmailSent),
90
- };
91
- } catch (err) {
92
- return {
93
- active: false,
94
- status: "network_error",
95
- error: err instanceof Error ? err.message : String(err),
96
- };
97
- }
98
- }
99
-
100
- export function formatRenewalEmailHint(result) {
101
- if (!result?.renewalEmailSent) return "";
102
- return "\n Renewal instructions were sent to your account email.\n https://library.sky-ui.com/pricing";
103
- }
104
-
105
- export function isInstallStrict() {
106
- if (process.env.SKY_UI_PRO_LENIENT === "1") return false;
107
- if (process.env.SKY_UI_PRO_STRICT === "0") return false;
108
- return true;
109
- }
110
-
111
- export function entitlementMarkerPath(pkgRoot) {
112
- return join(pkgRoot, ENTITLEMENT_MARKER);
113
- }
114
-
115
- export async function writeEntitlementMarker(pkgRoot, { name, version, status = "active" }) {
116
- const { writeFile } = await import("node:fs/promises");
117
- await writeFile(
118
- entitlementMarkerPath(pkgRoot),
119
- `${JSON.stringify(
120
- {
121
- name,
122
- version,
123
- status,
124
- validatedAt: new Date().toISOString(),
125
- },
126
- null,
127
- 2,
128
- )}\n`,
129
- "utf8",
130
- );
131
- }
132
-
133
- /** True when package was not hydrated (stub-only install). */
134
- export async function isStubOnlyPackage(pkgRoot) {
135
- const pluginsDir = join(pkgRoot, "plugins", "vite-plugin.js");
136
- if (await exists(pluginsDir)) return false;
137
- const distIndex = join(pkgRoot, "dist", "index.js");
138
- if (await exists(distIndex)) return false;
139
- const stubPath = join(pkgRoot, "dist", "stub", "index.js");
140
- if (!(await exists(stubPath))) return true;
141
- try {
142
- const stub = await readFile(stubPath, "utf8");
143
- return /export\s+default\s+\{\s*\}/.test(stub);
144
- } catch {
145
- return true;
146
- }
147
- }
@@ -1,287 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Downloads the full @sky.ui.pro/* artifact from the Sky UI npm proxy (GitLab upstream).
4
- * Cache restore re-validates the access token; install fails closed without a valid token.
5
- */
6
- import { createWriteStream } from "node:fs";
7
- import { cp, mkdir, mkdtemp, readdir, readFile, rm, writeFile } from "node:fs/promises";
8
- import { tmpdir } from "node:os";
9
- import { dirname, join } from "node:path";
10
- import { fileURLToPath } from "node:url";
11
- import { pipeline } from "node:stream/promises";
12
- import { extract } from "tar";
13
- import {
14
- ARTIFACT_MANIFEST_SIDECAR,
15
- hasHydratedExports,
16
- mergeHydratedManifest,
17
- } from "./lib/merge-manifest.mjs";
18
- import {
19
- ENTITLEMENT_MARKER,
20
- cacheRoot,
21
- exists,
22
- isInstallStrict,
23
- legacyCacheRoot,
24
- loadInstallProjectEnv,
25
- resolveApiBase,
26
- resolveToken,
27
- validateAccessTokenOnline,
28
- writeEntitlementMarker,
29
- formatRenewalEmailHint,
30
- } from "./lib/token.mjs";
31
-
32
- const scriptDir = dirname(fileURLToPath(import.meta.url));
33
- const pkgRoot = join(scriptDir, "..");
34
-
35
- const SKIP_COPY_TO_INSTALL = new Set([ENTITLEMENT_MARKER, ARTIFACT_MANIFEST_SIDECAR]);
36
-
37
- async function readJson(p) {
38
- return JSON.parse(await readFile(p, "utf8"));
39
- }
40
-
41
- async function writeJson(p, data) {
42
- await writeFile(p, `${JSON.stringify(data, null, 2)}\n`, "utf8");
43
- }
44
-
45
- function packageSlug(name) {
46
- return name.replace(/^@/, "").replace("/", "-");
47
- }
48
-
49
- function cacheVersionDir(root, slug, version) {
50
- return join(root, slug, version);
51
- }
52
-
53
- async function copyDirectoryContents(src, dest, { skip = SKIP_COPY_TO_INSTALL } = {}) {
54
- await mkdir(dest, { recursive: true });
55
- for (const entry of await readdir(src, { withFileTypes: true })) {
56
- if (skip.has(entry.name)) continue;
57
- await cp(join(src, entry.name), join(dest, entry.name), { recursive: true, force: true });
58
- }
59
- }
60
-
61
- /** Drop cached versions other than the one being installed (HeroUI cache policy). */
62
- async function enforceCachePolicy(slug, version) {
63
- const slugDir = join(cacheRoot, slug);
64
- if (!(await exists(slugDir))) return;
65
- for (const entry of await readdir(slugDir, { withFileTypes: true })) {
66
- if (entry.name === version || entry.name === ".gitignore") continue;
67
- await rm(join(slugDir, entry.name), { recursive: true, force: true });
68
- }
69
- }
70
-
71
- async function readArtifactManifestSidecar(cacheDir) {
72
- const sidecar = join(cacheDir, ARTIFACT_MANIFEST_SIDECAR);
73
- if (!(await exists(sidecar))) return null;
74
- return readJson(sidecar);
75
- }
76
-
77
- /** Read artifact package.json from cached tarball (legacy caches without sidecar). */
78
- async function readArtifactManifestFromTarball(slug, version) {
79
- const tgz = join(cacheRoot, `${slug}-${version}.tgz`);
80
- if (!(await exists(tgz))) return null;
81
- const stagingDir = await mkdtemp(join(tmpdir(), `sky.ui.pro-manifest-${slug}-${version}-`));
82
- try {
83
- await extract({ file: tgz, cwd: stagingDir, strip: 1 });
84
- return readJson(join(stagingDir, "package.json"));
85
- } catch {
86
- return null;
87
- } finally {
88
- await rm(stagingDir, { recursive: true, force: true });
89
- }
90
- }
91
-
92
- async function resolveArtifactManifest(stubManifest, slug, version, cacheDir) {
93
- const sidecar = cacheDir ? await readArtifactManifestSidecar(cacheDir) : null;
94
- if (sidecar) return sidecar;
95
- return readArtifactManifestFromTarball(slug, version);
96
- }
97
-
98
- async function applyHydratedManifest(targetRoot, stubManifest, artifactManifest) {
99
- const merged = mergeHydratedManifest(stubManifest, artifactManifest);
100
- await writeJson(join(targetRoot, "package.json"), merged);
101
- return merged;
102
- }
103
-
104
- async function finalizeHydratedManifest(targetRoot, stubManifest, slug, version, cacheDir) {
105
- const current = await readJson(join(targetRoot, "package.json"));
106
- if (hasHydratedExports(current)) {
107
- return current;
108
- }
109
- const artifactManifest = await resolveArtifactManifest(stubManifest, slug, version, cacheDir);
110
- if (!artifactManifest) return current;
111
- return applyHydratedManifest(targetRoot, stubManifest, artifactManifest);
112
- }
113
-
114
- async function restoreFromCache(slug, version, target, stubManifest) {
115
- for (const root of [cacheRoot, legacyCacheRoot]) {
116
- const src = cacheVersionDir(root, slug, version);
117
- if (!(await exists(src))) continue;
118
- const entries = await readdir(src);
119
- if (entries.length === 0) continue;
120
- await copyDirectoryContents(src, target);
121
- await finalizeHydratedManifest(target, stubManifest, slug, version, src);
122
- return { cacheDir: src };
123
- }
124
- return null;
125
- }
126
-
127
- async function saveToCache(slug, version, source, artifactManifest) {
128
- const dest = cacheVersionDir(cacheRoot, slug, version);
129
- await rm(dest, { recursive: true, force: true });
130
- await mkdir(dest, { recursive: true });
131
- await copyDirectoryContents(source, dest);
132
- if (artifactManifest) {
133
- await writeJson(join(dest, ARTIFACT_MANIFEST_SIDECAR), artifactManifest);
134
- }
135
- }
136
-
137
- async function invalidateCache(slug, version) {
138
- for (const root of [cacheRoot, legacyCacheRoot]) {
139
- const dir = cacheVersionDir(root, slug, version);
140
- if (await exists(dir)) {
141
- await rm(dir, { recursive: true, force: true });
142
- }
143
- }
144
- const tgz = join(cacheRoot, `${slug}-${version}.tgz`);
145
- if (await exists(tgz)) await rm(tgz, { force: true });
146
- }
147
-
148
- function tarballFileName(name, version) {
149
- return `${name.replace(/^@/, "").replace("/", "-")}-${version}.tgz`;
150
- }
151
-
152
- function tarballUrl(apiBase, name, version) {
153
- const base = apiBase.replace(/\/$/, "");
154
- const scopePath = name.replace("/", "%2f");
155
- const file = tarballFileName(name, version);
156
- return `${base}/npm/${scopePath}/-/${file}`;
157
- }
158
-
159
- function printMissingToken(name, apiBase) {
160
- console.warn(`
161
- [@sky.ui.pro] Missing install token — ${name} was not downloaded.
162
-
163
- Local dev:
164
- npx sky.ui.pro login
165
- or export SKY_UI_PERSONAL_TOKEN=sk_pt_…
166
-
167
- CI / pipelines:
168
- export SKY_UI_AUTH_TOKEN=sk_ci_…
169
-
170
- Or add SKY_UI_PERSONAL_TOKEN / SKY_UI_AUTH_TOKEN to your project .env
171
- API host (SKY_UI_API_URL): ${apiBase}
172
-
173
- Then re-run: npm install "${name}"
174
- Docs: https://library.sky-ui.com/docs/getting-started
175
-
176
- Maintainer escape hatch: SKY_UI_PRO_LENIENT=1
177
- `);
178
- }
179
-
180
- function printInvalidToken(name, result, apiBase) {
181
- console.error(
182
- `[@sky.ui.pro] License validation failed for ${name}: ${result.status ?? "inactive"}${
183
- result.error ? ` — ${result.error}` : ""
184
- }`,
185
- );
186
- console.error(`[@sky.ui.pro] API host: ${apiBase}`);
187
- const renewalHint = formatRenewalEmailHint(result);
188
- console.error(`
189
- Renew or regenerate your token, then re-run: npm install "${name}"${renewalHint}
190
- `);
191
- }
192
-
193
- async function installFromTarball(tgzPath, slug, version, stubManifest) {
194
- const stagingDir = await mkdtemp(join(tmpdir(), `sky.ui.pro-${slug}-${version}-`));
195
- try {
196
- await extract({ file: tgzPath, cwd: stagingDir, strip: 1 });
197
- const artifactManifest = await readJson(join(stagingDir, "package.json"));
198
- await copyDirectoryContents(stagingDir, pkgRoot);
199
- await applyHydratedManifest(pkgRoot, stubManifest, artifactManifest);
200
- await saveToCache(slug, version, pkgRoot, artifactManifest);
201
- } finally {
202
- await rm(stagingDir, { recursive: true, force: true });
203
- }
204
- }
205
-
206
- async function main() {
207
- if (process.env.SKY_UI_PRO_SKIP_POSTINSTALL === "1") return;
208
-
209
- await loadInstallProjectEnv(pkgRoot);
210
-
211
- const pkg = await readJson(join(pkgRoot, "package.json"));
212
- const { name, version } = pkg;
213
- if (!name?.startsWith("@sky.ui.pro/") || !version) {
214
- console.warn("[@sky.ui.pro] postinstall: invalid package.json name/version");
215
- return;
216
- }
217
-
218
- const stubManifest = structuredClone(pkg);
219
- const slug = packageSlug(name);
220
- const apiBase = resolveApiBase(pkg);
221
- const strict = isInstallStrict();
222
-
223
- await enforceCachePolicy(slug, version);
224
-
225
- const token = await resolveToken();
226
- const cacheAvailable =
227
- (await exists(cacheVersionDir(cacheRoot, slug, version))) ||
228
- (await exists(cacheVersionDir(legacyCacheRoot, slug, version)));
229
-
230
- if (cacheAvailable) {
231
- if (!token) {
232
- printMissingToken(name, apiBase);
233
- if (strict) process.exit(1);
234
- return;
235
- }
236
- const validation = await validateAccessTokenOnline(token, apiBase);
237
- if (validation.active) {
238
- if (await restoreFromCache(slug, version, pkgRoot, stubManifest)) {
239
- await writeEntitlementMarker(pkgRoot, { name, version, status: validation.status ?? "active" });
240
- console.log(`[@sky.ui.pro] Restored ${name}@${version} from cache.`);
241
- return;
242
- }
243
- } else {
244
- printInvalidToken(name, validation, apiBase);
245
- await invalidateCache(slug, version);
246
- if (strict) process.exit(1);
247
- return;
248
- }
249
- }
250
-
251
- if (!token) {
252
- printMissingToken(name, apiBase);
253
- if (strict) process.exit(1);
254
- return;
255
- }
256
-
257
- const preDownloadValidation = await validateAccessTokenOnline(token, apiBase);
258
- if (!preDownloadValidation.active) {
259
- printInvalidToken(name, preDownloadValidation, apiBase);
260
- if (strict) process.exit(1);
261
- return;
262
- }
263
-
264
- const url = tarballUrl(apiBase, name, version);
265
- const res = await fetch(url, {
266
- headers: { Authorization: `Bearer ${token}`, Accept: "application/octet-stream" },
267
- });
268
-
269
- if (!res.ok) {
270
- const body = await res.text().catch(() => "");
271
- console.error(`[@sky.ui.pro] Download failed (${res.status}) ${url}`);
272
- if (body) console.error(body.slice(0, 500));
273
- process.exit(1);
274
- }
275
-
276
- await mkdir(cacheRoot, { recursive: true });
277
- const tgzPath = join(cacheRoot, `${slug}-${version}.tgz`);
278
- await pipeline(res.body, createWriteStream(tgzPath));
279
- await installFromTarball(tgzPath, slug, version, stubManifest);
280
- await writeEntitlementMarker(pkgRoot, { name, version, status: "active" });
281
- console.log(`[@sky.ui.pro] Installed ${name}@${version}`);
282
- }
283
-
284
- main().catch((err) => {
285
- console.error("[@sky.ui.pro] postinstall error:", err instanceof Error ? err.message : err);
286
- process.exit(1);
287
- });