@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/helpers/config.js CHANGED
@@ -1,27 +1,140 @@
1
1
  import fs from 'fs'
2
2
  import path from 'path'
3
3
 
4
- export const getApiUrl = () => {
5
- if (process.env.SMBLS_API_URL) {
6
- return process.env.SMBLS_API_URL
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
- const configPath = path.join(process.cwd(), '.smblsrc.json')
10
- if (fs.existsSync(configPath)) {
11
- try {
12
- const config = JSON.parse(fs.readFileSync(configPath, 'utf8'))
13
- if (config.apiUrl) return config.apiUrl
14
- } catch (err) {
15
- // Silently fail and use defaults if config file is invalid
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
- switch (process.env.NODE_ENV) {
20
- case 'production':
21
- return 'https://api.symbols.app'
22
- case 'staging':
23
- return 'https://api-staging.symbols.app'
24
- default:
25
- return 'http://localhost:8080'
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
+ }
@@ -36,12 +36,18 @@ async function buildFromFile (inputFilePath, outputFilePath) {
36
36
  },
37
37
  minify: false,
38
38
  outfile: outputFilePath,
39
- target: 'node14',
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.11",
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.11",
19
- "@symbo.ls/init": "^2.33.11",
20
- "@symbo.ls/socket": "^2.33.11",
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": "bd35281698ecf0b85f212fa22e3ee66a5053c2bb"
31
+ "gitHead": "3d34d72f2ada44fdb269644cc915d3ef84cfe360"
30
32
  }