sitevision-cli 1.0.0-beta.2 → 1.0.0-beta.21
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/dist/app.d.ts +1 -1
- package/dist/app.js +59 -8
- package/dist/cli.js +96 -39
- package/dist/commands/build.js +1 -1
- package/dist/commands/deploy.d.ts +2 -2
- package/dist/commands/deploy.js +135 -25
- package/dist/commands/dev.d.ts +8 -10
- package/dist/commands/dev.js +77 -366
- package/dist/commands/info.js +2 -2
- package/dist/commands/watch.js +5 -23
- package/dist/components/AnimatedLogo.js +8 -2
- package/dist/components/AuthLoginScreen.d.ts +21 -0
- package/dist/components/AuthLoginScreen.js +90 -0
- package/dist/components/DevPropertiesForm.d.ts +2 -1
- package/dist/components/DevPropertiesForm.js +198 -33
- package/dist/components/InfoScreen.js +2 -2
- package/dist/components/MainMenu.js +7 -2
- package/dist/components/PasswordInput.js +2 -1
- package/dist/components/SetupFlow.d.ts +2 -1
- package/dist/components/SetupFlow.js +100 -11
- package/dist/shell/AddonPicker.d.ts +14 -0
- package/dist/shell/AddonPicker.js +54 -0
- package/dist/shell/CommandPalette.d.ts +8 -0
- package/dist/shell/CommandPalette.js +63 -0
- package/dist/shell/ConfigForm.d.ts +36 -0
- package/dist/shell/ConfigForm.js +558 -0
- package/dist/shell/Frame.d.ts +59 -0
- package/dist/shell/Frame.js +134 -0
- package/dist/shell/Settings.d.ts +6 -0
- package/dist/shell/Settings.js +96 -0
- package/dist/shell/Shell.d.ts +9 -0
- package/dist/shell/Shell.js +586 -0
- package/dist/shell/Tabs.d.ts +36 -0
- package/dist/shell/Tabs.js +90 -0
- package/dist/shell/actions.d.ts +45 -0
- package/dist/shell/actions.js +0 -0
- package/dist/types/index.d.ts +44 -5
- package/dist/utils/config.d.ts +10 -0
- package/dist/utils/config.js +14 -0
- package/dist/utils/environments.d.ts +20 -0
- package/dist/utils/environments.js +74 -0
- package/dist/utils/i18n.d.ts +12 -0
- package/dist/utils/i18n.js +279 -0
- package/dist/utils/jsonc.d.ts +19 -0
- package/dist/utils/jsonc.js +74 -0
- package/dist/utils/keychain.d.ts +9 -0
- package/dist/utils/keychain.js +54 -0
- package/dist/utils/oauth2-auth.d.ts +64 -0
- package/dist/utils/oauth2-auth.js +242 -0
- package/dist/utils/password-prompt.d.ts +5 -0
- package/dist/utils/password-prompt.js +28 -0
- package/dist/utils/project-detection.d.ts +105 -6
- package/dist/utils/project-detection.js +411 -54
- package/dist/utils/session-cookie-auth.d.ts +35 -0
- package/dist/utils/session-cookie-auth.js +99 -0
- package/dist/utils/sitevision-api.d.ts +64 -5
- package/dist/utils/sitevision-api.js +195 -33
- package/dist/utils/tasks.d.ts +48 -0
- package/dist/utils/tasks.js +371 -0
- package/dist/utils/workspace.d.ts +17 -0
- package/dist/utils/workspace.js +67 -0
- package/package.json +3 -1
- package/readme.md +102 -121
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
export const LANGUAGES = ['en', 'sv'];
|
|
2
|
+
export const LANGUAGE_NAMES = {
|
|
3
|
+
en: 'English',
|
|
4
|
+
sv: 'Svenska',
|
|
5
|
+
};
|
|
6
|
+
let current = 'en';
|
|
7
|
+
export function getLanguage() {
|
|
8
|
+
return current;
|
|
9
|
+
}
|
|
10
|
+
export function setLanguage(language) {
|
|
11
|
+
current = language;
|
|
12
|
+
}
|
|
13
|
+
export function t(text, vars) {
|
|
14
|
+
let out = current === 'sv' ? (sv[text] ?? text) : text;
|
|
15
|
+
if (vars) {
|
|
16
|
+
for (const [name, value] of Object.entries(vars)) {
|
|
17
|
+
out = out.split(`{${name}}`).join(String(value));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
22
|
+
const sv = {
|
|
23
|
+
// Frame
|
|
24
|
+
APP: 'APP',
|
|
25
|
+
'WORKSPACE {n} apps': 'ARBETSYTA {n} appar',
|
|
26
|
+
'WORKSPACE 1 app': 'ARBETSYTA 1 app',
|
|
27
|
+
'{arrow} {n} more': '{arrow} {n} till',
|
|
28
|
+
'deps·config·sync·signing': 'beroenden·konfig·synk·sign',
|
|
29
|
+
'Workspace settings': 'Arbetsyteinställningar',
|
|
30
|
+
TASKS: 'UPPGIFTER',
|
|
31
|
+
// Tabs
|
|
32
|
+
Overview: 'Översikt',
|
|
33
|
+
Config: 'Konfig',
|
|
34
|
+
Versions: 'Versioner',
|
|
35
|
+
Log: 'Logg',
|
|
36
|
+
Ovw: 'Övs',
|
|
37
|
+
Cfg: 'Kfg',
|
|
38
|
+
Ver: 'Ver',
|
|
39
|
+
id: 'id',
|
|
40
|
+
version: 'version',
|
|
41
|
+
type: 'typ',
|
|
42
|
+
addon: 'tillägg',
|
|
43
|
+
site: 'webbplats',
|
|
44
|
+
domain: 'domän',
|
|
45
|
+
auth: 'auth',
|
|
46
|
+
'signing user': 'signeringsanv.',
|
|
47
|
+
'not set': 'ej satt',
|
|
48
|
+
'↑ root': '↑ rot',
|
|
49
|
+
' · bundled': ' · paketerad',
|
|
50
|
+
deps: 'beroenden',
|
|
51
|
+
config: 'konfig',
|
|
52
|
+
sync: 'synk',
|
|
53
|
+
signing: 'signering',
|
|
54
|
+
scripts: 'scripts',
|
|
55
|
+
'missing · i to install': 'saknas · i för att installera',
|
|
56
|
+
'not installed · i to install': 'ej installerat · i för att installera',
|
|
57
|
+
'dev properties': 'dev-egenskaper',
|
|
58
|
+
'missing · e to edit': 'saknas · e för att redigera',
|
|
59
|
+
'{n} diffs · y to apply': '{n} skillnader · y för att tillämpa',
|
|
60
|
+
'1 diff · y to apply': '1 skillnad · y för att tillämpa',
|
|
61
|
+
'missing · / set up signing': 'saknas · / konfigurera signering',
|
|
62
|
+
'not installed': 'ej installerat',
|
|
63
|
+
'⚠ plaintext password in .dev_properties.json · / migrate': '⚠ lösenord i klartext i .dev_properties.json · / migrera',
|
|
64
|
+
RECENT: 'SENASTE',
|
|
65
|
+
'⚠ Configure dev properties first (e).': '⚠ Konfigurera dev-egenskaper först (e).',
|
|
66
|
+
'Press R to fetch versions from {domain}.': 'Tryck R för att hämta versioner från {domain}.',
|
|
67
|
+
'APP IDENTIFIER': 'APP-ID',
|
|
68
|
+
VERSION: 'VERSION',
|
|
69
|
+
ACTIVE: 'AKTIV',
|
|
70
|
+
'No versions uploaded to {addon}.': 'Inga versioner uppladdade till {addon}.',
|
|
71
|
+
'{n} versions · a activate selected · R refresh': '{n} versioner · a aktivera vald · R uppdatera',
|
|
72
|
+
'1 version · a activate selected · R refresh': '1 version · a aktivera vald · R uppdatera',
|
|
73
|
+
' · fetched {time}': ' · hämtad {time}',
|
|
74
|
+
'No task yet. d dev · w watch · b build · s sign · p deploy': 'Ingen uppgift ännu. d dev · w watch · b build · s sign · p deploy',
|
|
75
|
+
' · following': ' · följer',
|
|
76
|
+
// Palette
|
|
77
|
+
SETUP: 'INSTÄLLNINGAR',
|
|
78
|
+
AUTH: 'AUTH',
|
|
79
|
+
Commands: 'Kommandon',
|
|
80
|
+
'{n} actions': '{n} åtgärder',
|
|
81
|
+
'type to filter · ↑↓ move · Enter run · Esc close': 'skriv för att filtrera · ↑↓ flytta · Enter kör · Esc stäng',
|
|
82
|
+
// Addon picker
|
|
83
|
+
'Addon Repository': 'Tilläggsförråd',
|
|
84
|
+
'{n} of {m}': '{n} av {m}',
|
|
85
|
+
'fetching addons': 'hämtar tillägg',
|
|
86
|
+
'↑↓ move · Enter select · Esc cancel': '↑↓ flytta · Enter välj · Esc avbryt',
|
|
87
|
+
// Actions
|
|
88
|
+
Dev: 'Dev',
|
|
89
|
+
Watch: 'Watch',
|
|
90
|
+
Build: 'Build',
|
|
91
|
+
Sign: 'Sign',
|
|
92
|
+
Deploy: 'Driftsätt',
|
|
93
|
+
'Deploy (force)': 'Driftsätt (tvinga)',
|
|
94
|
+
'to {env}': 'till {env}',
|
|
95
|
+
'Switch environment': 'Byt miljö',
|
|
96
|
+
'Add environment': 'Lägg till miljö',
|
|
97
|
+
'e.g. test or prod, overriding domain and auth': 't.ex. test eller prod, med egen domän och auth',
|
|
98
|
+
'Environment name (e.g. test, prod)': 'Miljönamn (t.ex. test, prod)',
|
|
99
|
+
'Deploy the signed {id} to {env} and activate it?': 'Driftsätt signerade {id} till {env} och aktivera?',
|
|
100
|
+
'Dev never deploys to a production environment ({env}). Switch with E.': 'Dev driftsätter aldrig till en produktionsmiljö ({env}). Byt med E.',
|
|
101
|
+
'switched to {env}': 'bytte till {env}',
|
|
102
|
+
'environment {env} added': 'miljön {env} tillagd',
|
|
103
|
+
environment: 'miljö',
|
|
104
|
+
production: 'produktion',
|
|
105
|
+
env: 'miljö',
|
|
106
|
+
'↑ dev': '↑ dev',
|
|
107
|
+
'Activate a remote version': 'Aktivera en fjärrversion',
|
|
108
|
+
'Stop running task': 'Stoppa pågående uppgift',
|
|
109
|
+
'Edit config': 'Redigera konfig',
|
|
110
|
+
'Sync package.json': 'Synka package.json',
|
|
111
|
+
'Migrate password to OS keychain': 'Flytta lösenord till nyckelringen',
|
|
112
|
+
'Install dependencies': 'Installera beroenden',
|
|
113
|
+
'Log in': 'Logga in',
|
|
114
|
+
'Log out': 'Logga ut',
|
|
115
|
+
Quit: 'Avsluta',
|
|
116
|
+
Settings: 'Inställningar',
|
|
117
|
+
'build, sign and deploy on change': 'bygg, signera och driftsätt vid ändring',
|
|
118
|
+
'build and deploy on change': 'bygg och driftsätt vid ändring',
|
|
119
|
+
'rebuild and sign only': 'bara bygg om och signera',
|
|
120
|
+
'rebuild only': 'bara bygg om',
|
|
121
|
+
'credentials missing': 'uppgifter saknas',
|
|
122
|
+
'signed zip · confirms first': 'signerad zip · bekräftar först',
|
|
123
|
+
'shared auth and site config for every app': 'delad auth och webbplatskonfig för alla appar',
|
|
124
|
+
'dev properties, auth method, signing': 'dev-egenskaper, auth-metod, signering',
|
|
125
|
+
'{n} diffs': '{n} skillnader',
|
|
126
|
+
'1 diff': '1 skillnad',
|
|
127
|
+
'in sync': 'synkad',
|
|
128
|
+
'forget stored credentials for this site': 'glöm sparade uppgifter för webbplatsen',
|
|
129
|
+
'language, intro animation, workspace config': 'språk, introanimation, arbetsytans konfig',
|
|
130
|
+
'Workspace config': 'Arbetsytans konfig',
|
|
131
|
+
'not configured': 'ej konfigurerad',
|
|
132
|
+
'basic · password needed': 'basic · lösenord krävs',
|
|
133
|
+
'oauth2 · not logged in': 'oauth2 · ej inloggad',
|
|
134
|
+
'sso · not logged in': 'sso · ej inloggad',
|
|
135
|
+
'Dev properties not configured. Edit config first.': 'Dev-egenskaper ej konfigurerade. Redigera konfig först.',
|
|
136
|
+
'Deploy password for {user}@{domain}': 'Driftsättningslösenord för {user}@{domain}',
|
|
137
|
+
'Save to OS keychain': 'Spara i nyckelringen',
|
|
138
|
+
'Signing credentials not configured.': 'Signeringsuppgifter ej konfigurerade.',
|
|
139
|
+
'Signing password for {user} (developer.sitevision.se)': 'Signeringslösenord för {user} (developer.sitevision.se)',
|
|
140
|
+
'A dev/watch task is already running for this app (K stops it).': 'En dev/watch-uppgift körs redan för appen (K stoppar den).',
|
|
141
|
+
'stopped {n} task(s)': 'stoppade {n} uppgift(er)',
|
|
142
|
+
'nothing running': 'inget körs',
|
|
143
|
+
'Not in a workspace: run svc at the repo root.': 'Ingen arbetsyta: kör svc i repots rot.',
|
|
144
|
+
'package.json updated': 'package.json uppdaterad',
|
|
145
|
+
'password moved to keychain': 'lösenord flyttat till nyckelringen',
|
|
146
|
+
'could not access keychain': 'kunde inte nå nyckelringen',
|
|
147
|
+
'logged in': 'inloggad',
|
|
148
|
+
'credentials removed': 'uppgifter borttagna',
|
|
149
|
+
// Config form
|
|
150
|
+
Domain: 'Domän',
|
|
151
|
+
'Site name': 'Webbplatsnamn',
|
|
152
|
+
'Addon name': 'Tilläggsnamn',
|
|
153
|
+
Username: 'Användarnamn',
|
|
154
|
+
'Auth method': 'Auth-metod',
|
|
155
|
+
Password: 'Lösenord',
|
|
156
|
+
'OAuth2 client id': 'OAuth2 klient-id',
|
|
157
|
+
'Authorization endpoint': 'Auktoriseringsendpoint',
|
|
158
|
+
'Token endpoint': 'Token-endpoint',
|
|
159
|
+
Scopes: 'Scopes',
|
|
160
|
+
'Client secret': 'Klienthemlighet',
|
|
161
|
+
'Login URL': 'Inloggnings-URL',
|
|
162
|
+
'Use HTTP': 'Använd HTTP',
|
|
163
|
+
'Signing user': 'Signeringsanvändare',
|
|
164
|
+
Certificate: 'Certifikat',
|
|
165
|
+
'Signing password': 'Signeringslösenord',
|
|
166
|
+
'^O pick from repo': '^O välj från förråd',
|
|
167
|
+
'Space-separated scopes to request. ALL grants the Sitevision API and offline_access adds a refresh token so later runs log in silently. Match the casing your client expects.': 'Scopes att begära, separerade med mellanslag. ALL ger Sitevision-API:et och offline_access ger en refresh-token så att senare körningar loggar in tyst. Använd det skiftläge klienten förväntar sig.',
|
|
168
|
+
'blank = site root': 'tomt = webbplatsens rot',
|
|
169
|
+
'required for signed deploys': 'krävs för signerad driftsättning',
|
|
170
|
+
'blank = prompt each run': 'tomt = fråga varje gång',
|
|
171
|
+
SIGNING: 'SIGNERING',
|
|
172
|
+
ENVIRONMENT: 'MILJÖ',
|
|
173
|
+
'Environment name': 'Miljönamn',
|
|
174
|
+
Production: 'Produktion',
|
|
175
|
+
'What this base configuration is: dev, test, prod… Other environments are added on top of it with E or the palette and override only what differs.': 'Vad denna grundkonfiguration är: dev, test, prod… Andra miljöer läggs ovanpå med E eller paletten och skriver bara över det som skiljer.',
|
|
176
|
+
'Treat deploys to this base environment as production: signed zip, confirmation, activation, and no dev loop. Off by default even when the name says prod, so a repo with only a production site still gets a dev loop.': 'Behandla driftsättningar till grundmiljön som produktion: signerad zip, bekräftelse, aktivering och ingen dev-loop. Av som standard även om namnet säger prod, så att ett repo med bara en produktionssajt ändå får en dev-loop.',
|
|
177
|
+
'Saved {label}.': 'Sparade {label}.',
|
|
178
|
+
'Looking up OAuth2 endpoints…': 'Slår upp OAuth2-endpoints…',
|
|
179
|
+
'Endpoints filled from the site OpenID config.': 'Endpoints ifyllda från webbplatsens OpenID-konfig.',
|
|
180
|
+
'Could not discover OAuth2 endpoints; enter them by hand.': 'Kunde inte hitta OAuth2-endpoints; ange dem manuellt.',
|
|
181
|
+
'✗ required': '✗ krävs',
|
|
182
|
+
keychain: 'nyckelring',
|
|
183
|
+
local: 'lokal',
|
|
184
|
+
'•••••••• keychain': '•••••••• nyckelring',
|
|
185
|
+
FIELD: 'FÄLT',
|
|
186
|
+
VALUE: 'VÄRDE',
|
|
187
|
+
SOURCE: 'KÄLLA',
|
|
188
|
+
"Shared by every app below {root}. An app's own value wins.": 'Delas av alla appar under {root}. Appens eget värde vinner.',
|
|
189
|
+
'PACKAGE.JSON SYNC': 'PACKAGE.JSON-SYNK',
|
|
190
|
+
'no workspace package.json · y to set up': 'ingen package.json i arbetsytan · y för att skapa',
|
|
191
|
+
'Not saved: {error}': 'Inte sparat: {error}',
|
|
192
|
+
'←→ choose · Enter confirm · Esc cancel': '←→ välj · Enter bekräfta · Esc avbryt',
|
|
193
|
+
'Enter save · Esc cancel': 'Enter spara · Esc avbryt',
|
|
194
|
+
'↑↓ field · Enter edit · ^O pick addon': '↑↓ fält · Enter redigera · ^O välj tillägg',
|
|
195
|
+
'↑↓ field · Enter edit': '↑↓ fält · Enter redigera',
|
|
196
|
+
'Tab to edit': 'Tab för att redigera',
|
|
197
|
+
yes: 'ja',
|
|
198
|
+
no: 'nej',
|
|
199
|
+
// Shell
|
|
200
|
+
workspace: 'arbetsyta',
|
|
201
|
+
settings: 'inställningar',
|
|
202
|
+
save: 'spara',
|
|
203
|
+
cancel: 'avbryt',
|
|
204
|
+
field: 'fält',
|
|
205
|
+
edit: 'redigera',
|
|
206
|
+
back: 'tillbaka',
|
|
207
|
+
quit: 'avsluta',
|
|
208
|
+
search: 'sök',
|
|
209
|
+
move: 'flytta',
|
|
210
|
+
select: 'välj',
|
|
211
|
+
clear: 'rensa',
|
|
212
|
+
'no matches': 'inga träffar',
|
|
213
|
+
'{n} matches': '{n} träffar',
|
|
214
|
+
'1 match': '1 träff',
|
|
215
|
+
'edit settings': 'redigera inställningar',
|
|
216
|
+
apps: 'appar',
|
|
217
|
+
activate: 'aktivera',
|
|
218
|
+
refresh: 'uppdatera',
|
|
219
|
+
deploy: 'driftsätt',
|
|
220
|
+
commands: 'kommandon',
|
|
221
|
+
follow: 'följ',
|
|
222
|
+
wrap: 'radbryt',
|
|
223
|
+
stop: 'stoppa',
|
|
224
|
+
'pick addon': 'välj tillägg',
|
|
225
|
+
login: 'logga in',
|
|
226
|
+
install: 'installera',
|
|
227
|
+
'{v} is already active': '{v} är redan aktiv',
|
|
228
|
+
'{v} activated': '{v} aktiverad',
|
|
229
|
+
'No credentials.': 'Inga uppgifter.',
|
|
230
|
+
'not available': 'ej tillgänglig',
|
|
231
|
+
'{n} tasks': '{n} uppgifter',
|
|
232
|
+
idle: 'inaktiv',
|
|
233
|
+
'workspace config saved': 'arbetsytans konfig sparad',
|
|
234
|
+
'config saved': 'konfig sparad',
|
|
235
|
+
'Saved {label} as {value} — a domain is a host only.': 'Sparade {label} som {value} — en domän är enbart ett värdnamn.',
|
|
236
|
+
' · shared .dev_properties.json at the root': ' · delad .dev_properties.json i roten',
|
|
237
|
+
' · new workspace: fill in once, every app inherits · Esc skips': ' · ny arbetsyta: fyll i en gång, alla appar ärver · Esc hoppar över',
|
|
238
|
+
'y confirm · n cancel': 'y bekräfta · n avbryt',
|
|
239
|
+
// Config help
|
|
240
|
+
"Domain of this environment's site (USE or TSE) without https://, e.g. myorg-use.sitevision-cloud.se. Deploys and version lookups go here.": 'Domän för den här miljöns webbplats (USE eller TSE) utan https://, t.ex. myorg-use.sitevision-cloud.se. Driftsättningar och versionslistor går hit.',
|
|
241
|
+
"Name of the site's root node in Sitevision, exactly as shown in the site tree. It becomes part of the REST API path.": 'Namnet på webbplatsens rotnod i Sitevision, exakt som i webbplatsträdet. Det blir en del av REST API-sökvägen.',
|
|
242
|
+
"Name of the addon (custom module) in the site's Addon Repository that this app is uploaded into. Ctrl+O lists the existing ones.": 'Namnet på tillägget (custom module) i webbplatsens tilläggsförråd som appen laddas upp till. Ctrl+O listar befintliga.',
|
|
243
|
+
'Sitevision account used for deploys, usually your Sitevision Cloud e-mail. It needs DEVELOPER or MANAGE_ADDONS permission on the site. Required for basic auth; with oauth2 or cookie it only labels the stored credential.': 'Sitevision-konto som används för driftsättning, oftast din Sitevision Cloud-e-post. Behöver DEVELOPER eller MANAGE_ADDONS på webbplatsen. Krävs för basic; med oauth2 eller cookie används det bara för att märka den sparade inloggningen.',
|
|
244
|
+
"How deploys authenticate: basic = username and password; oauth2 = bearer token from the site's OAuth2 provider (PKCE, opens a browser); cookie = reuse a browser SSO/SAML session.": 'Hur driftsättningar autentiseras: basic = användarnamn och lösenord; oauth2 = bearer-token från webbplatsens OAuth2-provider (PKCE, öppnar webbläsare); cookie = återanvänd en SSO/SAML-session från webbläsaren.',
|
|
245
|
+
'Deploy password for the account above. Stored in the OS keychain, never in a file. Leave empty to be asked on each run.': 'Driftsättningslösenord för kontot ovan. Sparas i nyckelringen, aldrig i en fil. Lämna tomt för att bli tillfrågad varje gång.',
|
|
246
|
+
'Client id of the OAuth2 client registered on the site. Its redirect URI must be http://127.0.0.1:8137/callback.': 'Klient-id för OAuth2-klienten som är registrerad på webbplatsen. Dess redirect-URI måste vara http://127.0.0.1:8137/callback.',
|
|
247
|
+
"The provider's authorization URL. Filled in from the site's OpenID configuration when it can be discovered.": 'Providerns auktoriserings-URL. Fylls i från webbplatsens OpenID-konfiguration när den kan hittas.',
|
|
248
|
+
"The provider's token URL. Filled in from the site's OpenID configuration when it can be discovered.": 'Providerns token-URL. Fylls i från webbplatsens OpenID-konfiguration när den kan hittas.',
|
|
249
|
+
'Secret of a confidential OAuth2 client, stored in the OS keychain. Leave empty for a public client.': 'Hemlighet för en konfidentiell OAuth2-klient, sparas i nyckelringen. Lämna tomt för en publik klient.',
|
|
250
|
+
'Page opened in the browser for the SSO login. Leave empty to use the site root.': 'Sida som öppnas i webbläsaren för SSO-inloggning. Tomt = webbplatsens rot.',
|
|
251
|
+
'Use plain HTTP instead of HTTPS for deploys. Only for local or test servers without TLS.': 'Använd HTTP i stället för HTTPS vid driftsättning. Bara för lokala servrar eller testservrar utan TLS.',
|
|
252
|
+
'Your developer.sitevision.se account. Production deploys need the app signed by it.': 'Ditt konto på developer.sitevision.se. Produktionsdriftsättningar kräver att appen är signerad av det.',
|
|
253
|
+
'Which certificate to sign with when your developer account has several. Leave empty for the default.': 'Vilket certifikat som ska signera när utvecklarkontot har flera. Tomt = standard.',
|
|
254
|
+
'Password for the signing account, stored in the OS keychain. Leave empty to be asked on each run.': 'Lösenord för signeringskontot, sparas i nyckelringen. Lämna tomt för att bli tillfrågad varje gång.',
|
|
255
|
+
// Settings screen
|
|
256
|
+
Language: 'Språk',
|
|
257
|
+
'Intro animation': 'Introanimation',
|
|
258
|
+
on: 'på',
|
|
259
|
+
off: 'av',
|
|
260
|
+
'Saved.': 'Sparat.',
|
|
261
|
+
'stored in {file}': 'sparas i {file}',
|
|
262
|
+
'↑↓ setting · Enter edit · Esc close': '↑↓ inställning · Enter redigera · Esc stäng',
|
|
263
|
+
// Password prompt / login
|
|
264
|
+
'Press Enter to submit, Esc to cancel': 'Tryck Enter för att skicka, Esc för att avbryta',
|
|
265
|
+
'(Tab to toggle)': '(Tab växlar)',
|
|
266
|
+
'OAuth2 login': 'OAuth2-inloggning',
|
|
267
|
+
'Session cookie login': 'Sessionskaka-inloggning',
|
|
268
|
+
'Waiting for you to finish login in the browser…': 'Väntar på att du loggar in i webbläsaren…',
|
|
269
|
+
"If the browser didn't open, visit:": 'Om webbläsaren inte öppnades, gå till:',
|
|
270
|
+
'Opening browser…': 'Öppnar webbläsare…',
|
|
271
|
+
'Log in in the opened browser, then press Enter to capture the session.': 'Logga in i webbläsaren och tryck sedan Enter för att fånga sessionen.',
|
|
272
|
+
'Capturing session…': 'Fångar session…',
|
|
273
|
+
'A Chrome window is open at:': 'Ett Chrome-fönster är öppet på:',
|
|
274
|
+
'1. Log in to the site there, single sign-on included.': '1. Logga in på webbplatsen där, även med enkel inloggning.',
|
|
275
|
+
'2. Wait until the site itself has finished loading.': '2. Vänta tills själva webbplatsen har laddat klart.',
|
|
276
|
+
'3. Come back here and press Enter.': '3. Kom tillbaka hit och tryck Enter.',
|
|
277
|
+
'Leave the browser window open; it closes once the session is captured.': 'Låt webbläsarfönstret vara öppet; det stängs när sessionen har hämtats.',
|
|
278
|
+
'Press Esc to cancel.': 'Tryck Esc för att avbryta.',
|
|
279
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSONC helpers.
|
|
3
|
+
*
|
|
4
|
+
* Sitevision's own manifest documentation shows manifest.json with line and
|
|
5
|
+
* block comments (e.g. `"name": { // Multilingual-manifest requires SV 10.1`),
|
|
6
|
+
* so real-world manifests copied from the docs contain them. Strict JSON.parse
|
|
7
|
+
* rejects those, so we strip comments before parsing.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Remove line comments (//...) and block comments from a JSON string, leaving
|
|
11
|
+
* everything inside string literals untouched (so values like
|
|
12
|
+
* `"https://example.com"` survive).
|
|
13
|
+
*/
|
|
14
|
+
export declare function stripJsonComments(input: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Parse a JSON string that may contain comments (JSONC). Throws the underlying
|
|
17
|
+
* SyntaxError if the content is invalid even after comments are removed.
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseJsonc<T>(input: string): T;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSONC helpers.
|
|
3
|
+
*
|
|
4
|
+
* Sitevision's own manifest documentation shows manifest.json with line and
|
|
5
|
+
* block comments (e.g. `"name": { // Multilingual-manifest requires SV 10.1`),
|
|
6
|
+
* so real-world manifests copied from the docs contain them. Strict JSON.parse
|
|
7
|
+
* rejects those, so we strip comments before parsing.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Remove line comments (//...) and block comments from a JSON string, leaving
|
|
11
|
+
* everything inside string literals untouched (so values like
|
|
12
|
+
* `"https://example.com"` survive).
|
|
13
|
+
*/
|
|
14
|
+
export function stripJsonComments(input) {
|
|
15
|
+
let result = '';
|
|
16
|
+
let inString = false;
|
|
17
|
+
let inLineComment = false;
|
|
18
|
+
let inBlockComment = false;
|
|
19
|
+
for (let i = 0; i < input.length; i++) {
|
|
20
|
+
const char = input[i];
|
|
21
|
+
const next = input[i + 1];
|
|
22
|
+
if (inLineComment) {
|
|
23
|
+
if (char === '\n') {
|
|
24
|
+
inLineComment = false;
|
|
25
|
+
result += char;
|
|
26
|
+
}
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (inBlockComment) {
|
|
30
|
+
if (char === '*' && next === '/') {
|
|
31
|
+
inBlockComment = false;
|
|
32
|
+
i++;
|
|
33
|
+
}
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (inString) {
|
|
37
|
+
result += char;
|
|
38
|
+
// Copy escaped characters verbatim so an escaped quote (\") does not
|
|
39
|
+
// end the string early.
|
|
40
|
+
if (char === '\\') {
|
|
41
|
+
result += next ?? '';
|
|
42
|
+
i++;
|
|
43
|
+
}
|
|
44
|
+
else if (char === '"') {
|
|
45
|
+
inString = false;
|
|
46
|
+
}
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (char === '"') {
|
|
50
|
+
inString = true;
|
|
51
|
+
result += char;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (char === '/' && next === '/') {
|
|
55
|
+
inLineComment = true;
|
|
56
|
+
i++;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (char === '/' && next === '*') {
|
|
60
|
+
inBlockComment = true;
|
|
61
|
+
i++;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
result += char;
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Parse a JSON string that may contain comments (JSONC). Throws the underlying
|
|
70
|
+
* SyntaxError if the content is invalid even after comments are removed.
|
|
71
|
+
*/
|
|
72
|
+
export function parseJsonc(input) {
|
|
73
|
+
return JSON.parse(stripJsonComments(input));
|
|
74
|
+
}
|
package/dist/utils/keychain.d.ts
CHANGED
|
@@ -4,3 +4,12 @@ export declare function deleteDeployPassword(domain: string, username: string):
|
|
|
4
4
|
export declare function getSigningPassword(username: string): string | null;
|
|
5
5
|
export declare function setSigningPassword(username: string, password: string): boolean;
|
|
6
6
|
export declare function deleteSigningPassword(username: string): void;
|
|
7
|
+
export declare function getOAuth2RefreshToken(domain: string, clientId: string): string | null;
|
|
8
|
+
export declare function setOAuth2RefreshToken(domain: string, clientId: string, token: string): boolean;
|
|
9
|
+
export declare function deleteOAuth2RefreshToken(domain: string, clientId: string): void;
|
|
10
|
+
export declare function getOAuth2ClientSecret(domain: string, clientId: string): string | null;
|
|
11
|
+
export declare function setOAuth2ClientSecret(domain: string, clientId: string, secret: string): boolean;
|
|
12
|
+
export declare function deleteOAuth2ClientSecret(domain: string, clientId: string): void;
|
|
13
|
+
export declare function getSessionCookie(domain: string, username: string): string | null;
|
|
14
|
+
export declare function setSessionCookie(domain: string, username: string, cookie: string): boolean;
|
|
15
|
+
export declare function deleteSessionCookie(domain: string, username: string): void;
|
package/dist/utils/keychain.js
CHANGED
|
@@ -6,6 +6,15 @@ function deployAccount(domain, username) {
|
|
|
6
6
|
function signingAccount(username) {
|
|
7
7
|
return `signing:${username}`;
|
|
8
8
|
}
|
|
9
|
+
function oauthRefreshAccount(domain, clientId) {
|
|
10
|
+
return `oauth2-refresh:${clientId}@${domain}`;
|
|
11
|
+
}
|
|
12
|
+
function oauthSecretAccount(domain, clientId) {
|
|
13
|
+
return `oauth2-secret:${clientId}@${domain}`;
|
|
14
|
+
}
|
|
15
|
+
function sessionCookieAccount(domain, username) {
|
|
16
|
+
return `session:${username}@${domain}`;
|
|
17
|
+
}
|
|
9
18
|
function safeGet(account) {
|
|
10
19
|
try {
|
|
11
20
|
return new Entry(SERVICE, account).getPassword();
|
|
@@ -61,3 +70,48 @@ export function deleteSigningPassword(username) {
|
|
|
61
70
|
return;
|
|
62
71
|
safeDelete(signingAccount(username));
|
|
63
72
|
}
|
|
73
|
+
export function getOAuth2RefreshToken(domain, clientId) {
|
|
74
|
+
if (!domain || !clientId)
|
|
75
|
+
return null;
|
|
76
|
+
return safeGet(oauthRefreshAccount(domain, clientId));
|
|
77
|
+
}
|
|
78
|
+
export function setOAuth2RefreshToken(domain, clientId, token) {
|
|
79
|
+
if (!domain || !clientId || !token)
|
|
80
|
+
return false;
|
|
81
|
+
return safeSet(oauthRefreshAccount(domain, clientId), token);
|
|
82
|
+
}
|
|
83
|
+
export function deleteOAuth2RefreshToken(domain, clientId) {
|
|
84
|
+
if (!domain || !clientId)
|
|
85
|
+
return;
|
|
86
|
+
safeDelete(oauthRefreshAccount(domain, clientId));
|
|
87
|
+
}
|
|
88
|
+
export function getOAuth2ClientSecret(domain, clientId) {
|
|
89
|
+
if (!domain || !clientId)
|
|
90
|
+
return null;
|
|
91
|
+
return safeGet(oauthSecretAccount(domain, clientId));
|
|
92
|
+
}
|
|
93
|
+
export function setOAuth2ClientSecret(domain, clientId, secret) {
|
|
94
|
+
if (!domain || !clientId || !secret)
|
|
95
|
+
return false;
|
|
96
|
+
return safeSet(oauthSecretAccount(domain, clientId), secret);
|
|
97
|
+
}
|
|
98
|
+
export function deleteOAuth2ClientSecret(domain, clientId) {
|
|
99
|
+
if (!domain || !clientId)
|
|
100
|
+
return;
|
|
101
|
+
safeDelete(oauthSecretAccount(domain, clientId));
|
|
102
|
+
}
|
|
103
|
+
export function getSessionCookie(domain, username) {
|
|
104
|
+
if (!domain || !username)
|
|
105
|
+
return null;
|
|
106
|
+
return safeGet(sessionCookieAccount(domain, username));
|
|
107
|
+
}
|
|
108
|
+
export function setSessionCookie(domain, username, cookie) {
|
|
109
|
+
if (!domain || !username || !cookie)
|
|
110
|
+
return false;
|
|
111
|
+
return safeSet(sessionCookieAccount(domain, username), cookie);
|
|
112
|
+
}
|
|
113
|
+
export function deleteSessionCookie(domain, username) {
|
|
114
|
+
if (!domain || !username)
|
|
115
|
+
return;
|
|
116
|
+
safeDelete(sessionCookieAccount(domain, username));
|
|
117
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { DevProperties } from '../types/index.js';
|
|
2
|
+
/** Default loopback port. Fixed so a single redirect URI can be whitelisted. */
|
|
3
|
+
export declare const DEFAULT_REDIRECT_PORT = 8137;
|
|
4
|
+
export declare const DEFAULT_SCOPES: string[];
|
|
5
|
+
/** RFC 7636 S256 pair. Exported for testing the challenge derivation. */
|
|
6
|
+
export declare function createPkcePair(): {
|
|
7
|
+
verifier: string;
|
|
8
|
+
challenge: string;
|
|
9
|
+
};
|
|
10
|
+
export interface DiscoveredOAuth2 {
|
|
11
|
+
authorizationEndpoint: string;
|
|
12
|
+
tokenEndpoint: string;
|
|
13
|
+
scopesSupported?: string[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Fetch the site's OpenID configuration (unauthenticated) to auto-fill the
|
|
17
|
+
* authorization/token endpoints. Returns null if it isn't published (provider
|
|
18
|
+
* not enabled) or the response isn't a valid config, so callers fall back to
|
|
19
|
+
* manual entry.
|
|
20
|
+
*/
|
|
21
|
+
export declare function discoverOAuth2Config(domain: string, useHTTP?: boolean): Promise<DiscoveredOAuth2 | null>;
|
|
22
|
+
export declare function openBrowser(url: string): void;
|
|
23
|
+
/**
|
|
24
|
+
* Serve the loopback redirect once. Returns the awaited code and a `close()`
|
|
25
|
+
* that shuts the server down (freeing the port) if the login is cancelled — so
|
|
26
|
+
* a retry doesn't hit an EADDRINUSE on the fixed redirect port.
|
|
27
|
+
*/
|
|
28
|
+
interface LoopbackResult {
|
|
29
|
+
code?: string;
|
|
30
|
+
error?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Turn a redirect's query params into a result, prioritizing the provider's own
|
|
34
|
+
* error (the most useful reason) over a generic "no code". Exported for testing.
|
|
35
|
+
*/
|
|
36
|
+
export declare function classifyRedirect(params: {
|
|
37
|
+
expectedState: string;
|
|
38
|
+
state: string | null;
|
|
39
|
+
error: string | null;
|
|
40
|
+
errorDescription: string | null;
|
|
41
|
+
code: string | null;
|
|
42
|
+
}): LoopbackResult;
|
|
43
|
+
/**
|
|
44
|
+
* Start an interactive OAuth2 login. Returns the authorize URL to open and a
|
|
45
|
+
* `complete()` that awaits the loopback redirect, exchanges the code, stores the
|
|
46
|
+
* refresh token, and resolves the access token. UI-agnostic, so an Ink screen
|
|
47
|
+
* can drive it without owning the terminal.
|
|
48
|
+
*/
|
|
49
|
+
export declare function beginOAuth2Login(dev: DevProperties): {
|
|
50
|
+
authUrl: string;
|
|
51
|
+
complete: () => Promise<{
|
|
52
|
+
token?: string;
|
|
53
|
+
error?: string;
|
|
54
|
+
}>;
|
|
55
|
+
cancel: () => void;
|
|
56
|
+
} | null;
|
|
57
|
+
/**
|
|
58
|
+
* Silently resolve an access token by refreshing the keychain refresh token.
|
|
59
|
+
* Returns null when there's no refresh token or it's expired/revoked (in which
|
|
60
|
+
* case the stale token is dropped). Interactive login lives in `beginOAuth2Login`,
|
|
61
|
+
* driven by the Ink login screen — the access token is never persisted.
|
|
62
|
+
*/
|
|
63
|
+
export declare function resolveOAuth2AccessToken(dev: DevProperties): Promise<string | null>;
|
|
64
|
+
export {};
|