@phystack/hub-device 4.3.40-dev
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/.prettierignore +10 -0
- package/.prettierrc +10 -0
- package/CHANGELOG.md +1202 -0
- package/README.md +12 -0
- package/dist/index.d.ts +114 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +967 -0
- package/dist/index.js.map +1 -0
- package/dist/storage/browser.d.ts +2 -0
- package/dist/storage/browser.d.ts.map +1 -0
- package/dist/storage/browser.js +20 -0
- package/dist/storage/browser.js.map +1 -0
- package/dist/storage/index.d.ts +6 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +31 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/node.d.ts +2 -0
- package/dist/storage/node.d.ts.map +1 -0
- package/dist/storage/node.js +47 -0
- package/dist/storage/node.js.map +1 -0
- package/dist/sysinfo/browser.d.ts +3 -0
- package/dist/sysinfo/browser.d.ts.map +1 -0
- package/dist/sysinfo/browser.js +194 -0
- package/dist/sysinfo/browser.js.map +1 -0
- package/dist/sysinfo/index.d.ts +3 -0
- package/dist/sysinfo/index.d.ts.map +1 -0
- package/dist/sysinfo/index.js +34 -0
- package/dist/sysinfo/index.js.map +1 -0
- package/dist/sysinfo/node.d.ts +3 -0
- package/dist/sysinfo/node.d.ts.map +1 -0
- package/dist/sysinfo/node.js +53 -0
- package/dist/sysinfo/node.js.map +1 -0
- package/dist/sysinfo/tizen.d.ts +8 -0
- package/dist/sysinfo/tizen.d.ts.map +1 -0
- package/dist/sysinfo/tizen.js +168 -0
- package/dist/sysinfo/tizen.js.map +1 -0
- package/dist/types/command.types.d.ts +8 -0
- package/dist/types/command.types.d.ts.map +1 -0
- package/dist/types/command.types.js +8 -0
- package/dist/types/command.types.js.map +1 -0
- package/dist/types/container.types.d.ts +10 -0
- package/dist/types/container.types.d.ts.map +1 -0
- package/dist/types/container.types.js +3 -0
- package/dist/types/container.types.js.map +1 -0
- package/dist/types/job.types.d.ts +31 -0
- package/dist/types/job.types.d.ts.map +1 -0
- package/dist/types/job.types.js +15 -0
- package/dist/types/job.types.js.map +1 -0
- package/dist/types/twin.types.d.ts +653 -0
- package/dist/types/twin.types.d.ts.map +1 -0
- package/dist/types/twin.types.js +21 -0
- package/dist/types/twin.types.js.map +1 -0
- package/dist/utilities/get-device-identifier.utility.d.ts +2 -0
- package/dist/utilities/get-device-identifier.utility.d.ts.map +1 -0
- package/dist/utilities/get-device-identifier.utility.js +140 -0
- package/dist/utilities/get-device-identifier.utility.js.map +1 -0
- package/dist/utilities/get-hub-credentials.utility.d.ts +8 -0
- package/dist/utilities/get-hub-credentials.utility.d.ts.map +1 -0
- package/dist/utilities/get-hub-credentials.utility.js +47 -0
- package/dist/utilities/get-hub-credentials.utility.js.map +1 -0
- package/dist/utilities/get-provisioning-code.utility.d.ts +3 -0
- package/dist/utilities/get-provisioning-code.utility.d.ts.map +1 -0
- package/dist/utilities/get-provisioning-code.utility.js +49 -0
- package/dist/utilities/get-provisioning-code.utility.js.map +1 -0
- package/package.json +39 -0
- package/src/hub-device.d.ts +0 -0
- package/src/index.ts +1228 -0
- package/src/storage/browser.ts +16 -0
- package/src/storage/index.ts +46 -0
- package/src/storage/node.ts +42 -0
- package/src/sysinfo/browser.ts +217 -0
- package/src/sysinfo/index.ts +29 -0
- package/src/sysinfo/node.ts +387 -0
- package/src/sysinfo/tizen.ts +203 -0
- package/src/types/command.types.ts +8 -0
- package/src/types/container.types.ts +12 -0
- package/src/types/job.types.ts +36 -0
- package/src/types/twin.types.ts +751 -0
- package/src/utilities/get-device-identifier.utility.ts +179 -0
- package/src/utilities/get-hub-credentials.utility.ts +56 -0
- package/src/utilities/get-provisioning-code.utility.ts +55 -0
- package/tsconfig.json +45 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
|
|
2
|
+
import { spawnSync } from 'child_process';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import getSysinfo from '../sysinfo';
|
|
5
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
6
|
+
|
|
7
|
+
const logger = console;
|
|
8
|
+
|
|
9
|
+
function getSerialFromDmidecode(): string | undefined {
|
|
10
|
+
try {
|
|
11
|
+
// Execute the command using spawnSync
|
|
12
|
+
const result = spawnSync('sudo', ['dmidecode', '-s', 'system-serial-number'], {
|
|
13
|
+
encoding: 'utf-8',
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// Get the device serial number and trim any whitespace
|
|
17
|
+
const deviceSerialNumber = result.stdout?.trim() || '';
|
|
18
|
+
|
|
19
|
+
// Check if the serial number is '0', empty, or contains spaces
|
|
20
|
+
if (
|
|
21
|
+
deviceSerialNumber === '0' ||
|
|
22
|
+
deviceSerialNumber === '' ||
|
|
23
|
+
deviceSerialNumber.includes(' ')
|
|
24
|
+
) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return deviceSerialNumber;
|
|
29
|
+
} catch (error) {
|
|
30
|
+
logger.info('No serial number in dmidecode, trying other options');
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getSerialFromKernelCmdline(): string | undefined {
|
|
36
|
+
try {
|
|
37
|
+
// Check ARM64 device tree boot args first (most reliable for ARM64 systems)
|
|
38
|
+
if (fs.existsSync('/proc/device-tree/chosen/bootargs')) {
|
|
39
|
+
const bootArgs = fs.readFileSync('/proc/device-tree/chosen/bootargs', 'utf8');
|
|
40
|
+
// Look for phygrid.serial=VALUE parameter in boot args
|
|
41
|
+
const bootArgsMatch = bootArgs.match(/phygrid\.serial=([^\s\0]+)/);
|
|
42
|
+
if (bootArgsMatch && bootArgsMatch[1]) {
|
|
43
|
+
return bootArgsMatch[1].trim();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Fallback: Read kernel command line from /proc/cmdline (works on all architectures)
|
|
48
|
+
const cmdline = fs.readFileSync('/proc/cmdline', 'utf8');
|
|
49
|
+
// Look for phygrid.serial=VALUE parameter
|
|
50
|
+
const cmdlineMatch = cmdline.match(/phygrid\.serial=([^\s]+)/);
|
|
51
|
+
if (cmdlineMatch && cmdlineMatch[1]) {
|
|
52
|
+
return cmdlineMatch[1].trim();
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
logger.info('No serial number in kernel command line, trying other options');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getSerialFromCPU(): string | undefined {
|
|
62
|
+
// Helper function to get the Rockchip serial number
|
|
63
|
+
const getRockchipSN = (buffer: Buffer, offset: number): string | undefined => {
|
|
64
|
+
// Extract and return the serial number as a hex string
|
|
65
|
+
const serialNumber = buffer.toString('hex', offset, offset + 16);
|
|
66
|
+
return serialNumber || undefined;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Check if "/sys/bus/nvmem/devices/rockchip-otp0/nvmem" exists and try to read it
|
|
70
|
+
if (fs.existsSync('/sys/bus/nvmem/devices/rockchip-otp0/nvmem')) {
|
|
71
|
+
try {
|
|
72
|
+
const data = fs.readFileSync('/sys/bus/nvmem/devices/rockchip-otp0/nvmem');
|
|
73
|
+
return getRockchipSN(data, 10);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
logger.info('No serial number in rockchip-otp0, trying other options');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Check if "/sys/bus/nvmem/devices/rockchip-efuse0/nvmem" exists and try to read it
|
|
80
|
+
if (fs.existsSync('/sys/bus/nvmem/devices/rockchip-efuse0/nvmem')) {
|
|
81
|
+
try {
|
|
82
|
+
const data = fs.readFileSync('/sys/bus/nvmem/devices/rockchip-efuse0/nvmem');
|
|
83
|
+
return getRockchipSN(data, 7);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
logger.info('No serial number in rockchip-efuse0, trying other options');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Attempt to read the serial number from "/proc/cpuinfo"
|
|
90
|
+
try {
|
|
91
|
+
const cpuInfo = fs.readFileSync('/proc/cpuinfo', 'utf8');
|
|
92
|
+
const lines = cpuInfo.split('\n');
|
|
93
|
+
|
|
94
|
+
for (const line of lines) {
|
|
95
|
+
if (line.startsWith('Serial')) {
|
|
96
|
+
return line.slice(10, 26).trim();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} catch (error) {
|
|
100
|
+
logger.info('No serial number in /proc/cpuinfo, trying other options');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Return undefined if the serial number couldn't be found
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function getSerialFromMachineId(): string | undefined {
|
|
108
|
+
try {
|
|
109
|
+
// Check if /var/lib/dbus/machine-id exists and read it
|
|
110
|
+
if (fs.existsSync('/var/lib/dbus/machine-id')) {
|
|
111
|
+
const dbusMachineId = fs.readFileSync('/var/lib/dbus/machine-id', 'utf8').trim();
|
|
112
|
+
|
|
113
|
+
if (dbusMachineId && dbusMachineId.length === 32 && /^[0-9a-f]{32}$/i.test(dbusMachineId)) {
|
|
114
|
+
return dbusMachineId.toUpperCase();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} catch (error) {
|
|
118
|
+
logger.info('No machine-id found, trying other options');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export default async function getDeviceIdentifier() {
|
|
125
|
+
// In browser environment, skip system checks and return UUID
|
|
126
|
+
if (typeof window !== 'undefined') {
|
|
127
|
+
const generatedUuid = uuidv4();
|
|
128
|
+
logger.info('Browser environment detected, generating UUID:', generatedUuid);
|
|
129
|
+
return generatedUuid;
|
|
130
|
+
}
|
|
131
|
+
// Priority 1: Kernel command line (ONLY for QEMU ARM64 virt machines where SMBIOS doesn't work)
|
|
132
|
+
const serialFromKernel = getSerialFromKernelCmdline();
|
|
133
|
+
if (serialFromKernel && serialFromKernel !== '-' && serialFromKernel.trim() !== '') {
|
|
134
|
+
return serialFromKernel.trim();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Priority 2: Dmidecode
|
|
138
|
+
const serialFromDmidecode = getSerialFromDmidecode();
|
|
139
|
+
if (serialFromDmidecode && serialFromDmidecode !== '-' && serialFromDmidecode.trim() !== '') {
|
|
140
|
+
return serialFromDmidecode.trim();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Priority 3: Get from CPU
|
|
144
|
+
const serialFromCpu = getSerialFromCPU();
|
|
145
|
+
if (serialFromCpu && serialFromCpu !== '-' && serialFromCpu.trim() !== '') {
|
|
146
|
+
return serialFromCpu.trim();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Priority 4: Machine ID (systemd-generated unique identifier)
|
|
150
|
+
const serialFromMachineId = getSerialFromMachineId();
|
|
151
|
+
if (serialFromMachineId && serialFromMachineId !== '-' && serialFromMachineId.trim() !== '') {
|
|
152
|
+
return serialFromMachineId.trim();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Priority 5: MAC address of the first network interface that is either Ethernet or Wi-Fi
|
|
156
|
+
const { system = {}, net = [] } = await getSysinfo();
|
|
157
|
+
|
|
158
|
+
for (const iface of net) {
|
|
159
|
+
if ((iface.type === 'wired' || iface.type === 'wireless') &&
|
|
160
|
+
iface.mac && iface.mac !== '-' && iface.mac.trim() !== '') {
|
|
161
|
+
return iface.mac.trim();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Priority 6: Serial (if valid)
|
|
166
|
+
if (system.serial && system.serial !== '-' && system.serial.trim() !== '') {
|
|
167
|
+
return system.serial.trim();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Priority 7: UUID
|
|
171
|
+
if (system.uuid && system.uuid !== '-' && system.uuid.trim() !== '') {
|
|
172
|
+
return system.uuid.trim();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// If no valid identifier found or if it's '-', generate a UUID
|
|
176
|
+
const generatedUuid = uuidv4();
|
|
177
|
+
logger.info('No valid device identifier found, generating UUID:', generatedUuid);
|
|
178
|
+
return generatedUuid;
|
|
179
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import getStorage from '../storage';
|
|
2
|
+
import getAxiosInstanceWithProxy from '@phystack/axios-proxy';
|
|
3
|
+
|
|
4
|
+
const logger = console;
|
|
5
|
+
|
|
6
|
+
const getHubCredentials = async (
|
|
7
|
+
apiUrl: string
|
|
8
|
+
): Promise<{ accessKey: string; deviceId: string; phyhubUrl: string; region: string } | undefined> => {
|
|
9
|
+
console.log('getHubCredentials(): calling getAxiosInstanceWithProxy()');
|
|
10
|
+
const axios = await getAxiosInstanceWithProxy();
|
|
11
|
+
console.log('getHubCredentials(): axios', axios);
|
|
12
|
+
const storage = await getStorage();
|
|
13
|
+
const deviceSerial: string = await storage.get('deviceSerial');
|
|
14
|
+
let accessKey: string = await storage.get('accessKey');
|
|
15
|
+
let deviceId: string = await storage.get('deviceId');
|
|
16
|
+
let phyhubUrl: string = await storage.get('phyhubUrl');
|
|
17
|
+
let region: string = await storage.get('region');
|
|
18
|
+
if (accessKey && deviceId && phyhubUrl) {
|
|
19
|
+
return { accessKey, deviceId, phyhubUrl, region };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
logger.info(
|
|
24
|
+
`getHubCredentials(): Fetching hub credentials for device ${deviceSerial} [${apiUrl}/provision]`
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const res = await axios.post(
|
|
28
|
+
`${apiUrl}/v1/provision`,
|
|
29
|
+
{
|
|
30
|
+
deviceSerial,
|
|
31
|
+
},
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
accessKey = res.data?.data?.accessKey;
|
|
35
|
+
deviceId = res.data?.data?._id;
|
|
36
|
+
phyhubUrl = res.data?.data?.parentDevice?.phyhubUrl;
|
|
37
|
+
region = res.data?.data?.parentDevice?.region;
|
|
38
|
+
if (!accessKey || !deviceId || !phyhubUrl || !region) {
|
|
39
|
+
throw new Error(`Credentials missing missing from response: ${JSON.stringify(res.data ?? {})}`)
|
|
40
|
+
}
|
|
41
|
+
await storage.set('accessKey', accessKey);
|
|
42
|
+
await storage.set('deviceId', deviceId);
|
|
43
|
+
await storage.set('phyhubUrl', phyhubUrl);
|
|
44
|
+
await storage.set('region', region);
|
|
45
|
+
logger.info(`getHubCredentials(): Device ${deviceId} provisioned 🟢-🟢-⚪-⚪-⚪`);
|
|
46
|
+
return { accessKey, deviceId, phyhubUrl, region };
|
|
47
|
+
} catch (err: any) {
|
|
48
|
+
logger.error(
|
|
49
|
+
`getHubCredentials(): Cannot fetch hub credentials for device ${deviceSerial} [${apiUrl}/provision] 🟢-🔴-⚪-⚪-⚪`,
|
|
50
|
+
err.toString()
|
|
51
|
+
);
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export default getHubCredentials;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import getStorage from '../storage';
|
|
2
|
+
import getAxiosInstanceWithProxy from '@phystack/axios-proxy';
|
|
3
|
+
|
|
4
|
+
const logger = console;
|
|
5
|
+
|
|
6
|
+
const getProvisioningCode = async (apiUrl: string): Promise<any> => {
|
|
7
|
+
const axios = await getAxiosInstanceWithProxy();
|
|
8
|
+
const storage = await getStorage();
|
|
9
|
+
const deviceSerial: string = await storage.get('deviceSerial');
|
|
10
|
+
const deviceId = await storage.get('deviceId');
|
|
11
|
+
const accessKey = await storage.get('accessKey');
|
|
12
|
+
const gridEnv = await storage.get('gridEnv') || 'PROD';
|
|
13
|
+
|
|
14
|
+
// If device is already provisioned, don't fetch new code
|
|
15
|
+
if (deviceId && accessKey) {
|
|
16
|
+
logger.info(`getProvisioningCode(): Device already provisioned, skipping code fetch`);
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const lastProvisioningCheckKey = `lastProvisioningCheck_${gridEnv}`;
|
|
21
|
+
const provisioningCodeKey = `provisioningCode_${gridEnv}`;
|
|
22
|
+
|
|
23
|
+
const lastProvisioningCheck = await storage.get(lastProvisioningCheckKey);
|
|
24
|
+
const currentTime = Date.now();
|
|
25
|
+
|
|
26
|
+
// If we have a recent check (within last 4.5 minutes), use cached code
|
|
27
|
+
if (lastProvisioningCheck && (currentTime - parseInt(lastProvisioningCheck)) < 270000) {
|
|
28
|
+
const existingCode = await storage.get(provisioningCodeKey);
|
|
29
|
+
if (existingCode) {
|
|
30
|
+
logger.info(`getProvisioningCode(): Using cached provisioning code ${existingCode} for env ${gridEnv}`);
|
|
31
|
+
return { provisioningCode: existingCode, deviceSerial };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const provisioningUrl = `${apiUrl}/v1/codes`;
|
|
37
|
+
const res = await axios.post(provisioningUrl, { deviceSerial });
|
|
38
|
+
const provisioningCode = res.data?.data?.code;
|
|
39
|
+
if (!provisioningCode) {
|
|
40
|
+
throw new Error(`Provisioning code missing from response: ${JSON.stringify(res.data ?? {})}`)
|
|
41
|
+
}
|
|
42
|
+
logger.info(`getProvisioningCode(): Fetched provisioning code ${provisioningCode} for env ${gridEnv} 🟢-🟢-🟢-⚪-⚪`);
|
|
43
|
+
|
|
44
|
+
// Store with environment-specific keys
|
|
45
|
+
await storage.set(provisioningCodeKey, provisioningCode);
|
|
46
|
+
await storage.set(lastProvisioningCheckKey, currentTime.toString());
|
|
47
|
+
|
|
48
|
+
return { provisioningCode, deviceSerial };
|
|
49
|
+
} catch (err: any) {
|
|
50
|
+
logger.error(`getProvisioningCode(): Cannot fetch provisioning code for env ${gridEnv} 🟢-🟢-🔴-⚪-⚪`, err.toString());
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default getProvisioningCode;
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "NodeNext",
|
|
4
|
+
"target": "es2022",
|
|
5
|
+
"outDir": "dist",
|
|
6
|
+
"rootDir": "./src",
|
|
7
|
+
"baseUrl": "src",
|
|
8
|
+
"removeComments": true,
|
|
9
|
+
"moduleResolution": "NodeNext",
|
|
10
|
+
"sourceMap": true,
|
|
11
|
+
"strict": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"alwaysStrict": true,
|
|
14
|
+
"allowJs": true,
|
|
15
|
+
"noEmitOnError": true,
|
|
16
|
+
"noFallthroughCasesInSwitch": true,
|
|
17
|
+
"noImplicitAny": true,
|
|
18
|
+
"noImplicitReturns": false,
|
|
19
|
+
"noImplicitThis": true,
|
|
20
|
+
"noUnusedLocals": true,
|
|
21
|
+
"noUnusedParameters": true,
|
|
22
|
+
"strictBindCallApply": true,
|
|
23
|
+
"strictNullChecks": true,
|
|
24
|
+
"allowSyntheticDefaultImports": true,
|
|
25
|
+
"resolveJsonModule": true,
|
|
26
|
+
"esModuleInterop": true,
|
|
27
|
+
"declarationDir": "dist",
|
|
28
|
+
"declarationMap": true,
|
|
29
|
+
"declaration": true,
|
|
30
|
+
"paths": {
|
|
31
|
+
"@/*": ["*"]
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"include": [
|
|
35
|
+
"./src/**/*"
|
|
36
|
+
, "src/__tests__" ],
|
|
37
|
+
"exclude": [
|
|
38
|
+
"node_modules/**/*",
|
|
39
|
+
".serverless/**/*",
|
|
40
|
+
".webpack/**/*",
|
|
41
|
+
"_warmup/**/*",
|
|
42
|
+
"dist/**/*",
|
|
43
|
+
".vscode/**/*",
|
|
44
|
+
],
|
|
45
|
+
}
|