@localess/cli 0.0.1-dev.20260216094809
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/README.md +62 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +517 -0
- package/dist/index.mjs +494 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<br/>
|
|
2
|
+
<br/>
|
|
3
|
+
<img src="https://github.com/Lessify/localess/wiki/img/logo-adaptive.svg" alt="logo">
|
|
4
|
+
<br/>
|
|
5
|
+
<br/>
|
|
6
|
+
|
|
7
|
+
----
|
|
8
|
+
|
|
9
|
+
# Localess Command Line
|
|
10
|
+
|
|
11
|
+
This client SDK is designed to work with the Localess API. It provides a simple way to interact with the Localess API from your JavaScript or TypeScript application.
|
|
12
|
+
|
|
13
|
+
> **Important:**
|
|
14
|
+
> The Client is designed to be used on the server side only, as it requires your **Localess API Token** to be kept secret.
|
|
15
|
+
> Do not use this client in your frontend application, as it exposes your API Token to the public.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
### NPM
|
|
20
|
+
````bash
|
|
21
|
+
npm install @localess/js-client@latest
|
|
22
|
+
````
|
|
23
|
+
|
|
24
|
+
### Yarn
|
|
25
|
+
````bash
|
|
26
|
+
yarn add @localess/js-client@latest
|
|
27
|
+
````
|
|
28
|
+
|
|
29
|
+
## Client
|
|
30
|
+
|
|
31
|
+
````ts
|
|
32
|
+
import {localessClient} from "@localess/js-client";
|
|
33
|
+
|
|
34
|
+
const llClient = localessClient({
|
|
35
|
+
// A fully qualified domain name with protocol (http/https) and port.
|
|
36
|
+
origin: 'https://my-localess.web.app',
|
|
37
|
+
// Localess space ID, cna be found in the Localess Space settings
|
|
38
|
+
spaceId: 'I1LoVe2LocaLess4Rever',
|
|
39
|
+
// Localess API token, can be found in the Localess Space settings
|
|
40
|
+
token: 'Baz00KaT0KeN8S3CureLL'
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Fetch all Content Links
|
|
44
|
+
llClient.getLinks()
|
|
45
|
+
// Fetch content by SLUG
|
|
46
|
+
llClient.getContentBySlug('docs/overview')
|
|
47
|
+
// Fetch content by ID
|
|
48
|
+
llClient.getContentById('FRnIT7CUABoRCdSVVGGs')
|
|
49
|
+
// Fetch translations by locale
|
|
50
|
+
llClient.getTranslations('en')
|
|
51
|
+
````
|
|
52
|
+
|
|
53
|
+
## Sync with Visual Editor
|
|
54
|
+
|
|
55
|
+
It will automatically inject Localess Sync Script in to the HTML page.
|
|
56
|
+
|
|
57
|
+
````ts
|
|
58
|
+
import {loadLocalessSync} from "@localess/js-client";
|
|
59
|
+
|
|
60
|
+
// A fully qualified domain name with protocol (http/https) and port.
|
|
61
|
+
loadLocalessSync('https://my-localess.web.app')
|
|
62
|
+
````
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/program.ts
|
|
27
|
+
var import_commander4 = require("commander");
|
|
28
|
+
|
|
29
|
+
// src/commands/login/index.ts
|
|
30
|
+
var import_commander = require("commander");
|
|
31
|
+
|
|
32
|
+
// src/utils.ts
|
|
33
|
+
var RESET = "\x1B[0m";
|
|
34
|
+
var FG_BLUE = "\x1B[34m";
|
|
35
|
+
|
|
36
|
+
// src/cache.ts
|
|
37
|
+
var NoCache = class {
|
|
38
|
+
set(key, value) {
|
|
39
|
+
}
|
|
40
|
+
get(key) {
|
|
41
|
+
return void 0;
|
|
42
|
+
}
|
|
43
|
+
has(key) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
var TTLCache = class {
|
|
48
|
+
/**
|
|
49
|
+
* Creates a TTLCache with a specified time-to-live (TTL) for each entry.
|
|
50
|
+
* default is 5 minutes (300000 ms).
|
|
51
|
+
* @param ttlMs
|
|
52
|
+
*/
|
|
53
|
+
constructor(ttlMs = 3e5) {
|
|
54
|
+
this.ttlMs = ttlMs;
|
|
55
|
+
}
|
|
56
|
+
cache = /* @__PURE__ */ new Map();
|
|
57
|
+
set(key, value) {
|
|
58
|
+
this.cache.set(key, { value, expiresAt: Date.now() + this.ttlMs });
|
|
59
|
+
}
|
|
60
|
+
get(key) {
|
|
61
|
+
const entry = this.cache.get(key);
|
|
62
|
+
if (!entry) return void 0;
|
|
63
|
+
if (Date.now() > entry.expiresAt) {
|
|
64
|
+
this.cache.delete(key);
|
|
65
|
+
return void 0;
|
|
66
|
+
}
|
|
67
|
+
return entry.value;
|
|
68
|
+
}
|
|
69
|
+
has(key) {
|
|
70
|
+
return this.get(key) !== void 0;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// src/client.ts
|
|
75
|
+
var LOG_GROUP = `${FG_BLUE}[Localess:Client]${RESET}`;
|
|
76
|
+
function localessClient(options) {
|
|
77
|
+
if (options.debug) {
|
|
78
|
+
console.log(LOG_GROUP, "Client Options : ", options);
|
|
79
|
+
}
|
|
80
|
+
const fetchOptions = {
|
|
81
|
+
redirect: "follow",
|
|
82
|
+
headers: {
|
|
83
|
+
"Content-Type": "application/json",
|
|
84
|
+
"Accept": "application/json",
|
|
85
|
+
"X-Localess-Agent": "Localess-CLI-Client",
|
|
86
|
+
"X-Localess-Agent-Version": "0.9.0"
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const cache = options.cacheTTL === false ? new NoCache() : new TTLCache(options.cacheTTL);
|
|
90
|
+
return {
|
|
91
|
+
async getSpace() {
|
|
92
|
+
if (options.debug) {
|
|
93
|
+
console.log(LOG_GROUP, "getSpace()");
|
|
94
|
+
}
|
|
95
|
+
let url = `${options.origin}/api/v1/spaces/${options.spaceId}?token=${options.token}`;
|
|
96
|
+
if (options.debug) {
|
|
97
|
+
console.log(LOG_GROUP, "getSpace fetch url : ", url);
|
|
98
|
+
}
|
|
99
|
+
if (cache.has(url)) {
|
|
100
|
+
if (options.debug) {
|
|
101
|
+
console.log(LOG_GROUP, "getSpace cache hit");
|
|
102
|
+
}
|
|
103
|
+
return cache.get(url);
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
const response = await fetch(url, fetchOptions);
|
|
107
|
+
if (options.debug) {
|
|
108
|
+
console.log(LOG_GROUP, "getSpace status : ", response.status);
|
|
109
|
+
}
|
|
110
|
+
const data = await response.json();
|
|
111
|
+
cache.set(url, data);
|
|
112
|
+
return data;
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.error(LOG_GROUP, "getSpace error : ", error);
|
|
115
|
+
return {};
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
async getLinks(params) {
|
|
119
|
+
if (options.debug) {
|
|
120
|
+
console.log(LOG_GROUP, "getLinks() params : ", JSON.stringify(params));
|
|
121
|
+
}
|
|
122
|
+
let kind = "";
|
|
123
|
+
if (params?.kind) {
|
|
124
|
+
kind = `&kind=${params.kind}`;
|
|
125
|
+
}
|
|
126
|
+
let parentSlug = "";
|
|
127
|
+
if (params?.parentSlug) {
|
|
128
|
+
parentSlug = `&parentSlug=${params.parentSlug}`;
|
|
129
|
+
}
|
|
130
|
+
let excludeChildren = "";
|
|
131
|
+
if (params?.excludeChildren) {
|
|
132
|
+
excludeChildren = `&excludeChildren=${params.excludeChildren}`;
|
|
133
|
+
}
|
|
134
|
+
let url = `${options.origin}/api/v1/spaces/${options.spaceId}/links?token=${options.token}${kind}${parentSlug}${excludeChildren}`;
|
|
135
|
+
if (options.debug) {
|
|
136
|
+
console.log(LOG_GROUP, "getLinks fetch url : ", url);
|
|
137
|
+
}
|
|
138
|
+
if (cache.has(url)) {
|
|
139
|
+
if (options.debug) {
|
|
140
|
+
console.log(LOG_GROUP, "getLinks cache hit");
|
|
141
|
+
}
|
|
142
|
+
return cache.get(url);
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const response = await fetch(url, fetchOptions);
|
|
146
|
+
if (options.debug) {
|
|
147
|
+
console.log(LOG_GROUP, "getLinks status : ", response.status);
|
|
148
|
+
}
|
|
149
|
+
const data = await response.json();
|
|
150
|
+
cache.set(url, data);
|
|
151
|
+
return data;
|
|
152
|
+
} catch (error) {
|
|
153
|
+
console.error(LOG_GROUP, "getLinks error : ", error);
|
|
154
|
+
return {};
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
async getContentBySlug(slug, params) {
|
|
158
|
+
if (options.debug) {
|
|
159
|
+
console.log(LOG_GROUP, "getContentBySlug() slug : ", slug);
|
|
160
|
+
console.log(LOG_GROUP, "getContentBySlug() params : ", JSON.stringify(params));
|
|
161
|
+
}
|
|
162
|
+
let version = "";
|
|
163
|
+
if (options?.version && options.version == "draft") {
|
|
164
|
+
version = `&version=${options.version}`;
|
|
165
|
+
}
|
|
166
|
+
if (params?.version && params.version == "draft") {
|
|
167
|
+
version = `&version=${params.version}`;
|
|
168
|
+
}
|
|
169
|
+
const locale = params?.locale ? `&locale=${params.locale}` : "";
|
|
170
|
+
const resolveReference = params?.resolveReference ? `&resolveReference=${params.resolveReference}` : "";
|
|
171
|
+
const resolveLink = params?.resolveLink ? `&resolveLink=${params.resolveLink}` : "";
|
|
172
|
+
let url = `${options.origin}/api/v1/spaces/${options.spaceId}/contents/slugs/${slug}?token=${options.token}${version}${locale}${resolveReference}${resolveLink}`;
|
|
173
|
+
if (options.debug) {
|
|
174
|
+
console.log(LOG_GROUP, "getContentBySlug fetch url : ", url);
|
|
175
|
+
}
|
|
176
|
+
if (cache.has(url)) {
|
|
177
|
+
if (options.debug) {
|
|
178
|
+
console.log(LOG_GROUP, "getContentBySlug cache hit");
|
|
179
|
+
}
|
|
180
|
+
return cache.get(url);
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
const response = await fetch(url, fetchOptions);
|
|
184
|
+
if (options.debug) {
|
|
185
|
+
console.log(LOG_GROUP, "getContentBySlug status : ", response.status);
|
|
186
|
+
}
|
|
187
|
+
const data = await response.json();
|
|
188
|
+
cache.set(url, data);
|
|
189
|
+
return data;
|
|
190
|
+
} catch (error) {
|
|
191
|
+
console.error(LOG_GROUP, "getContentBySlug error : ", error);
|
|
192
|
+
return {};
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
async getContentById(id, params) {
|
|
196
|
+
if (options.debug) {
|
|
197
|
+
console.log(LOG_GROUP, "getContentById() id : ", id);
|
|
198
|
+
console.log(LOG_GROUP, "getContentById() params : ", JSON.stringify(params));
|
|
199
|
+
}
|
|
200
|
+
let version = "";
|
|
201
|
+
if (options?.version && options.version == "draft") {
|
|
202
|
+
version = `&version=${options.version}`;
|
|
203
|
+
}
|
|
204
|
+
if (params?.version && params.version == "draft") {
|
|
205
|
+
version = `&version=${params.version}`;
|
|
206
|
+
}
|
|
207
|
+
const locale = params?.locale ? `&locale=${params.locale}` : "";
|
|
208
|
+
const resolveReference = params?.resolveReference ? `&resolveReference=${params.resolveReference}` : "";
|
|
209
|
+
const resolveLink = params?.resolveLink ? `&resolveLink=${params.resolveLink}` : "";
|
|
210
|
+
let url = `${options.origin}/api/v1/spaces/${options.spaceId}/contents/${id}?token=${options.token}${version}${locale}${resolveReference}${resolveLink}`;
|
|
211
|
+
if (options.debug) {
|
|
212
|
+
console.log(LOG_GROUP, "getContentById fetch url : ", url);
|
|
213
|
+
}
|
|
214
|
+
if (cache.has(url)) {
|
|
215
|
+
if (options.debug) {
|
|
216
|
+
console.log(LOG_GROUP, "getContentById cache hit");
|
|
217
|
+
}
|
|
218
|
+
return cache.get(url);
|
|
219
|
+
}
|
|
220
|
+
try {
|
|
221
|
+
const response = await fetch(url, fetchOptions);
|
|
222
|
+
if (options.debug) {
|
|
223
|
+
console.log(LOG_GROUP, "getContentById status : ", response.status);
|
|
224
|
+
}
|
|
225
|
+
const data = await response.json();
|
|
226
|
+
cache.set(url, data);
|
|
227
|
+
return data;
|
|
228
|
+
} catch (error) {
|
|
229
|
+
console.error(LOG_GROUP, "getContentById error : ", error);
|
|
230
|
+
return {};
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
async getTranslations(locale) {
|
|
234
|
+
if (options.debug) {
|
|
235
|
+
console.log(LOG_GROUP, "getTranslations() locale : ", locale);
|
|
236
|
+
}
|
|
237
|
+
let url = `${options.origin}/api/v1/spaces/${options.spaceId}/translations/${locale}?token=${options.token}`;
|
|
238
|
+
if (options.debug) {
|
|
239
|
+
console.log(LOG_GROUP, "getTranslations fetch url : ", url);
|
|
240
|
+
}
|
|
241
|
+
if (cache.has(url)) {
|
|
242
|
+
if (options.debug) {
|
|
243
|
+
console.log(LOG_GROUP, "getTranslations cache hit");
|
|
244
|
+
}
|
|
245
|
+
return cache.get(url);
|
|
246
|
+
}
|
|
247
|
+
try {
|
|
248
|
+
const response = await fetch(url, fetchOptions);
|
|
249
|
+
if (options.debug) {
|
|
250
|
+
console.log(LOG_GROUP, "getTranslations status : ", response.status);
|
|
251
|
+
}
|
|
252
|
+
const data = await response.json();
|
|
253
|
+
cache.set(url, data);
|
|
254
|
+
return data;
|
|
255
|
+
} catch (error) {
|
|
256
|
+
console.error(LOG_GROUP, "getTranslations error : ", error);
|
|
257
|
+
return {};
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
async updateTranslations(locale, type, values) {
|
|
261
|
+
if (options.debug) {
|
|
262
|
+
console.log(LOG_GROUP, "updateTranslations() locale : ", locale);
|
|
263
|
+
console.log(LOG_GROUP, "updateTranslations() type : ", type);
|
|
264
|
+
console.log(LOG_GROUP, "updateTranslations() values : ", JSON.stringify(values));
|
|
265
|
+
}
|
|
266
|
+
let url = `${options.origin}/api/v1/spaces/${options.spaceId}/translations/${locale}`;
|
|
267
|
+
if (options.debug) {
|
|
268
|
+
console.log(LOG_GROUP, "updateTranslations fetch url : ", url);
|
|
269
|
+
}
|
|
270
|
+
const body = {
|
|
271
|
+
type,
|
|
272
|
+
values
|
|
273
|
+
};
|
|
274
|
+
try {
|
|
275
|
+
const response = await fetch(url, {
|
|
276
|
+
...fetchOptions,
|
|
277
|
+
method: "POST",
|
|
278
|
+
headers: {
|
|
279
|
+
"X-API-KEY": options.token
|
|
280
|
+
},
|
|
281
|
+
body: JSON.stringify(body)
|
|
282
|
+
});
|
|
283
|
+
if (options.debug) {
|
|
284
|
+
console.log(LOG_GROUP, "updateTranslations status : ", response.status);
|
|
285
|
+
}
|
|
286
|
+
} catch (error) {
|
|
287
|
+
console.error(LOG_GROUP, "updateTranslations error : ", error);
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
async getOpenApi() {
|
|
291
|
+
if (options.debug) {
|
|
292
|
+
console.log(LOG_GROUP, "getOpenApi()");
|
|
293
|
+
}
|
|
294
|
+
let url = `${options.origin}/api/v1/spaces/${options.spaceId}/open-api?token=${options.token}`;
|
|
295
|
+
if (options.debug) {
|
|
296
|
+
console.log(LOG_GROUP, "getOpenApi fetch url : ", url);
|
|
297
|
+
}
|
|
298
|
+
if (cache.has(url)) {
|
|
299
|
+
if (options.debug) {
|
|
300
|
+
console.log(LOG_GROUP, "getTranslations cache hit");
|
|
301
|
+
}
|
|
302
|
+
return cache.get(url);
|
|
303
|
+
}
|
|
304
|
+
try {
|
|
305
|
+
const response = await fetch(url, fetchOptions);
|
|
306
|
+
if (options.debug) {
|
|
307
|
+
console.log(LOG_GROUP, "getOpenApi status : ", response.status);
|
|
308
|
+
}
|
|
309
|
+
const data = await response.json();
|
|
310
|
+
cache.set(url, data);
|
|
311
|
+
return data;
|
|
312
|
+
} catch (error) {
|
|
313
|
+
console.error(LOG_GROUP, "getOpenApi error : ", error);
|
|
314
|
+
return {};
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
syncScriptUrl() {
|
|
318
|
+
return `${options.origin}/scripts/sync-v1.js`;
|
|
319
|
+
},
|
|
320
|
+
assetLink(asset) {
|
|
321
|
+
if (typeof asset === "string") {
|
|
322
|
+
return `${options.origin}/api/v1/spaces/${options.spaceId}/assets/${asset}`;
|
|
323
|
+
} else {
|
|
324
|
+
return `${options.origin}/api/v1/spaces/${options.spaceId}/assets/${asset.uri}`;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// src/session.ts
|
|
331
|
+
var import_promises2 = require("fs/promises");
|
|
332
|
+
var import_node_path2 = require("path");
|
|
333
|
+
var process2 = __toESM(require("process"));
|
|
334
|
+
|
|
335
|
+
// src/file.ts
|
|
336
|
+
var import_promises = require("fs/promises");
|
|
337
|
+
var import_node_path = require("path");
|
|
338
|
+
var DEFAULT_CONFIG_DIR = ".localess";
|
|
339
|
+
async function writeToFile(filePath, data, option) {
|
|
340
|
+
const resolvedPath = (0, import_node_path.parse)(filePath).dir;
|
|
341
|
+
try {
|
|
342
|
+
await (0, import_promises.mkdir)(resolvedPath, { recursive: true });
|
|
343
|
+
} catch (mkdirError) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
try {
|
|
347
|
+
await (0, import_promises.writeFile)(filePath, data, option);
|
|
348
|
+
} catch (writeError) {
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// src/session.ts
|
|
353
|
+
var CREDENTIALS_PATH = (0, import_node_path2.join)(process2.cwd(), DEFAULT_CONFIG_DIR, "credentials.json");
|
|
354
|
+
async function getSession() {
|
|
355
|
+
let session = {
|
|
356
|
+
isLoggedIn: false
|
|
357
|
+
};
|
|
358
|
+
const token = process2.env.LOCALESS_TOKEN;
|
|
359
|
+
const space = process2.env.LOCALESS_SPACE;
|
|
360
|
+
const origin = process2.env.LOCALESS_ORIGIN;
|
|
361
|
+
if (token && space && origin) {
|
|
362
|
+
console.debug(`Login in using environment variables.`);
|
|
363
|
+
return {
|
|
364
|
+
isLoggedIn: true,
|
|
365
|
+
space,
|
|
366
|
+
origin,
|
|
367
|
+
token,
|
|
368
|
+
method: "env"
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
try {
|
|
372
|
+
await (0, import_promises2.access)(CREDENTIALS_PATH);
|
|
373
|
+
const content = await (0, import_promises2.readFile)(CREDENTIALS_PATH, "utf8");
|
|
374
|
+
const parsedContent = JSON.parse(content);
|
|
375
|
+
if (Object.keys(parsedContent).length === 0) {
|
|
376
|
+
return session;
|
|
377
|
+
}
|
|
378
|
+
if (parsedContent.origin && parsedContent.token && parsedContent.space) {
|
|
379
|
+
console.debug(`Login in using credentials file.`);
|
|
380
|
+
return {
|
|
381
|
+
isLoggedIn: true,
|
|
382
|
+
space: parsedContent.space,
|
|
383
|
+
origin: parsedContent.origin,
|
|
384
|
+
token: parsedContent.token,
|
|
385
|
+
method: "file"
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
} catch (e) {
|
|
389
|
+
console.error('No credentials found. Please log in using the "localess login" command.');
|
|
390
|
+
}
|
|
391
|
+
console.debug("Not logged in.");
|
|
392
|
+
return session;
|
|
393
|
+
}
|
|
394
|
+
async function persistSession(data) {
|
|
395
|
+
if (data.origin && data.token && data.space) {
|
|
396
|
+
await writeToFile(CREDENTIALS_PATH, JSON.stringify(data, null, 2), { mode: 384 });
|
|
397
|
+
console.log("Add session credentials to file system.");
|
|
398
|
+
console.log("Add .localess to .gitignore to avoid committing them to your repository.");
|
|
399
|
+
} else {
|
|
400
|
+
throw new Error("Cannot persist session: missing required fields.");
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
async function clearSession() {
|
|
404
|
+
try {
|
|
405
|
+
await (0, import_promises2.access)(CREDENTIALS_PATH);
|
|
406
|
+
await writeToFile(CREDENTIALS_PATH, "{}", { mode: 384 });
|
|
407
|
+
} catch (error) {
|
|
408
|
+
throw new Error("Failed to clear session credentials.");
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// src/commands/login/index.ts
|
|
413
|
+
var loginCommand = new import_commander.Command("login").description("Login to Localess CLI").option("-t, --token <token>", "Token to login to Localess CLI").option("-s, --space <space>", "Space ID to login to").option("-o, --origin <origin>", "Origin of the Localess instance").action(async (options) => {
|
|
414
|
+
console.log("Logging in with options:", options);
|
|
415
|
+
const session = await getSession();
|
|
416
|
+
if (session.isLoggedIn && session.method === "file") {
|
|
417
|
+
console.log('Already logged in. If you want to log in with different credentials, please log out first using "localess logout" command.');
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
if (options.origin && options.space && options.token) {
|
|
421
|
+
const client = localessClient({
|
|
422
|
+
origin: options.origin,
|
|
423
|
+
spaceId: options.space,
|
|
424
|
+
token: options.token
|
|
425
|
+
});
|
|
426
|
+
try {
|
|
427
|
+
const space = await client.getSpace();
|
|
428
|
+
console.log(`Successfully logged in to space: ${space.name} (${space.id})`);
|
|
429
|
+
await persistSession({
|
|
430
|
+
origin: options.origin,
|
|
431
|
+
space: options.space,
|
|
432
|
+
token: options.token
|
|
433
|
+
});
|
|
434
|
+
} catch (e) {
|
|
435
|
+
console.error("Login failed");
|
|
436
|
+
}
|
|
437
|
+
} else if (session.isLoggedIn && session.method === "env") {
|
|
438
|
+
console.log("Already logged in with environment variables.");
|
|
439
|
+
console.log("If you want to log in with different credentials, Please provide all required options: --origin, --space, and --token");
|
|
440
|
+
} else {
|
|
441
|
+
console.log("Please provide all required options: --origin, --space, and --token");
|
|
442
|
+
console.log("Or set the following environment variables: LOCALESS_ORIGIN, LOCALESS_SPACE, and LOCALESS_TOKEN");
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
// src/commands/logout/index.ts
|
|
447
|
+
var import_commander2 = require("commander");
|
|
448
|
+
var logoutCommand = new import_commander2.Command("logout").description("Logout from Localess CLI").action(async () => {
|
|
449
|
+
console.log("Logging out...");
|
|
450
|
+
const session = await getSession();
|
|
451
|
+
if (!session.isLoggedIn) {
|
|
452
|
+
console.log("Not currently logged in.");
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
if (session.method === "env") {
|
|
456
|
+
console.log("You are logged in using environment variables. To log out, unset LOCALESS_TOKEN, LOCALESS_SPACE, and LOCALESS_ORIGIN.");
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
try {
|
|
460
|
+
await clearSession();
|
|
461
|
+
console.log("Successfully logged out.");
|
|
462
|
+
} catch (e) {
|
|
463
|
+
console.error("Failed to log out:", e);
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
// src/commands/types/index.ts
|
|
468
|
+
var import_commander3 = require("commander");
|
|
469
|
+
var import_openapi_typescript = __toESM(require("openapi-typescript"));
|
|
470
|
+
var import_node_path3 = require("path");
|
|
471
|
+
var import_node_process = __toESM(require("process"));
|
|
472
|
+
var TYPES_PATH = (0, import_node_path3.join)(import_node_process.default.cwd(), DEFAULT_CONFIG_DIR, "localess.d.ts");
|
|
473
|
+
var typesCommand = new import_commander3.Command("types").description("Generate types for your schemas").action(async (options) => {
|
|
474
|
+
console.log("Types in with options:", options);
|
|
475
|
+
const session = await getSession();
|
|
476
|
+
if (!session.isLoggedIn) {
|
|
477
|
+
console.error("Not logged in");
|
|
478
|
+
console.error('Please log in first using "localess login" command');
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
const client = localessClient({
|
|
482
|
+
origin: session.origin,
|
|
483
|
+
spaceId: session.space,
|
|
484
|
+
token: session.token
|
|
485
|
+
});
|
|
486
|
+
console.log("Fetching OpenAPI specification from Localess...");
|
|
487
|
+
const specification = await client.getOpenApi();
|
|
488
|
+
console.log("Generating types from OpenAPI specification...");
|
|
489
|
+
try {
|
|
490
|
+
const minimalSpec = {
|
|
491
|
+
openapi: "3.0.0",
|
|
492
|
+
info: { title: "Schemas Only", version: "1.0.0" },
|
|
493
|
+
components: { schemas: specification.components?.schemas || {} }
|
|
494
|
+
};
|
|
495
|
+
const ast = await (0, import_openapi_typescript.default)(minimalSpec, { exportType: true, rootTypes: true, rootTypesNoSchemaPrefix: true });
|
|
496
|
+
const contents = (0, import_openapi_typescript.astToString)(ast);
|
|
497
|
+
await writeToFile(TYPES_PATH, contents);
|
|
498
|
+
console.log(`Types generated successfully at ${TYPES_PATH}`);
|
|
499
|
+
} catch (e) {
|
|
500
|
+
console.error(e);
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
// src/program.ts
|
|
505
|
+
var program = new import_commander4.Command();
|
|
506
|
+
program.name("Localess CLI").description("CLI tool for Localess platform management").version("0.0.1");
|
|
507
|
+
program.addCommand(loginCommand);
|
|
508
|
+
program.addCommand(logoutCommand);
|
|
509
|
+
program.addCommand(typesCommand);
|
|
510
|
+
|
|
511
|
+
// src/index.ts
|
|
512
|
+
try {
|
|
513
|
+
program.parse(process.argv);
|
|
514
|
+
} catch (e) {
|
|
515
|
+
console.error("Error executing command:", e instanceof Error ? e.message : e);
|
|
516
|
+
process.exit(1);
|
|
517
|
+
}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/program.ts
|
|
4
|
+
import { Command as Command4 } from "commander";
|
|
5
|
+
|
|
6
|
+
// src/commands/login/index.ts
|
|
7
|
+
import { Command } from "commander";
|
|
8
|
+
|
|
9
|
+
// src/utils.ts
|
|
10
|
+
var RESET = "\x1B[0m";
|
|
11
|
+
var FG_BLUE = "\x1B[34m";
|
|
12
|
+
|
|
13
|
+
// src/cache.ts
|
|
14
|
+
var NoCache = class {
|
|
15
|
+
set(key, value) {
|
|
16
|
+
}
|
|
17
|
+
get(key) {
|
|
18
|
+
return void 0;
|
|
19
|
+
}
|
|
20
|
+
has(key) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
var TTLCache = class {
|
|
25
|
+
/**
|
|
26
|
+
* Creates a TTLCache with a specified time-to-live (TTL) for each entry.
|
|
27
|
+
* default is 5 minutes (300000 ms).
|
|
28
|
+
* @param ttlMs
|
|
29
|
+
*/
|
|
30
|
+
constructor(ttlMs = 3e5) {
|
|
31
|
+
this.ttlMs = ttlMs;
|
|
32
|
+
}
|
|
33
|
+
cache = /* @__PURE__ */ new Map();
|
|
34
|
+
set(key, value) {
|
|
35
|
+
this.cache.set(key, { value, expiresAt: Date.now() + this.ttlMs });
|
|
36
|
+
}
|
|
37
|
+
get(key) {
|
|
38
|
+
const entry = this.cache.get(key);
|
|
39
|
+
if (!entry) return void 0;
|
|
40
|
+
if (Date.now() > entry.expiresAt) {
|
|
41
|
+
this.cache.delete(key);
|
|
42
|
+
return void 0;
|
|
43
|
+
}
|
|
44
|
+
return entry.value;
|
|
45
|
+
}
|
|
46
|
+
has(key) {
|
|
47
|
+
return this.get(key) !== void 0;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// src/client.ts
|
|
52
|
+
var LOG_GROUP = `${FG_BLUE}[Localess:Client]${RESET}`;
|
|
53
|
+
function localessClient(options) {
|
|
54
|
+
if (options.debug) {
|
|
55
|
+
console.log(LOG_GROUP, "Client Options : ", options);
|
|
56
|
+
}
|
|
57
|
+
const fetchOptions = {
|
|
58
|
+
redirect: "follow",
|
|
59
|
+
headers: {
|
|
60
|
+
"Content-Type": "application/json",
|
|
61
|
+
"Accept": "application/json",
|
|
62
|
+
"X-Localess-Agent": "Localess-CLI-Client",
|
|
63
|
+
"X-Localess-Agent-Version": "0.9.0"
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
const cache = options.cacheTTL === false ? new NoCache() : new TTLCache(options.cacheTTL);
|
|
67
|
+
return {
|
|
68
|
+
async getSpace() {
|
|
69
|
+
if (options.debug) {
|
|
70
|
+
console.log(LOG_GROUP, "getSpace()");
|
|
71
|
+
}
|
|
72
|
+
let url = `${options.origin}/api/v1/spaces/${options.spaceId}?token=${options.token}`;
|
|
73
|
+
if (options.debug) {
|
|
74
|
+
console.log(LOG_GROUP, "getSpace fetch url : ", url);
|
|
75
|
+
}
|
|
76
|
+
if (cache.has(url)) {
|
|
77
|
+
if (options.debug) {
|
|
78
|
+
console.log(LOG_GROUP, "getSpace cache hit");
|
|
79
|
+
}
|
|
80
|
+
return cache.get(url);
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const response = await fetch(url, fetchOptions);
|
|
84
|
+
if (options.debug) {
|
|
85
|
+
console.log(LOG_GROUP, "getSpace status : ", response.status);
|
|
86
|
+
}
|
|
87
|
+
const data = await response.json();
|
|
88
|
+
cache.set(url, data);
|
|
89
|
+
return data;
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error(LOG_GROUP, "getSpace error : ", error);
|
|
92
|
+
return {};
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
async getLinks(params) {
|
|
96
|
+
if (options.debug) {
|
|
97
|
+
console.log(LOG_GROUP, "getLinks() params : ", JSON.stringify(params));
|
|
98
|
+
}
|
|
99
|
+
let kind = "";
|
|
100
|
+
if (params?.kind) {
|
|
101
|
+
kind = `&kind=${params.kind}`;
|
|
102
|
+
}
|
|
103
|
+
let parentSlug = "";
|
|
104
|
+
if (params?.parentSlug) {
|
|
105
|
+
parentSlug = `&parentSlug=${params.parentSlug}`;
|
|
106
|
+
}
|
|
107
|
+
let excludeChildren = "";
|
|
108
|
+
if (params?.excludeChildren) {
|
|
109
|
+
excludeChildren = `&excludeChildren=${params.excludeChildren}`;
|
|
110
|
+
}
|
|
111
|
+
let url = `${options.origin}/api/v1/spaces/${options.spaceId}/links?token=${options.token}${kind}${parentSlug}${excludeChildren}`;
|
|
112
|
+
if (options.debug) {
|
|
113
|
+
console.log(LOG_GROUP, "getLinks fetch url : ", url);
|
|
114
|
+
}
|
|
115
|
+
if (cache.has(url)) {
|
|
116
|
+
if (options.debug) {
|
|
117
|
+
console.log(LOG_GROUP, "getLinks cache hit");
|
|
118
|
+
}
|
|
119
|
+
return cache.get(url);
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
const response = await fetch(url, fetchOptions);
|
|
123
|
+
if (options.debug) {
|
|
124
|
+
console.log(LOG_GROUP, "getLinks status : ", response.status);
|
|
125
|
+
}
|
|
126
|
+
const data = await response.json();
|
|
127
|
+
cache.set(url, data);
|
|
128
|
+
return data;
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.error(LOG_GROUP, "getLinks error : ", error);
|
|
131
|
+
return {};
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
async getContentBySlug(slug, params) {
|
|
135
|
+
if (options.debug) {
|
|
136
|
+
console.log(LOG_GROUP, "getContentBySlug() slug : ", slug);
|
|
137
|
+
console.log(LOG_GROUP, "getContentBySlug() params : ", JSON.stringify(params));
|
|
138
|
+
}
|
|
139
|
+
let version = "";
|
|
140
|
+
if (options?.version && options.version == "draft") {
|
|
141
|
+
version = `&version=${options.version}`;
|
|
142
|
+
}
|
|
143
|
+
if (params?.version && params.version == "draft") {
|
|
144
|
+
version = `&version=${params.version}`;
|
|
145
|
+
}
|
|
146
|
+
const locale = params?.locale ? `&locale=${params.locale}` : "";
|
|
147
|
+
const resolveReference = params?.resolveReference ? `&resolveReference=${params.resolveReference}` : "";
|
|
148
|
+
const resolveLink = params?.resolveLink ? `&resolveLink=${params.resolveLink}` : "";
|
|
149
|
+
let url = `${options.origin}/api/v1/spaces/${options.spaceId}/contents/slugs/${slug}?token=${options.token}${version}${locale}${resolveReference}${resolveLink}`;
|
|
150
|
+
if (options.debug) {
|
|
151
|
+
console.log(LOG_GROUP, "getContentBySlug fetch url : ", url);
|
|
152
|
+
}
|
|
153
|
+
if (cache.has(url)) {
|
|
154
|
+
if (options.debug) {
|
|
155
|
+
console.log(LOG_GROUP, "getContentBySlug cache hit");
|
|
156
|
+
}
|
|
157
|
+
return cache.get(url);
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const response = await fetch(url, fetchOptions);
|
|
161
|
+
if (options.debug) {
|
|
162
|
+
console.log(LOG_GROUP, "getContentBySlug status : ", response.status);
|
|
163
|
+
}
|
|
164
|
+
const data = await response.json();
|
|
165
|
+
cache.set(url, data);
|
|
166
|
+
return data;
|
|
167
|
+
} catch (error) {
|
|
168
|
+
console.error(LOG_GROUP, "getContentBySlug error : ", error);
|
|
169
|
+
return {};
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
async getContentById(id, params) {
|
|
173
|
+
if (options.debug) {
|
|
174
|
+
console.log(LOG_GROUP, "getContentById() id : ", id);
|
|
175
|
+
console.log(LOG_GROUP, "getContentById() params : ", JSON.stringify(params));
|
|
176
|
+
}
|
|
177
|
+
let version = "";
|
|
178
|
+
if (options?.version && options.version == "draft") {
|
|
179
|
+
version = `&version=${options.version}`;
|
|
180
|
+
}
|
|
181
|
+
if (params?.version && params.version == "draft") {
|
|
182
|
+
version = `&version=${params.version}`;
|
|
183
|
+
}
|
|
184
|
+
const locale = params?.locale ? `&locale=${params.locale}` : "";
|
|
185
|
+
const resolveReference = params?.resolveReference ? `&resolveReference=${params.resolveReference}` : "";
|
|
186
|
+
const resolveLink = params?.resolveLink ? `&resolveLink=${params.resolveLink}` : "";
|
|
187
|
+
let url = `${options.origin}/api/v1/spaces/${options.spaceId}/contents/${id}?token=${options.token}${version}${locale}${resolveReference}${resolveLink}`;
|
|
188
|
+
if (options.debug) {
|
|
189
|
+
console.log(LOG_GROUP, "getContentById fetch url : ", url);
|
|
190
|
+
}
|
|
191
|
+
if (cache.has(url)) {
|
|
192
|
+
if (options.debug) {
|
|
193
|
+
console.log(LOG_GROUP, "getContentById cache hit");
|
|
194
|
+
}
|
|
195
|
+
return cache.get(url);
|
|
196
|
+
}
|
|
197
|
+
try {
|
|
198
|
+
const response = await fetch(url, fetchOptions);
|
|
199
|
+
if (options.debug) {
|
|
200
|
+
console.log(LOG_GROUP, "getContentById status : ", response.status);
|
|
201
|
+
}
|
|
202
|
+
const data = await response.json();
|
|
203
|
+
cache.set(url, data);
|
|
204
|
+
return data;
|
|
205
|
+
} catch (error) {
|
|
206
|
+
console.error(LOG_GROUP, "getContentById error : ", error);
|
|
207
|
+
return {};
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
async getTranslations(locale) {
|
|
211
|
+
if (options.debug) {
|
|
212
|
+
console.log(LOG_GROUP, "getTranslations() locale : ", locale);
|
|
213
|
+
}
|
|
214
|
+
let url = `${options.origin}/api/v1/spaces/${options.spaceId}/translations/${locale}?token=${options.token}`;
|
|
215
|
+
if (options.debug) {
|
|
216
|
+
console.log(LOG_GROUP, "getTranslations fetch url : ", url);
|
|
217
|
+
}
|
|
218
|
+
if (cache.has(url)) {
|
|
219
|
+
if (options.debug) {
|
|
220
|
+
console.log(LOG_GROUP, "getTranslations cache hit");
|
|
221
|
+
}
|
|
222
|
+
return cache.get(url);
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
const response = await fetch(url, fetchOptions);
|
|
226
|
+
if (options.debug) {
|
|
227
|
+
console.log(LOG_GROUP, "getTranslations status : ", response.status);
|
|
228
|
+
}
|
|
229
|
+
const data = await response.json();
|
|
230
|
+
cache.set(url, data);
|
|
231
|
+
return data;
|
|
232
|
+
} catch (error) {
|
|
233
|
+
console.error(LOG_GROUP, "getTranslations error : ", error);
|
|
234
|
+
return {};
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
async updateTranslations(locale, type, values) {
|
|
238
|
+
if (options.debug) {
|
|
239
|
+
console.log(LOG_GROUP, "updateTranslations() locale : ", locale);
|
|
240
|
+
console.log(LOG_GROUP, "updateTranslations() type : ", type);
|
|
241
|
+
console.log(LOG_GROUP, "updateTranslations() values : ", JSON.stringify(values));
|
|
242
|
+
}
|
|
243
|
+
let url = `${options.origin}/api/v1/spaces/${options.spaceId}/translations/${locale}`;
|
|
244
|
+
if (options.debug) {
|
|
245
|
+
console.log(LOG_GROUP, "updateTranslations fetch url : ", url);
|
|
246
|
+
}
|
|
247
|
+
const body = {
|
|
248
|
+
type,
|
|
249
|
+
values
|
|
250
|
+
};
|
|
251
|
+
try {
|
|
252
|
+
const response = await fetch(url, {
|
|
253
|
+
...fetchOptions,
|
|
254
|
+
method: "POST",
|
|
255
|
+
headers: {
|
|
256
|
+
"X-API-KEY": options.token
|
|
257
|
+
},
|
|
258
|
+
body: JSON.stringify(body)
|
|
259
|
+
});
|
|
260
|
+
if (options.debug) {
|
|
261
|
+
console.log(LOG_GROUP, "updateTranslations status : ", response.status);
|
|
262
|
+
}
|
|
263
|
+
} catch (error) {
|
|
264
|
+
console.error(LOG_GROUP, "updateTranslations error : ", error);
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
async getOpenApi() {
|
|
268
|
+
if (options.debug) {
|
|
269
|
+
console.log(LOG_GROUP, "getOpenApi()");
|
|
270
|
+
}
|
|
271
|
+
let url = `${options.origin}/api/v1/spaces/${options.spaceId}/open-api?token=${options.token}`;
|
|
272
|
+
if (options.debug) {
|
|
273
|
+
console.log(LOG_GROUP, "getOpenApi fetch url : ", url);
|
|
274
|
+
}
|
|
275
|
+
if (cache.has(url)) {
|
|
276
|
+
if (options.debug) {
|
|
277
|
+
console.log(LOG_GROUP, "getTranslations cache hit");
|
|
278
|
+
}
|
|
279
|
+
return cache.get(url);
|
|
280
|
+
}
|
|
281
|
+
try {
|
|
282
|
+
const response = await fetch(url, fetchOptions);
|
|
283
|
+
if (options.debug) {
|
|
284
|
+
console.log(LOG_GROUP, "getOpenApi status : ", response.status);
|
|
285
|
+
}
|
|
286
|
+
const data = await response.json();
|
|
287
|
+
cache.set(url, data);
|
|
288
|
+
return data;
|
|
289
|
+
} catch (error) {
|
|
290
|
+
console.error(LOG_GROUP, "getOpenApi error : ", error);
|
|
291
|
+
return {};
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
syncScriptUrl() {
|
|
295
|
+
return `${options.origin}/scripts/sync-v1.js`;
|
|
296
|
+
},
|
|
297
|
+
assetLink(asset) {
|
|
298
|
+
if (typeof asset === "string") {
|
|
299
|
+
return `${options.origin}/api/v1/spaces/${options.spaceId}/assets/${asset}`;
|
|
300
|
+
} else {
|
|
301
|
+
return `${options.origin}/api/v1/spaces/${options.spaceId}/assets/${asset.uri}`;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// src/session.ts
|
|
308
|
+
import { access as access2, readFile } from "fs/promises";
|
|
309
|
+
import { join } from "path";
|
|
310
|
+
import * as process2 from "process";
|
|
311
|
+
|
|
312
|
+
// src/file.ts
|
|
313
|
+
import { access, constants, mkdir, writeFile } from "fs/promises";
|
|
314
|
+
import { parse } from "path";
|
|
315
|
+
var DEFAULT_CONFIG_DIR = ".localess";
|
|
316
|
+
async function writeToFile(filePath, data, option) {
|
|
317
|
+
const resolvedPath = parse(filePath).dir;
|
|
318
|
+
try {
|
|
319
|
+
await mkdir(resolvedPath, { recursive: true });
|
|
320
|
+
} catch (mkdirError) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
try {
|
|
324
|
+
await writeFile(filePath, data, option);
|
|
325
|
+
} catch (writeError) {
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// src/session.ts
|
|
330
|
+
var CREDENTIALS_PATH = join(process2.cwd(), DEFAULT_CONFIG_DIR, "credentials.json");
|
|
331
|
+
async function getSession() {
|
|
332
|
+
let session = {
|
|
333
|
+
isLoggedIn: false
|
|
334
|
+
};
|
|
335
|
+
const token = process2.env.LOCALESS_TOKEN;
|
|
336
|
+
const space = process2.env.LOCALESS_SPACE;
|
|
337
|
+
const origin = process2.env.LOCALESS_ORIGIN;
|
|
338
|
+
if (token && space && origin) {
|
|
339
|
+
console.debug(`Login in using environment variables.`);
|
|
340
|
+
return {
|
|
341
|
+
isLoggedIn: true,
|
|
342
|
+
space,
|
|
343
|
+
origin,
|
|
344
|
+
token,
|
|
345
|
+
method: "env"
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
try {
|
|
349
|
+
await access2(CREDENTIALS_PATH);
|
|
350
|
+
const content = await readFile(CREDENTIALS_PATH, "utf8");
|
|
351
|
+
const parsedContent = JSON.parse(content);
|
|
352
|
+
if (Object.keys(parsedContent).length === 0) {
|
|
353
|
+
return session;
|
|
354
|
+
}
|
|
355
|
+
if (parsedContent.origin && parsedContent.token && parsedContent.space) {
|
|
356
|
+
console.debug(`Login in using credentials file.`);
|
|
357
|
+
return {
|
|
358
|
+
isLoggedIn: true,
|
|
359
|
+
space: parsedContent.space,
|
|
360
|
+
origin: parsedContent.origin,
|
|
361
|
+
token: parsedContent.token,
|
|
362
|
+
method: "file"
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
} catch (e) {
|
|
366
|
+
console.error('No credentials found. Please log in using the "localess login" command.');
|
|
367
|
+
}
|
|
368
|
+
console.debug("Not logged in.");
|
|
369
|
+
return session;
|
|
370
|
+
}
|
|
371
|
+
async function persistSession(data) {
|
|
372
|
+
if (data.origin && data.token && data.space) {
|
|
373
|
+
await writeToFile(CREDENTIALS_PATH, JSON.stringify(data, null, 2), { mode: 384 });
|
|
374
|
+
console.log("Add session credentials to file system.");
|
|
375
|
+
console.log("Add .localess to .gitignore to avoid committing them to your repository.");
|
|
376
|
+
} else {
|
|
377
|
+
throw new Error("Cannot persist session: missing required fields.");
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
async function clearSession() {
|
|
381
|
+
try {
|
|
382
|
+
await access2(CREDENTIALS_PATH);
|
|
383
|
+
await writeToFile(CREDENTIALS_PATH, "{}", { mode: 384 });
|
|
384
|
+
} catch (error) {
|
|
385
|
+
throw new Error("Failed to clear session credentials.");
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// src/commands/login/index.ts
|
|
390
|
+
var loginCommand = new Command("login").description("Login to Localess CLI").option("-t, --token <token>", "Token to login to Localess CLI").option("-s, --space <space>", "Space ID to login to").option("-o, --origin <origin>", "Origin of the Localess instance").action(async (options) => {
|
|
391
|
+
console.log("Logging in with options:", options);
|
|
392
|
+
const session = await getSession();
|
|
393
|
+
if (session.isLoggedIn && session.method === "file") {
|
|
394
|
+
console.log('Already logged in. If you want to log in with different credentials, please log out first using "localess logout" command.');
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
if (options.origin && options.space && options.token) {
|
|
398
|
+
const client = localessClient({
|
|
399
|
+
origin: options.origin,
|
|
400
|
+
spaceId: options.space,
|
|
401
|
+
token: options.token
|
|
402
|
+
});
|
|
403
|
+
try {
|
|
404
|
+
const space = await client.getSpace();
|
|
405
|
+
console.log(`Successfully logged in to space: ${space.name} (${space.id})`);
|
|
406
|
+
await persistSession({
|
|
407
|
+
origin: options.origin,
|
|
408
|
+
space: options.space,
|
|
409
|
+
token: options.token
|
|
410
|
+
});
|
|
411
|
+
} catch (e) {
|
|
412
|
+
console.error("Login failed");
|
|
413
|
+
}
|
|
414
|
+
} else if (session.isLoggedIn && session.method === "env") {
|
|
415
|
+
console.log("Already logged in with environment variables.");
|
|
416
|
+
console.log("If you want to log in with different credentials, Please provide all required options: --origin, --space, and --token");
|
|
417
|
+
} else {
|
|
418
|
+
console.log("Please provide all required options: --origin, --space, and --token");
|
|
419
|
+
console.log("Or set the following environment variables: LOCALESS_ORIGIN, LOCALESS_SPACE, and LOCALESS_TOKEN");
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
// src/commands/logout/index.ts
|
|
424
|
+
import { Command as Command2 } from "commander";
|
|
425
|
+
var logoutCommand = new Command2("logout").description("Logout from Localess CLI").action(async () => {
|
|
426
|
+
console.log("Logging out...");
|
|
427
|
+
const session = await getSession();
|
|
428
|
+
if (!session.isLoggedIn) {
|
|
429
|
+
console.log("Not currently logged in.");
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
if (session.method === "env") {
|
|
433
|
+
console.log("You are logged in using environment variables. To log out, unset LOCALESS_TOKEN, LOCALESS_SPACE, and LOCALESS_ORIGIN.");
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
try {
|
|
437
|
+
await clearSession();
|
|
438
|
+
console.log("Successfully logged out.");
|
|
439
|
+
} catch (e) {
|
|
440
|
+
console.error("Failed to log out:", e);
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
// src/commands/types/index.ts
|
|
445
|
+
import { Command as Command3 } from "commander";
|
|
446
|
+
import openapiTS, { astToString } from "openapi-typescript";
|
|
447
|
+
import { join as join2 } from "path";
|
|
448
|
+
import process3 from "process";
|
|
449
|
+
var TYPES_PATH = join2(process3.cwd(), DEFAULT_CONFIG_DIR, "localess.d.ts");
|
|
450
|
+
var typesCommand = new Command3("types").description("Generate types for your schemas").action(async (options) => {
|
|
451
|
+
console.log("Types in with options:", options);
|
|
452
|
+
const session = await getSession();
|
|
453
|
+
if (!session.isLoggedIn) {
|
|
454
|
+
console.error("Not logged in");
|
|
455
|
+
console.error('Please log in first using "localess login" command');
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
const client = localessClient({
|
|
459
|
+
origin: session.origin,
|
|
460
|
+
spaceId: session.space,
|
|
461
|
+
token: session.token
|
|
462
|
+
});
|
|
463
|
+
console.log("Fetching OpenAPI specification from Localess...");
|
|
464
|
+
const specification = await client.getOpenApi();
|
|
465
|
+
console.log("Generating types from OpenAPI specification...");
|
|
466
|
+
try {
|
|
467
|
+
const minimalSpec = {
|
|
468
|
+
openapi: "3.0.0",
|
|
469
|
+
info: { title: "Schemas Only", version: "1.0.0" },
|
|
470
|
+
components: { schemas: specification.components?.schemas || {} }
|
|
471
|
+
};
|
|
472
|
+
const ast = await openapiTS(minimalSpec, { exportType: true, rootTypes: true, rootTypesNoSchemaPrefix: true });
|
|
473
|
+
const contents = astToString(ast);
|
|
474
|
+
await writeToFile(TYPES_PATH, contents);
|
|
475
|
+
console.log(`Types generated successfully at ${TYPES_PATH}`);
|
|
476
|
+
} catch (e) {
|
|
477
|
+
console.error(e);
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
// src/program.ts
|
|
482
|
+
var program = new Command4();
|
|
483
|
+
program.name("Localess CLI").description("CLI tool for Localess platform management").version("0.0.1");
|
|
484
|
+
program.addCommand(loginCommand);
|
|
485
|
+
program.addCommand(logoutCommand);
|
|
486
|
+
program.addCommand(typesCommand);
|
|
487
|
+
|
|
488
|
+
// src/index.ts
|
|
489
|
+
try {
|
|
490
|
+
program.parse(process.argv);
|
|
491
|
+
} catch (e) {
|
|
492
|
+
console.error("Error executing command:", e instanceof Error ? e.message : e);
|
|
493
|
+
process.exit(1);
|
|
494
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@localess/cli",
|
|
3
|
+
"version": "0.0.1-dev.20260216094809",
|
|
4
|
+
"description": "Localess Command Line.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"localess",
|
|
7
|
+
"cli",
|
|
8
|
+
"node",
|
|
9
|
+
"javascript",
|
|
10
|
+
"typescript"
|
|
11
|
+
],
|
|
12
|
+
"author": "Lessify",
|
|
13
|
+
"homepage": "https://github.com/Lessify/localess-js",
|
|
14
|
+
"sideEffects": false,
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.mjs"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"main": "./dist/index.mjs",
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"bin": {
|
|
27
|
+
"localess": "./dist/index.mjs"
|
|
28
|
+
},
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/Lessify/localess-js.git",
|
|
32
|
+
"directory": "packages/cli"
|
|
33
|
+
},
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/Lessify/localess-js/issues"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --shims",
|
|
39
|
+
"test": "vitest"
|
|
40
|
+
},
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"commander": "^14.0.3",
|
|
44
|
+
"chalk": "^5.6.2",
|
|
45
|
+
"openapi-typescript": "^7.12.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "^20",
|
|
49
|
+
"tsup": "^8.5.1",
|
|
50
|
+
"typescript": "^5.0.0"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">= 20.0.0"
|
|
54
|
+
}
|
|
55
|
+
}
|