@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.
Files changed (82) hide show
  1. package/.prettierignore +10 -0
  2. package/.prettierrc +10 -0
  3. package/CHANGELOG.md +1202 -0
  4. package/README.md +12 -0
  5. package/dist/index.d.ts +114 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +967 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/storage/browser.d.ts +2 -0
  10. package/dist/storage/browser.d.ts.map +1 -0
  11. package/dist/storage/browser.js +20 -0
  12. package/dist/storage/browser.js.map +1 -0
  13. package/dist/storage/index.d.ts +6 -0
  14. package/dist/storage/index.d.ts.map +1 -0
  15. package/dist/storage/index.js +31 -0
  16. package/dist/storage/index.js.map +1 -0
  17. package/dist/storage/node.d.ts +2 -0
  18. package/dist/storage/node.d.ts.map +1 -0
  19. package/dist/storage/node.js +47 -0
  20. package/dist/storage/node.js.map +1 -0
  21. package/dist/sysinfo/browser.d.ts +3 -0
  22. package/dist/sysinfo/browser.d.ts.map +1 -0
  23. package/dist/sysinfo/browser.js +194 -0
  24. package/dist/sysinfo/browser.js.map +1 -0
  25. package/dist/sysinfo/index.d.ts +3 -0
  26. package/dist/sysinfo/index.d.ts.map +1 -0
  27. package/dist/sysinfo/index.js +34 -0
  28. package/dist/sysinfo/index.js.map +1 -0
  29. package/dist/sysinfo/node.d.ts +3 -0
  30. package/dist/sysinfo/node.d.ts.map +1 -0
  31. package/dist/sysinfo/node.js +53 -0
  32. package/dist/sysinfo/node.js.map +1 -0
  33. package/dist/sysinfo/tizen.d.ts +8 -0
  34. package/dist/sysinfo/tizen.d.ts.map +1 -0
  35. package/dist/sysinfo/tizen.js +168 -0
  36. package/dist/sysinfo/tizen.js.map +1 -0
  37. package/dist/types/command.types.d.ts +8 -0
  38. package/dist/types/command.types.d.ts.map +1 -0
  39. package/dist/types/command.types.js +8 -0
  40. package/dist/types/command.types.js.map +1 -0
  41. package/dist/types/container.types.d.ts +10 -0
  42. package/dist/types/container.types.d.ts.map +1 -0
  43. package/dist/types/container.types.js +3 -0
  44. package/dist/types/container.types.js.map +1 -0
  45. package/dist/types/job.types.d.ts +31 -0
  46. package/dist/types/job.types.d.ts.map +1 -0
  47. package/dist/types/job.types.js +15 -0
  48. package/dist/types/job.types.js.map +1 -0
  49. package/dist/types/twin.types.d.ts +653 -0
  50. package/dist/types/twin.types.d.ts.map +1 -0
  51. package/dist/types/twin.types.js +21 -0
  52. package/dist/types/twin.types.js.map +1 -0
  53. package/dist/utilities/get-device-identifier.utility.d.ts +2 -0
  54. package/dist/utilities/get-device-identifier.utility.d.ts.map +1 -0
  55. package/dist/utilities/get-device-identifier.utility.js +140 -0
  56. package/dist/utilities/get-device-identifier.utility.js.map +1 -0
  57. package/dist/utilities/get-hub-credentials.utility.d.ts +8 -0
  58. package/dist/utilities/get-hub-credentials.utility.d.ts.map +1 -0
  59. package/dist/utilities/get-hub-credentials.utility.js +47 -0
  60. package/dist/utilities/get-hub-credentials.utility.js.map +1 -0
  61. package/dist/utilities/get-provisioning-code.utility.d.ts +3 -0
  62. package/dist/utilities/get-provisioning-code.utility.d.ts.map +1 -0
  63. package/dist/utilities/get-provisioning-code.utility.js +49 -0
  64. package/dist/utilities/get-provisioning-code.utility.js.map +1 -0
  65. package/package.json +39 -0
  66. package/src/hub-device.d.ts +0 -0
  67. package/src/index.ts +1228 -0
  68. package/src/storage/browser.ts +16 -0
  69. package/src/storage/index.ts +46 -0
  70. package/src/storage/node.ts +42 -0
  71. package/src/sysinfo/browser.ts +217 -0
  72. package/src/sysinfo/index.ts +29 -0
  73. package/src/sysinfo/node.ts +387 -0
  74. package/src/sysinfo/tizen.ts +203 -0
  75. package/src/types/command.types.ts +8 -0
  76. package/src/types/container.types.ts +12 -0
  77. package/src/types/job.types.ts +36 -0
  78. package/src/types/twin.types.ts +751 -0
  79. package/src/utilities/get-device-identifier.utility.ts +179 -0
  80. package/src/utilities/get-hub-credentials.utility.ts +56 -0
  81. package/src/utilities/get-provisioning-code.utility.ts +55 -0
  82. 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
+ }