@symbo.ls/cli 2.33.11 → 2.33.13
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/bin/collab.js +334 -0
- package/bin/fetch.js +77 -54
- package/bin/fs.js +150 -61
- package/bin/index.js +1 -0
- package/bin/install.js +6 -19
- package/bin/login.js +82 -62
- package/bin/push.js +157 -117
- package/bin/require.js +140 -6
- package/bin/socket-server.js +5 -10
- package/bin/sync.js +313 -112
- package/helpers/apiUtils.js +60 -58
- package/helpers/buildMessages.js +76 -0
- package/helpers/changesUtils.js +474 -0
- package/helpers/compareUtils.js +136 -2
- package/helpers/config.js +131 -18
- package/helpers/credentialManager.js +66 -0
- package/helpers/fileUtils.js +8 -2
- package/helpers/symbolsConfig.js +35 -0
- package/helpers/transportUtils.js +58 -0
- package/package.json +7 -5
package/helpers/config.js
CHANGED
|
@@ -1,27 +1,140 @@
|
|
|
1
1
|
import fs from 'fs'
|
|
2
2
|
import path from 'path'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
// New configuration layout
|
|
5
|
+
// .symbols/config.json -> project runtime configuration (apiBaseUrl, projectKey|projectId, branch)
|
|
6
|
+
// .symbols/lock.json -> last pulled snapshot metadata (etag, version, projectId, branch, pulledAt)
|
|
7
|
+
// Backward compatibility:
|
|
8
|
+
// - Keep reading legacy .smblsrc and symbols.json when present
|
|
9
|
+
|
|
10
|
+
const CWD = process.cwd()
|
|
11
|
+
const SYMBOLS_DIR = path.join(CWD, '.symbols')
|
|
12
|
+
const CONFIG_PATH = path.join(SYMBOLS_DIR, 'config.json')
|
|
13
|
+
const LOCK_PATH = path.join(SYMBOLS_DIR, 'lock.json')
|
|
14
|
+
const PROJECT_JSON_PATH = path.join(SYMBOLS_DIR, 'project.json')
|
|
15
|
+
const LEGACY_RC_PATH = path.join(CWD, '.smblsrc')
|
|
16
|
+
const LEGACY_SYMBOLS_JSON = path.join(CWD, 'symbols.json')
|
|
17
|
+
|
|
18
|
+
function ensureDir(dir) {
|
|
19
|
+
try {
|
|
20
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })
|
|
21
|
+
} catch (_) {
|
|
22
|
+
// ignore
|
|
7
23
|
}
|
|
24
|
+
}
|
|
8
25
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
26
|
+
function readJsonSafe(filePath) {
|
|
27
|
+
try {
|
|
28
|
+
if (!fs.existsSync(filePath)) return null
|
|
29
|
+
const content = fs.readFileSync(filePath, 'utf8')
|
|
30
|
+
return JSON.parse(content)
|
|
31
|
+
} catch (_) {
|
|
32
|
+
return null
|
|
17
33
|
}
|
|
34
|
+
}
|
|
18
35
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
36
|
+
function writeJsonSafe(filePath, data) {
|
|
37
|
+
ensureDir(path.dirname(filePath))
|
|
38
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function getConfigPaths() {
|
|
42
|
+
return {
|
|
43
|
+
symbolsDir: SYMBOLS_DIR,
|
|
44
|
+
configPath: CONFIG_PATH,
|
|
45
|
+
lockPath: LOCK_PATH,
|
|
46
|
+
projectPath: PROJECT_JSON_PATH,
|
|
47
|
+
legacySmblsrc: LEGACY_RC_PATH,
|
|
48
|
+
legacySymbolsJson: LEGACY_SYMBOLS_JSON
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function loadCliConfig() {
|
|
53
|
+
// Env overrides first
|
|
54
|
+
const envApi =
|
|
55
|
+
process.env.SYMBOLS_API_BASE_URL ||
|
|
56
|
+
process.env.SMBLS_API_URL // backward compat
|
|
57
|
+
const envProjectKey = process.env.SYMBOLS_PROJECT_KEY
|
|
58
|
+
const envProjectId = process.env.SYMBOLS_PROJECT_ID
|
|
59
|
+
const envBranch = process.env.SYMBOLS_BRANCH
|
|
60
|
+
|
|
61
|
+
// New config layout
|
|
62
|
+
const symbolsConfig = readJsonSafe(CONFIG_PATH) || {}
|
|
63
|
+
|
|
64
|
+
// Legacy project identifiers and defaults from symbols.json
|
|
65
|
+
const legacySymbols = readJsonSafe(LEGACY_SYMBOLS_JSON) || {}
|
|
66
|
+
|
|
67
|
+
// Legacy rc might include apiUrl
|
|
68
|
+
const legacyRc = readJsonSafe(LEGACY_RC_PATH) || {}
|
|
69
|
+
|
|
70
|
+
const apiBaseUrl =
|
|
71
|
+
envApi ||
|
|
72
|
+
symbolsConfig.apiBaseUrl ||
|
|
73
|
+
legacyRc.apiUrl ||
|
|
74
|
+
// default to production if nothing set
|
|
75
|
+
'https://api.symbols.app'
|
|
76
|
+
|
|
77
|
+
const projectKey = envProjectKey || symbolsConfig.projectKey || legacySymbols.key
|
|
78
|
+
const projectId = envProjectId || symbolsConfig.projectId || null
|
|
79
|
+
const branch = envBranch || symbolsConfig.branch || legacySymbols.branch || 'main'
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
apiBaseUrl,
|
|
83
|
+
projectKey,
|
|
84
|
+
projectId,
|
|
85
|
+
branch,
|
|
86
|
+
// expose raw sources for advanced usage
|
|
87
|
+
_raw: {
|
|
88
|
+
symbolsConfig,
|
|
89
|
+
legacySymbols,
|
|
90
|
+
legacyRc
|
|
91
|
+
}
|
|
26
92
|
}
|
|
27
93
|
}
|
|
94
|
+
|
|
95
|
+
export function saveCliConfig(partial) {
|
|
96
|
+
const current = readJsonSafe(CONFIG_PATH) || {}
|
|
97
|
+
const next = { ...current, ...partial }
|
|
98
|
+
writeJsonSafe(CONFIG_PATH, next)
|
|
99
|
+
return next
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function readLock() {
|
|
103
|
+
return readJsonSafe(LOCK_PATH) || {}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function writeLock(partial) {
|
|
107
|
+
const current = readJsonSafe(LOCK_PATH) || {}
|
|
108
|
+
const next = { ...current, ...partial }
|
|
109
|
+
writeJsonSafe(LOCK_PATH, next)
|
|
110
|
+
return next
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function getApiUrl() {
|
|
114
|
+
// Prefer new env var and config
|
|
115
|
+
const { apiBaseUrl } = loadCliConfig()
|
|
116
|
+
return apiBaseUrl
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function getProjectKeyOrId() {
|
|
120
|
+
const { projectKey, projectId } = loadCliConfig()
|
|
121
|
+
return { projectKey, projectId }
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function getBranch() {
|
|
125
|
+
const { branch } = loadCliConfig()
|
|
126
|
+
return branch || 'main'
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function ensureSymbolsDir() {
|
|
130
|
+
ensureDir(SYMBOLS_DIR)
|
|
131
|
+
return SYMBOLS_DIR
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Helper for legacy projects to keep version/branch updates in symbols.json
|
|
135
|
+
export function updateLegacySymbolsJson(partial) {
|
|
136
|
+
const current = readJsonSafe(LEGACY_SYMBOLS_JSON) || {}
|
|
137
|
+
const next = { ...current, ...partial }
|
|
138
|
+
writeJsonSafe(LEGACY_SYMBOLS_JSON, next)
|
|
139
|
+
return next
|
|
140
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import os from 'os'
|
|
4
|
+
|
|
5
|
+
const RC_FILE = '.smblsrc'
|
|
6
|
+
|
|
7
|
+
export class CredentialManager {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.rcPath = path.join(os.homedir(), RC_FILE)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Load credentials from rc file
|
|
13
|
+
loadCredentials() {
|
|
14
|
+
try {
|
|
15
|
+
const data = fs.readFileSync(this.rcPath, 'utf8')
|
|
16
|
+
return JSON.parse(data)
|
|
17
|
+
} catch (err) {
|
|
18
|
+
return {}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Save credentials to rc file
|
|
23
|
+
saveCredentials(credentials) {
|
|
24
|
+
try {
|
|
25
|
+
const existing = this.loadCredentials()
|
|
26
|
+
const merged = { ...existing, ...credentials }
|
|
27
|
+
fs.writeFileSync(this.rcPath, JSON.stringify(merged, null, 2))
|
|
28
|
+
return true
|
|
29
|
+
} catch (err) {
|
|
30
|
+
console.error('Failed to save credentials:', err)
|
|
31
|
+
return false
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Get stored auth token
|
|
36
|
+
getAuthToken() {
|
|
37
|
+
const envToken = process.env.SYMBOLS_TOKEN || process.env.SMBLS_TOKEN
|
|
38
|
+
if (envToken) return envToken
|
|
39
|
+
const creds = this.loadCredentials()
|
|
40
|
+
return creds.authToken || creds.token || creds.accessToken || creds.jwt
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Ensure token presence; returns token or null
|
|
44
|
+
ensureAuthToken() {
|
|
45
|
+
const token = this.getAuthToken()
|
|
46
|
+
return token || null
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Optional: get refresh token if present
|
|
50
|
+
getRefreshToken() {
|
|
51
|
+
const envToken = process.env.SYMBOLS_REFRESH_TOKEN
|
|
52
|
+
if (envToken) return envToken
|
|
53
|
+
const creds = this.loadCredentials()
|
|
54
|
+
return creds.refreshToken || null
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Clear stored credentials
|
|
58
|
+
clearCredentials() {
|
|
59
|
+
try {
|
|
60
|
+
fs.unlinkSync(this.rcPath)
|
|
61
|
+
return true
|
|
62
|
+
} catch (err) {
|
|
63
|
+
return false
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
package/helpers/fileUtils.js
CHANGED
|
@@ -36,12 +36,18 @@ async function buildFromFile (inputFilePath, outputFilePath) {
|
|
|
36
36
|
},
|
|
37
37
|
minify: false,
|
|
38
38
|
outfile: outputFilePath,
|
|
39
|
-
target: '
|
|
39
|
+
target: 'node16',
|
|
40
40
|
platform: 'node',
|
|
41
41
|
format: 'cjs',
|
|
42
42
|
bundle: true,
|
|
43
43
|
mainFields: ['module', 'main'],
|
|
44
|
-
external: ['esbuild']
|
|
44
|
+
external: ['esbuild'],
|
|
45
|
+
define: {
|
|
46
|
+
window: 'undefined',
|
|
47
|
+
document: 'undefined',
|
|
48
|
+
navigator: 'undefined',
|
|
49
|
+
global: '{}'
|
|
50
|
+
}
|
|
45
51
|
})
|
|
46
52
|
} catch (error) {
|
|
47
53
|
console.error('Error building file:', error)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import chalk from 'chalk'
|
|
3
|
+
import { loadModule } from '../bin/require.js'
|
|
4
|
+
|
|
5
|
+
const RC_PATH = process.cwd() + '/symbols.json'
|
|
6
|
+
|
|
7
|
+
export const loadSymbolsConfig = async (options = {}) => {
|
|
8
|
+
const {
|
|
9
|
+
required = true,
|
|
10
|
+
validateKey = true,
|
|
11
|
+
silent = false
|
|
12
|
+
} = options
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
const config = await loadModule(RC_PATH, { json: true })
|
|
16
|
+
|
|
17
|
+
if (validateKey && (!config || !config.key)) {
|
|
18
|
+
throw new Error('Missing app key in symbols.json')
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return config
|
|
22
|
+
} catch (error) {
|
|
23
|
+
if (error.message.includes('Missing app key')) {
|
|
24
|
+
console.error(chalk.bold.red('\nInvalid symbols.json configuration:'))
|
|
25
|
+
console.error(chalk.white('The file must contain a valid app key.'))
|
|
26
|
+
console.error(chalk.bold.yellow('\nExample symbols.json:'))
|
|
27
|
+
console.error(chalk.cyan(JSON.stringify({ key: 'your.app.key' }, null, 2)))
|
|
28
|
+
} else if (!silent) {
|
|
29
|
+
console.error(chalk.bold.red('Please include symbols.json in your repository root'))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (required) process.exit(1)
|
|
33
|
+
return null
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Utilities for preparing data for transport to the Symbols API.
|
|
2
|
+
// Mirrors the behaviour used in the web app for serialising functions.
|
|
3
|
+
|
|
4
|
+
// Keys that should be skipped entirely when cloning for transport.
|
|
5
|
+
// These typically contain non-serialisable metadata or runtime-only values.
|
|
6
|
+
// NOTE: This list can be extended to stay in sync with the webapp if needed.
|
|
7
|
+
export const FUNCTION_META_KEYS = [
|
|
8
|
+
// Internal / meta fields that should not be transported
|
|
9
|
+
'__fn',
|
|
10
|
+
'__fnMeta',
|
|
11
|
+
'__handler',
|
|
12
|
+
'__meta'
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Recursively clones a value and stringifies any functions so that the
|
|
17
|
+
* result is JSON-serialisable and safe to send over the wire.
|
|
18
|
+
*
|
|
19
|
+
* This intentionally skips keys listed in FUNCTION_META_KEYS to avoid
|
|
20
|
+
* leaking internal runtime metadata.
|
|
21
|
+
*
|
|
22
|
+
* @param {any} value
|
|
23
|
+
* @param {WeakMap<object, any>} [seen]
|
|
24
|
+
* @returns {any}
|
|
25
|
+
*/
|
|
26
|
+
export function stringifyFunctionsForTransport (value, seen = new WeakMap()) {
|
|
27
|
+
// Primitive values or functions
|
|
28
|
+
if (value === null || typeof value !== 'object') {
|
|
29
|
+
return typeof value === 'function' ? value.toString() : value
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Handle circular references
|
|
33
|
+
if (seen.has(value)) {
|
|
34
|
+
return seen.get(value)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const clone = Array.isArray(value) ? [] : {}
|
|
38
|
+
seen.set(value, clone)
|
|
39
|
+
|
|
40
|
+
if (Array.isArray(value)) {
|
|
41
|
+
for (let i = 0; i < value.length; i++) {
|
|
42
|
+
clone[i] = stringifyFunctionsForTransport(value[i], seen)
|
|
43
|
+
}
|
|
44
|
+
return clone
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const keys = Object.keys(value)
|
|
48
|
+
for (let i = 0; i < keys.length; i++) {
|
|
49
|
+
const key = keys[i]
|
|
50
|
+
if (!FUNCTION_META_KEYS.includes(key)) {
|
|
51
|
+
clone[key] = stringifyFunctionsForTransport(value[key], seen)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return clone
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbo.ls/cli",
|
|
3
|
-
"version": "2.33.
|
|
3
|
+
"version": "2.33.13",
|
|
4
4
|
"description": "Fetch your Symbols configuration",
|
|
5
5
|
"main": "bin/fetch.js",
|
|
6
6
|
"author": "Symbols",
|
|
@@ -15,16 +15,18 @@
|
|
|
15
15
|
"vpatch": "npm version patch && npm publish"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@symbo.ls/fetch": "^2.33.
|
|
19
|
-
"@symbo.ls/init": "^2.33.
|
|
20
|
-
"@symbo.ls/socket": "^2.33.
|
|
18
|
+
"@symbo.ls/fetch": "^2.33.13",
|
|
19
|
+
"@symbo.ls/init": "^2.33.13",
|
|
20
|
+
"@symbo.ls/socket": "^2.33.13",
|
|
21
21
|
"chalk": "^5.4.1",
|
|
22
|
+
"chokidar": "^4.0.3",
|
|
22
23
|
"commander": "^13.1.0",
|
|
23
24
|
"diff": "^5.2.0",
|
|
24
25
|
"esbuild": "^0.25.1",
|
|
25
26
|
"inquirer": "^12.9.0",
|
|
26
27
|
"node-fetch": "^3.3.2",
|
|
28
|
+
"socket.io-client": "^4.8.1",
|
|
27
29
|
"v8-compile-cache": "^2.4.0"
|
|
28
30
|
},
|
|
29
|
-
"gitHead": "
|
|
31
|
+
"gitHead": "3d34d72f2ada44fdb269644cc915d3ef84cfe360"
|
|
30
32
|
}
|