@lambda-kata/licensing 0.1.5 → 0.1.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/package.json +5 -5
- package/scripts/install.js +219 -0
- package/scripts/postinstall.js +163 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lambda-kata/licensing",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Tamper-resistant native licensing validator for Lambda Kata Integration",
|
|
5
5
|
"main": "out/dist/index.js",
|
|
6
6
|
"types": "out/tsc/index.d.ts",
|
|
@@ -48,15 +48,15 @@
|
|
|
48
48
|
"lint": "eslint src/ test/ --ext .ts",
|
|
49
49
|
"lint:fix": "eslint src/ test/ --ext .ts --fix",
|
|
50
50
|
"docs": "typedoc src/index.ts --out docs/",
|
|
51
|
-
"_install": "node scripts/install.js",
|
|
52
|
-
"_postinstall": "node scripts/postinstall.js || echo 'Postinstall script failed, using fallback mode'",
|
|
53
51
|
"install": "node scripts/install.js",
|
|
54
|
-
"postinstall": "node scripts/postinstall.js || echo
|
|
52
|
+
"postinstall": "node scripts/postinstall.js || echo 'Postinstall script failed, using fallback mode'"
|
|
55
53
|
},
|
|
56
54
|
"files": [
|
|
57
55
|
"out/",
|
|
58
56
|
"build/amd64/",
|
|
59
57
|
"build/arm64/",
|
|
58
|
+
"scripts/install.js",
|
|
59
|
+
"scripts/postinstall.js",
|
|
60
60
|
"README.md",
|
|
61
61
|
"LICENSE"
|
|
62
62
|
],
|
|
@@ -96,4 +96,4 @@
|
|
|
96
96
|
9
|
|
97
97
|
]
|
|
98
98
|
}
|
|
99
|
-
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Elastic License 2.0
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) 2024 Lambda Kata Team, Raman Marozau raman@worktif.com
|
|
6
|
+
*
|
|
7
|
+
* npm install script for native licensing validator
|
|
8
|
+
* Handles prebuilt binary selection and fallback logic
|
|
9
|
+
*
|
|
10
|
+
* @remarks Validates: Requirements 5.6
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const os = require('os');
|
|
16
|
+
|
|
17
|
+
// Configuration
|
|
18
|
+
const PACKAGE_NAME = '@lambda-kata/licensing';
|
|
19
|
+
const ADDON_NAME = 'lambda_kata_licensing.node';
|
|
20
|
+
|
|
21
|
+
// Platform mapping
|
|
22
|
+
const PLATFORM_MAP = {
|
|
23
|
+
'linux-x64': 'amd64',
|
|
24
|
+
'linux-arm64': 'arm64'
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// Colors for output
|
|
28
|
+
const colors = {
|
|
29
|
+
red: '\x1b[31m',
|
|
30
|
+
green: '\x1b[32m',
|
|
31
|
+
yellow: '\x1b[33m',
|
|
32
|
+
blue: '\x1b[34m',
|
|
33
|
+
reset: '\x1b[0m'
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
function log(level, message) {
|
|
37
|
+
const timestamp = new Date().toISOString();
|
|
38
|
+
const color = colors[level] || colors.reset;
|
|
39
|
+
console.log(`${color}[${level.toUpperCase()}]${colors.reset} ${timestamp} ${message}`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getPlatformKey() {
|
|
43
|
+
const platform = os.platform();
|
|
44
|
+
const arch = os.arch();
|
|
45
|
+
|
|
46
|
+
// Only support Linux for Lambda deployment
|
|
47
|
+
if (platform !== 'linux') {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Map Node.js arch to our naming convention
|
|
52
|
+
const archMap = {
|
|
53
|
+
'x64': 'x64',
|
|
54
|
+
'arm64': 'arm64'
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const mappedArch = archMap[arch];
|
|
58
|
+
if (!mappedArch) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return `${platform}-${mappedArch}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getPrebuiltPath() {
|
|
66
|
+
const platformKey = getPlatformKey();
|
|
67
|
+
if (!platformKey) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const mappedArch = PLATFORM_MAP[platformKey];
|
|
72
|
+
if (!mappedArch) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Look for prebuilt binary in prebuilt directory (shipped with npm package)
|
|
77
|
+
const prebuiltDir = path.join(__dirname, '..', 'prebuilt');
|
|
78
|
+
const prebuiltPath = path.join(prebuiltDir, mappedArch, 'build', 'Release', ADDON_NAME);
|
|
79
|
+
|
|
80
|
+
if (fs.existsSync(prebuiltPath)) {
|
|
81
|
+
return prebuiltPath;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Fallback: check if already in build directory (from previous install)
|
|
85
|
+
const buildDir = path.join(__dirname, '..', 'build');
|
|
86
|
+
const buildPath = path.join(buildDir, 'Release', ADDON_NAME);
|
|
87
|
+
|
|
88
|
+
if (fs.existsSync(buildPath)) {
|
|
89
|
+
log('blue', 'Using existing build from previous installation');
|
|
90
|
+
return null; // Already in place, no need to copy
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function getTargetPath() {
|
|
97
|
+
const targetDir = path.join(__dirname, '..', 'build', 'Release');
|
|
98
|
+
return path.join(targetDir, ADDON_NAME);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function ensureDirectoryExists(dirPath) {
|
|
102
|
+
if (!fs.existsSync(dirPath)) {
|
|
103
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function copyPrebuiltBinary() {
|
|
108
|
+
const prebuiltPath = getPrebuiltPath();
|
|
109
|
+
if (!prebuiltPath) {
|
|
110
|
+
log('warn', 'No prebuilt binary available for this platform');
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const targetPath = getTargetPath();
|
|
115
|
+
const targetDir = path.dirname(targetPath);
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
// Ensure target directory exists
|
|
119
|
+
ensureDirectoryExists(targetDir);
|
|
120
|
+
|
|
121
|
+
// Copy prebuilt binary
|
|
122
|
+
fs.copyFileSync(prebuiltPath, targetPath);
|
|
123
|
+
|
|
124
|
+
// Set executable permissions
|
|
125
|
+
fs.chmodSync(targetPath, 0o755);
|
|
126
|
+
|
|
127
|
+
log('green', `Installed prebuilt binary: ${targetPath}`);
|
|
128
|
+
return true;
|
|
129
|
+
} catch (error) {
|
|
130
|
+
log('red', `Failed to copy prebuilt binary: ${error.message}`);
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function tryNativeBuild() {
|
|
136
|
+
const { execSync } = require('child_process');
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
log('blue', 'Attempting native build...');
|
|
140
|
+
|
|
141
|
+
// Check if we have build tools
|
|
142
|
+
execSync('node-gyp --version', { stdio: 'pipe' });
|
|
143
|
+
|
|
144
|
+
// Try to build
|
|
145
|
+
execSync('node-gyp rebuild', {
|
|
146
|
+
stdio: 'inherit',
|
|
147
|
+
cwd: path.join(__dirname, '..')
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Verify build output
|
|
151
|
+
const targetPath = getTargetPath();
|
|
152
|
+
if (fs.existsSync(targetPath)) {
|
|
153
|
+
log('green', 'Native build successful');
|
|
154
|
+
return true;
|
|
155
|
+
} else {
|
|
156
|
+
log('red', 'Native build completed but addon not found');
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
} catch (error) {
|
|
160
|
+
log('yellow', `Native build failed: ${error.message}`);
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function createFallbackMarker() {
|
|
166
|
+
const markerPath = path.join(__dirname, '..', '.fallback-mode');
|
|
167
|
+
try {
|
|
168
|
+
fs.writeFileSync(markerPath, JSON.stringify({
|
|
169
|
+
reason: 'No native addon available',
|
|
170
|
+
platform: os.platform(),
|
|
171
|
+
arch: os.arch(),
|
|
172
|
+
timestamp: new Date().toISOString()
|
|
173
|
+
}, null, 2));
|
|
174
|
+
log('yellow', 'Created fallback mode marker');
|
|
175
|
+
} catch (error) {
|
|
176
|
+
log('red', `Failed to create fallback marker: ${error.message}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function main() {
|
|
181
|
+
log('blue', `Installing ${PACKAGE_NAME}...`);
|
|
182
|
+
log('blue', `Platform: ${os.platform()}-${os.arch()}`);
|
|
183
|
+
|
|
184
|
+
// Skip installation in CI environments unless explicitly requested
|
|
185
|
+
if (process.env.CI && !process.env.FORCE_NATIVE_BUILD) {
|
|
186
|
+
log('yellow', 'Skipping native addon installation in CI environment');
|
|
187
|
+
createFallbackMarker();
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Skip installation during npm pack/publish
|
|
192
|
+
if (process.env.npm_lifecycle_event === 'prepack' ||
|
|
193
|
+
process.env.npm_lifecycle_event === 'prepublishOnly') {
|
|
194
|
+
log('yellow', 'Skipping native addon installation during packaging');
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Try prebuilt binary first
|
|
199
|
+
if (copyPrebuiltBinary()) {
|
|
200
|
+
log('green', 'Installation completed using prebuilt binary');
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Fall back to native build
|
|
205
|
+
if (tryNativeBuild()) {
|
|
206
|
+
log('green', 'Installation completed using native build');
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Create fallback marker
|
|
211
|
+
createFallbackMarker();
|
|
212
|
+
log('yellow', 'Installation completed in fallback mode (JavaScript only)');
|
|
213
|
+
log('yellow', 'Native licensing validation will not be available');
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Only run if called directly
|
|
217
|
+
if (require.main === module) {
|
|
218
|
+
main();
|
|
219
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Elastic License 2.0
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) 2024 Lambda Kata Team, Raman Marozau raman@worktif.com
|
|
6
|
+
*
|
|
7
|
+
* npm postinstall script for native licensing validator
|
|
8
|
+
* Verifies installation and provides user feedback
|
|
9
|
+
*
|
|
10
|
+
* @remarks Validates: Requirements 5.6
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const os = require('os');
|
|
16
|
+
|
|
17
|
+
// Configuration
|
|
18
|
+
const ADDON_NAME = 'lambda_kata_licensing.node';
|
|
19
|
+
|
|
20
|
+
// Colors for output
|
|
21
|
+
const colors = {
|
|
22
|
+
red: '\x1b[31m',
|
|
23
|
+
green: '\x1b[32m',
|
|
24
|
+
yellow: '\x1b[33m',
|
|
25
|
+
blue: '\x1b[34m',
|
|
26
|
+
reset: '\x1b[0m'
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function log(level, message) {
|
|
30
|
+
const color = colors[level] || colors.reset;
|
|
31
|
+
console.log(`${color}[${level.toUpperCase()}]${colors.reset} ${message}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function checkNativeAddon() {
|
|
35
|
+
const addonPath = path.join(__dirname, '..', 'build', 'Release', ADDON_NAME);
|
|
36
|
+
|
|
37
|
+
if (!fs.existsSync(addonPath)) {
|
|
38
|
+
return {available: false, reason: 'Addon file not found'};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const stats = fs.statSync(addonPath);
|
|
43
|
+
|
|
44
|
+
// Check if file is executable
|
|
45
|
+
const isExecutable = (stats.mode & parseInt('111', 8)) !== 0;
|
|
46
|
+
if (!isExecutable) {
|
|
47
|
+
return {available: false, reason: 'Addon file not executable'};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Try to load the addon
|
|
51
|
+
const addon = require(addonPath);
|
|
52
|
+
if (typeof addon.checkEntitlement === 'function') {
|
|
53
|
+
return {available: true, path: addonPath, size: stats.size};
|
|
54
|
+
} else {
|
|
55
|
+
return {available: false, reason: 'Addon missing required exports'};
|
|
56
|
+
}
|
|
57
|
+
} catch (error) {
|
|
58
|
+
return {available: false, reason: `Addon load failed: ${error.message}`};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function checkFallbackMode() {
|
|
63
|
+
const markerPath = path.join(__dirname, '..', '.fallback-mode');
|
|
64
|
+
|
|
65
|
+
if (fs.existsSync(markerPath)) {
|
|
66
|
+
try {
|
|
67
|
+
const marker = JSON.parse(fs.readFileSync(markerPath, 'utf8'));
|
|
68
|
+
return {fallback: true, marker};
|
|
69
|
+
} catch (error) {
|
|
70
|
+
return {fallback: true, marker: {reason: 'Unknown'}};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return {fallback: false};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function checkTypeScriptOutput() {
|
|
78
|
+
const jsPath = path.join(__dirname, '..', 'out', 'dist', 'index.js');
|
|
79
|
+
const dtsPath = path.join(__dirname, '..', 'out', 'tsc', 'index.d.ts');
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
js: fs.existsSync(jsPath),
|
|
83
|
+
types: fs.existsSync(dtsPath)
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function displayInstallationSummary() {
|
|
88
|
+
log('blue', '='.repeat(60));
|
|
89
|
+
log('blue', 'Native Licensing Validator - Installation Summary');
|
|
90
|
+
log('blue', '='.repeat(60));
|
|
91
|
+
|
|
92
|
+
// Platform info
|
|
93
|
+
log('blue', `Platform: ${os.platform()}-${os.arch()}`);
|
|
94
|
+
log('blue', `Node.js: ${process.version}`);
|
|
95
|
+
|
|
96
|
+
// Check native addon
|
|
97
|
+
const addonStatus = checkNativeAddon();
|
|
98
|
+
if (addonStatus.available) {
|
|
99
|
+
log('green', `✓ Native addon: Available (${Math.round(addonStatus.size / 1024)}KB)`);
|
|
100
|
+
log('green', ' Enhanced security features enabled');
|
|
101
|
+
} else {
|
|
102
|
+
log('yellow', `⚠ Native addon: Not available (${addonStatus.reason})`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Check fallback mode
|
|
106
|
+
const fallbackStatus = checkFallbackMode();
|
|
107
|
+
if (fallbackStatus.fallback) {
|
|
108
|
+
log('yellow', `⚠ Fallback mode: Active (${fallbackStatus.marker.reason})`);
|
|
109
|
+
log('yellow', ' Using JavaScript-only implementation');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Check TypeScript output
|
|
113
|
+
const tsStatus = checkTypeScriptOutput();
|
|
114
|
+
if (tsStatus.js && tsStatus.types) {
|
|
115
|
+
log('green', '✓ TypeScript output: Available');
|
|
116
|
+
} else {
|
|
117
|
+
log('red', '✗ TypeScript output: Missing');
|
|
118
|
+
if (!tsStatus.js) log('red', ' - JavaScript bundle missing');
|
|
119
|
+
if (!tsStatus.types) log('red', ' - Type definitions missing');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Usage recommendations
|
|
123
|
+
log('blue', '');
|
|
124
|
+
log('blue', 'Usage:');
|
|
125
|
+
log('blue', ' const { NativeLicensingService } = require("@lambda-kata/licensing");');
|
|
126
|
+
log('blue', ' const service = new NativeLicensingService();');
|
|
127
|
+
|
|
128
|
+
if (!addonStatus.available) {
|
|
129
|
+
log('yellow', '');
|
|
130
|
+
log('yellow', 'Note: Native addon not available. The service will use fallback mode.');
|
|
131
|
+
log('yellow', 'For production use, ensure native addon is built for your target platform.');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Lambda deployment info
|
|
135
|
+
if (addonStatus.available) {
|
|
136
|
+
log('blue', '');
|
|
137
|
+
log('blue', 'Lambda Deployment:');
|
|
138
|
+
log('blue', ' Use the provided Lambda Layer packages for deployment');
|
|
139
|
+
log('blue', ' Run: npm run build:all to create deployment artifacts');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
log('blue', '='.repeat(60));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function main() {
|
|
146
|
+
// Skip in CI unless explicitly requested
|
|
147
|
+
if (process.env.CI && !process.env.SHOW_INSTALL_SUMMARY) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Skip during npm pack/publish
|
|
152
|
+
if (process.env.npm_lifecycle_event === 'prepack' ||
|
|
153
|
+
process.env.npm_lifecycle_event === 'prepublishOnly') {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
displayInstallationSummary();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Only run if called directly
|
|
161
|
+
if (require.main === module) {
|
|
162
|
+
main();
|
|
163
|
+
}
|