sitevision-cli 1.0.0-beta.9 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/CHANGELOG.md +138 -0
  2. package/LICENSE +21 -0
  3. package/dist/cli.js +194 -70
  4. package/dist/commands/TaskScreen.js +32 -0
  5. package/dist/commands/build.js +6 -185
  6. package/dist/commands/deploy.js +95 -212
  7. package/dist/commands/dev.js +87 -416
  8. package/dist/commands/info.js +1 -1
  9. package/dist/commands/setup-signing.js +50 -33
  10. package/dist/commands/sign.js +9 -86
  11. package/dist/commands/use-finish.js +17 -0
  12. package/dist/commands/watch.js +5 -31
  13. package/dist/components/AnimatedLogo.js +8 -2
  14. package/dist/components/AuthLoginScreen.js +33 -15
  15. package/dist/components/PasswordInput.js +2 -1
  16. package/dist/scaffold/inquirer-stub.js +119 -0
  17. package/dist/scaffold/register.js +15 -0
  18. package/dist/shell/AddonPicker.js +54 -0
  19. package/dist/shell/Changelog.js +44 -0
  20. package/dist/shell/CommandPalette.js +63 -0
  21. package/dist/shell/ConfigForm.js +703 -0
  22. package/dist/shell/Frame.js +138 -0
  23. package/dist/shell/Help.js +96 -0
  24. package/dist/shell/Popover.js +15 -0
  25. package/dist/shell/Settings.js +149 -0
  26. package/dist/shell/Shell.js +953 -0
  27. package/dist/shell/Tabs.js +96 -0
  28. package/dist/shell/actions.js +493 -0
  29. package/dist/utils/config.js +62 -2
  30. package/dist/utils/create-app.js +231 -0
  31. package/dist/utils/debug.js +32 -0
  32. package/dist/utils/environments.js +74 -0
  33. package/dist/utils/i18n.js +369 -0
  34. package/dist/utils/jsonc.js +2 -1
  35. package/dist/utils/keychain.js +54 -6
  36. package/dist/utils/oauth2-auth.js +146 -43
  37. package/dist/utils/password-prompt.js +37 -3
  38. package/dist/utils/process-runner.js +77 -38
  39. package/dist/utils/project-detection.js +457 -112
  40. package/dist/utils/session-cookie-auth.js +10 -6
  41. package/dist/utils/sitevision-api.js +134 -25
  42. package/dist/utils/sitevision-scripts-runner.js +50 -22
  43. package/dist/utils/tasks.js +510 -0
  44. package/dist/utils/version-check.js +3 -3
  45. package/dist/utils/webpack-runner.js +9 -5
  46. package/dist/utils/workspace.js +105 -0
  47. package/dist/utils/zip.js +18 -19
  48. package/package.json +27 -4
  49. package/readme.md +113 -141
  50. package/dist/app.d.ts +0 -6
  51. package/dist/app.js +0 -307
  52. package/dist/cli.d.ts +0 -2
  53. package/dist/commands/build.d.ts +0 -12
  54. package/dist/commands/deploy.d.ts +0 -16
  55. package/dist/commands/dev.d.ts +0 -16
  56. package/dist/commands/index.d.ts +0 -4
  57. package/dist/commands/info.d.ts +0 -2
  58. package/dist/commands/setup-signing.d.ts +0 -2
  59. package/dist/commands/sign.d.ts +0 -14
  60. package/dist/commands/types.d.ts +0 -18
  61. package/dist/commands/watch.d.ts +0 -2
  62. package/dist/components/AnimatedLogo.d.ts +0 -10
  63. package/dist/components/AuthLoginScreen.d.ts +0 -21
  64. package/dist/components/DevPropertiesForm.d.ts +0 -10
  65. package/dist/components/DevPropertiesForm.js +0 -210
  66. package/dist/components/InfoScreen.d.ts +0 -7
  67. package/dist/components/InfoScreen.js +0 -14
  68. package/dist/components/KeychainPasswordChoice.d.ts +0 -8
  69. package/dist/components/KeychainPasswordChoice.js +0 -30
  70. package/dist/components/MainMenu.d.ts +0 -7
  71. package/dist/components/MainMenu.js +0 -83
  72. package/dist/components/PasswordInput.d.ts +0 -10
  73. package/dist/components/ProcessOutput.d.ts +0 -6
  74. package/dist/components/ProcessOutput.js +0 -30
  75. package/dist/components/SetupFlow.d.ts +0 -8
  76. package/dist/components/SetupFlow.js +0 -233
  77. package/dist/components/SigningPropertiesForm.d.ts +0 -7
  78. package/dist/components/SigningPropertiesForm.js +0 -38
  79. package/dist/components/StatusIndicator.d.ts +0 -8
  80. package/dist/components/TextInput.d.ts +0 -10
  81. package/dist/components/TextInput.js +0 -29
  82. package/dist/components/WelcomeScreen.d.ts +0 -14
  83. package/dist/types/index.d.ts +0 -284
  84. package/dist/utils/branding.d.ts +0 -28
  85. package/dist/utils/config.d.ts +0 -17
  86. package/dist/utils/jsonc.d.ts +0 -19
  87. package/dist/utils/keychain.d.ts +0 -15
  88. package/dist/utils/oauth2-auth.d.ts +0 -27
  89. package/dist/utils/password-prompt.d.ts +0 -14
  90. package/dist/utils/process-runner.d.ts +0 -22
  91. package/dist/utils/project-detection.d.ts +0 -151
  92. package/dist/utils/session-cookie-auth.d.ts +0 -34
  93. package/dist/utils/signing-password.d.ts +0 -12
  94. package/dist/utils/signing-step.d.ts +0 -15
  95. package/dist/utils/signing-step.js +0 -16
  96. package/dist/utils/sitevision-api.d.ts +0 -112
  97. package/dist/utils/sitevision-scripts-runner.d.ts +0 -83
  98. package/dist/utils/version-check.d.ts +0 -9
  99. package/dist/utils/webpack-runner.d.ts +0 -76
  100. package/dist/utils/zip.d.ts +0 -71
@@ -0,0 +1,369 @@
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': '↑ root',
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_properties',
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 funna 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: 'Deploy',
93
+ 'Deploy (force)': 'Deploy (force)',
94
+ 'to {env}': 'till {env}',
95
+ 'Switch environment': 'Byt miljö',
96
+ 'Add environment': 'Lägg till miljö',
97
+ Help: 'Hjälp',
98
+ 'every key in one place': 'alla kortkommandon på ett ställe',
99
+ Keys: 'Tangenter',
100
+ 'Esc close': 'Esc stäng',
101
+ Here: 'Här',
102
+ 'Move around': 'Förflytta dig',
103
+ 'switch pane': 'byt panel',
104
+ tabs: 'flikar',
105
+ help: 'hjälp',
106
+ // Help guide
107
+ 'Typing filters the app list. ↑↓ move, Enter selects the app and moves focus to the content pane. Action keys such as d or p only work there; in the navigator they search.': 'Skriv för att filtrera applistan. ↑↓ flyttar, Enter väljer appen och flyttar fokus till innehållspanelen. Åtgärdstangenter som d eller p fungerar bara där; i navigatorn söker de.',
108
+ 'The last row is Workspace settings: the shared root config that every app inherits.': 'Sista raden är Arbetsytans inställningar: den delade rotkonfigurationen som alla appar ärver.',
109
+ "The root .dev_properties.json shared by every app, with the root package.json defaults underneath. Fill in site, auth and environments once; an app's own config overrides only what differs.": 'Rotens .dev_properties.json som delas av alla appar, med rotens package.json som standardvärden under. Fyll i webbplats, autentisering och miljöer en gång; en apps egen konfig skriver bara över det som skiljer.',
110
+ 'Same keys as the Config tab: Enter edits and saves, Esc cancels, ←→ or space cycles choices.': 'Samma tangenter som Konfig-fliken: Enter redigerar och sparar, Esc avbryter, ←→ eller mellanslag bläddrar bland val.',
111
+ 'Each status line names the key that fixes it: i installs dependencies, e opens Config, y syncs package.json, / sets up signing.': 'Varje statusrad anger tangenten som åtgärdar den: i installerar beroenden, e öppnar Konfig, y synkar package.json, / sätter upp signering.',
112
+ 'The badge in the top bar is the active environment: green for the base, yellow for others, red for production. v cycles it.': 'Märket i toppraden är den aktiva miljön: grönt för basen, gult för övriga, rött för produktion. v växlar.',
113
+ 'Values come in layers and the source is shown next to each: your local .dev_properties.json wins, shared package.json values sit underneath, and in a workspace the root config underneath that. Environments add on top of the base and override only what differs.': 'Värden kommer i lager och källan visas bredvid varje: din lokala .dev_properties.json vinner, delade värden i package.json ligger under, och i en arbetsyta rotkonfigurationen under det. Miljöer läggs ovanpå basen och skriver bara över det som skiljer.',
114
+ 'Enter edits and saves a field, Esc cancels, ←→ or space cycles choices, Ctrl+O lists the addons on the site. y copies shared values into package.json for the team.': 'Enter redigerar och sparar ett fält, Esc avbryter, ←→ eller mellanslag bläddrar bland val, Ctrl+O listar webbplatsens tillägg. y kopierar delade värden till package.json för teamet.',
115
+ 'Passwords and secrets go to the OS keychain, never to a file. Leave them empty to be asked on each run.': 'Lösenord och hemligheter sparas i nyckelringen, aldrig i en fil. Lämna dem tomma för att bli tillfrågad varje gång.',
116
+ "The versions uploaded to the addon on the active environment's site, the domain in the top bar. v switches environment.": 'Versionerna som laddats upp till tillägget på den aktiva miljöns webbplats, domänen i toppraden. v byter miljö.',
117
+ '↑↓ select, a activates the selected version, r refreshes. Production deploys activate on their own.': '↑↓ väljer, a aktiverar vald version, r uppdaterar. Produktionsdriftsättningar aktiverar själva.',
118
+ 'Output from build, sign, deploy, dev and watch for the selected app. Dev and watch keep running while you switch apps; K stops them.': 'Utdata från build, sign, deploy, dev och watch för vald app. Dev och watch fortsätter köra medan du byter app; K stoppar dem.',
119
+ '↑↓ scroll, PgUp/PgDn page, f jumps to the end, x toggles line wrap.': '↑↓ scrollar, PgUp/PgDn bläddrar sida, f hoppar till slutet, x växlar radbrytning.',
120
+ "What's new": 'Nyheter',
121
+ 'changelog for every release': 'ändringslogg för varje version',
122
+ Changelog: 'Ändringslogg',
123
+ "What's new since {version}": 'Nyheter sedan {version}',
124
+ '↑↓ scroll · Esc close': '↑↓ scrolla · Esc stäng',
125
+ 'No changelog found.': 'Ingen ändringslogg hittades.',
126
+ 'Create addon': 'Skapa tillägg',
127
+ 'Create addon failed': 'Kunde inte skapa tillägget',
128
+ 'addon {addon} created': 'tillägget {addon} skapat',
129
+ 'Addon {addon} does not exist on {domain}. Create it and deploy again?': 'Tillägget {addon} finns inte på {domain}. Skapa det och driftsätt igen?',
130
+ 'e.g. test or prod, overriding domain and auth': 't.ex. test eller prod, med egen domän och auth',
131
+ 'Environment name (e.g. test, prod)': 'Miljönamn (t.ex. test, prod)',
132
+ 'Deploy the signed {id} to {env} (addon {addon}) and activate it?': 'Driftsätt signerade {id} till {env} (addon {addon}) och aktivera?',
133
+ 'Dev never deploys to a production environment ({env}). Switch with v.': 'Dev driftsätter aldrig till en produktionsmiljö ({env}). Byt med v.',
134
+ 'switched to {env}': 'bytte till {env}',
135
+ 'environment {env} added': 'miljön {env} tillagd',
136
+ environment: 'miljö',
137
+ production: 'produktion',
138
+ env: 'miljö',
139
+ '↑ dev': '↑ dev',
140
+ 'Activate a remote version': 'Aktivera en uppladdad version',
141
+ 'Stop running task': 'Stoppa pågående körning',
142
+ 'Edit config': 'Redigera konfig',
143
+ 'New app': 'Ny app',
144
+ 'Skipped: {reason}': 'Hoppade över: {reason}',
145
+ 'Skipped {n} apps. First: {reason}': 'Hoppade över {n} appar. Första: {reason}',
146
+ 'A new app is still being created. Stop it and quit?': 'En ny app håller på att skapas. Avbryta den och avsluta?',
147
+ 'An app is already being created.': 'En app håller redan på att skapas.',
148
+ 'Could not save to the OS keychain; you will be asked again next time.': 'Kunde inte spara i nyckelringen; du får frågan igen nästa gång.',
149
+ Navigator: 'Navigering',
150
+ 'Sync package.json': 'Synka package.json',
151
+ 'Migrate password to OS keychain': 'Flytta lösenord till nyckelringen',
152
+ 'Install dependencies': 'Installera beroenden',
153
+ 'Log in': 'Logga in',
154
+ 'Log out': 'Logga ut',
155
+ Quit: 'Avsluta',
156
+ Settings: 'Inställningar',
157
+ 'build, sign and deploy on change': 'bygg, signera och driftsätt vid ändring',
158
+ 'build and deploy on change': 'bygg och driftsätt vid ändring',
159
+ 'rebuild and sign only': 'bara bygg om och signera',
160
+ 'rebuild only': 'bara bygg om',
161
+ 'credentials missing': 'uppgifter saknas',
162
+ 'signed zip · confirms first': 'signerad zip · bekräftar först',
163
+ 'shared auth and site config for every app': 'delad auth och webbplatskonfig för alla appar',
164
+ 'dev properties, auth method, signing': 'dev-egenskaper, auth-metod, signering',
165
+ '{n} diffs': '{n} skillnader',
166
+ '1 diff': '1 skillnad',
167
+ 'in sync': 'synkad',
168
+ 'forget stored credentials for this site': 'glöm sparade uppgifter för webbplatsen',
169
+ 'language, intro animation, workspace config': 'språk, introanimation, arbetsytans konfig',
170
+ 'Workspace config': 'Arbetsytans konfig',
171
+ 'not configured': 'ej konfigurerad',
172
+ 'basic · password needed': 'basic · lösenord krävs',
173
+ 'oauth2 · not logged in': 'oauth2 · ej inloggad',
174
+ 'sso · not logged in': 'sso · ej inloggad',
175
+ 'Dev properties not configured. Edit config first.': 'Dev-egenskaper ej konfigurerade. Redigera konfig först.',
176
+ 'Deploy password for {user}@{domain}': 'Driftsättningslösenord för {user}@{domain}',
177
+ 'Save to OS keychain': 'Spara i nyckelringen',
178
+ 'Signing credentials not configured.': 'Signeringsuppgifter ej konfigurerade.',
179
+ 'Signing password for {user} (developer.sitevision.se)': 'Signeringslösenord för {user} (developer.sitevision.se)',
180
+ '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).',
181
+ 'stopped {n} task(s)': 'stoppade {n} uppgift(er)',
182
+ 'nothing running': 'inget körs',
183
+ 'Not in a workspace: run svc at the repo root.': 'Ingen arbetsyta: kör svc i repots rot.',
184
+ 'package.json updated': 'package.json uppdaterad',
185
+ 'password moved to keychain': 'lösenord flyttat till nyckelringen',
186
+ 'could not access keychain': 'kunde inte nå nyckelringen',
187
+ 'logged in': 'inloggad',
188
+ 'credentials removed': 'uppgifter borttagna',
189
+ // Config form
190
+ Domain: 'Domän',
191
+ 'Site name': 'Webbplatsnamn',
192
+ 'Addon name': 'Tilläggsnamn',
193
+ Username: 'Användarnamn',
194
+ 'Auth method': 'Auth-metod',
195
+ Password: 'Lösenord',
196
+ 'OAuth2 client id': 'OAuth2 klient-id',
197
+ 'Authorization endpoint': 'Authorization url',
198
+ 'Token endpoint': 'Token-endpoint',
199
+ Scopes: 'Scopes',
200
+ 'Client secret': 'Klienthemlighet',
201
+ 'Login URL': 'Inloggnings-URL',
202
+ 'Use HTTP': 'Använd HTTP',
203
+ 'Signing user': 'Signeringsanvändare',
204
+ Certificate: 'Certifikat',
205
+ 'Signing password': 'Signeringslösenord',
206
+ '^O pick from repo': '^O välj från förråd',
207
+ '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. Skriftlägesskänsligt.',
208
+ 'blank = site root': 'tomt = webbplatsens rot',
209
+ 'required for signed deploys': 'krävs för signerad driftsättning',
210
+ 'blank = prompt each run': 'tomt = fråga varje gång',
211
+ SIGNING: 'SIGNERING',
212
+ MANIFEST: 'MANIFEST',
213
+ // New app
214
+ 'Name of the new app': 'Namn på den nya appen',
215
+ 'Create it in folder': 'Skapa den i mappen',
216
+ 'Other folder…': 'Annan mapp…',
217
+ 'Type a name for the app, for example my-new-app.': 'Skriv ett namn på appen, till exempel min-nya-app.',
218
+ 'Try "{suggestion}".': 'Prova "{suggestion}".',
219
+ "An app name can't have spaces.": 'Ett appnamn kan inte innehålla mellanslag.',
220
+ "An app name can't contain {chars}: it becomes the folder, the package name and the app id.": 'Ett appnamn kan inte innehålla {chars}: det blir mappen, paketnamnet och appens id.',
221
+ 'Lowercase is safer: npm expects it, and "{name}" and "{lower}" are one folder on macOS and Windows but two on Linux. Try "{suggestion}", or press Enter again to keep "{name}".': 'Gemener är säkrare: npm förväntar sig det, och "{name}" och "{lower}" är samma mapp på macOS och Windows men två på Linux. Prova "{suggestion}", eller tryck Enter igen för att behålla "{name}".',
222
+ 'Start the name with a letter or a digit.': 'Börja namnet med en bokstav eller en siffra.',
223
+ '{dir} already exists. Pick another name, or keep it and choose a different folder next.': '{dir} finns redan. Välj ett annat namn, eller behåll det och välj en annan mapp i nästa steg.',
224
+ 'creating {app}: installing, questions follow': 'skapar {app}: installerar, frågor kommer strax',
225
+ 'The scaffolder could not be run from here': 'Verktyget kunde inte köras härifrån',
226
+ 'creating {app} failed, see the log': 'kunde inte skapa {app}, se loggen',
227
+ '{app} created in {dir}': '{app} skapad i {dir}',
228
+ '{app} created': '{app} skapad',
229
+ 'Create the addon "{addon}" on {domain} now?': 'Skapa tillägget "{addon}" på {domain} nu?',
230
+ '↑↓ move · Space toggle · Enter submit · Esc cancel': '↑↓ flytta · Mellanslag markera · Enter skicka · Esc avbryt',
231
+ 'App id': 'App-id',
232
+ Version: 'Version',
233
+ Name: 'Namn',
234
+ Description: 'Beskrivning',
235
+ Author: 'Författare',
236
+ 'Help URL': 'Hjälp-URL',
237
+ 'Not saved: {label} is required.': 'Inte sparat: {label} krävs.',
238
+ 'Identifier of the app in Sitevision; it also names the zip. Changing it makes the next deploy a new app instead of an update.': 'Appens identifierare i Sitevision; den namnger också zip-filen. Ändras den blir nästa driftsättning en ny app i stället för en uppdatering.',
239
+ 'Version of the app. Id and version together identify an upload, so bump it to deploy a new version instead of overwriting the current one.': 'Appens version. Id och version identifierar tillsammans en uppladdning, så höj den för att driftsätta en ny version i stället för att skriva över den nuvarande.',
240
+ 'Name shown when importing and administering the app in the Sitevision editor. A multilingual manifest needs at least English.': 'Namnet som visas när appen importeras och administreras i Sitevisions redigerare. Ett flerspråkigt manifest behöver minst engelska.',
241
+ 'Short description shown next to the name in the Sitevision editor.': 'Kort beskrivning som visas bredvid namnet i Sitevisions redigerare.',
242
+ 'Who made the app, shown in the Sitevision editor.': 'Vem som gjort appen, visas i Sitevisions redigerare.',
243
+ "Link to the app's documentation, shown in the Sitevision editor.": 'Länk till appens dokumentation, visas i Sitevisions redigerare.',
244
+ ENVIRONMENT: 'MILJÖ',
245
+ 'Environment name': 'Miljönamn',
246
+ Production: 'Produktion',
247
+ '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.',
248
+ '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.',
249
+ 'Saved {label}.': 'Sparade {label}.',
250
+ 'Looking up OAuth2 endpoints…': 'Slår upp OAuth2-endpoints…',
251
+ 'Endpoints filled from the site OpenID config.': 'Endpoints ifyllda från webbplatsens OpenID-konfig.',
252
+ 'Could not discover OAuth2 endpoints; enter them by hand.': 'Kunde inte hitta OAuth2-endpoints; ange dem manuellt.',
253
+ '✗ required': '✗ krävs',
254
+ keychain: 'nyckelring',
255
+ local: 'lokal',
256
+ '•••••••• keychain': '•••••••• nyckelring',
257
+ FIELD: 'FÄLT',
258
+ VALUE: 'VÄRDE',
259
+ SOURCE: 'KÄLLA',
260
+ "Shared by every app below {root}. An app's own value wins.": 'Delas av alla appar under {root}. Appens eget värde vinner.',
261
+ 'PACKAGE.JSON SYNC': 'PACKAGE.JSON-SYNK',
262
+ 'no workspace package.json · y to set up': 'ingen package.json i arbetsytan · y för att skapa',
263
+ 'Not saved: {error}': 'Inte sparat: {error}',
264
+ '←→ choose · Enter confirm · Esc cancel': '←→ välj · Enter bekräfta · Esc avbryt',
265
+ 'Enter save · Esc cancel': 'Enter spara · Esc avbryt',
266
+ '↑↓ field · Enter edit · ^O pick addon': '↑↓ fält · Enter redigera · ^O välj tillägg',
267
+ '↑↓ field · Enter edit': '↑↓ fält · Enter redigera',
268
+ 'Tab to edit': 'Tab för att redigera',
269
+ yes: 'ja',
270
+ no: 'nej',
271
+ // Shell
272
+ workspace: 'arbetsyta',
273
+ settings: 'inställningar',
274
+ save: 'spara',
275
+ cancel: 'avbryt',
276
+ field: 'fält',
277
+ edit: 'redigera',
278
+ back: 'tillbaka',
279
+ quit: 'avsluta',
280
+ search: 'sök',
281
+ move: 'flytta',
282
+ select: 'välj',
283
+ clear: 'rensa',
284
+ 'no matches': 'inga träffar',
285
+ '{n} matches': '{n} träffar',
286
+ '1 match': '1 träff',
287
+ 'edit settings': 'redigera inställningar',
288
+ apps: 'appar',
289
+ activate: 'aktivera',
290
+ refresh: 'uppdatera',
291
+ deploy: 'driftsätt',
292
+ force: 'tvinga',
293
+ versions: 'versioner',
294
+ commands: 'kommandon',
295
+ follow: 'följ',
296
+ wrap: 'radbryt',
297
+ stop: 'stoppa',
298
+ 'pick addon': 'välj tillägg',
299
+ login: 'logga in',
300
+ install: 'installera',
301
+ '{v} is already active': '{v} är redan aktiv',
302
+ '{v} activated': '{v} aktiverad',
303
+ 'No credentials.': 'Inga uppgifter.',
304
+ 'not available': 'ej tillgänglig',
305
+ '{n} tasks': '{n} uppgifter',
306
+ idle: 'inaktiv',
307
+ 'workspace config saved': 'arbetsytans konfig sparad',
308
+ 'config saved': 'konfig sparad',
309
+ 'Saved {label} as {value} — a domain is a host only.': 'Sparade {label} som {value} — en domän är enbart ett värdnamn.',
310
+ ' · shared .dev_properties.json at the root': ' · delad .dev_properties.json i roten',
311
+ ' · new workspace: fill in once, every app inherits · Esc skips': ' · ny arbetsyta: fyll i en gång, alla appar ärver · Esc hoppar över',
312
+ 'y confirm · n cancel': 'y bekräfta · n avbryt',
313
+ // Config help
314
+ "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.',
315
+ "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.',
316
+ "Name of the addon (custom module) in the site's Addon Repository that this app is uploaded into. Ctrl+O lists the existing ones. It is separate from the manifest name: to make them match, rename the addon in Sitevision (Addons, General, Settings) and pick it again with Ctrl+O. For a RESTApp the addon name is part of its endpoint URL.": 'Namnet på tillägget (custom module) i webbplatsens tilläggsförråd som appen laddas upp till. Ctrl+O listar befintliga. Det är skilt från manifestets namn: för att få dem att stämma, byt namn på tillägget i Sitevision (Tillägg, Allmänt, Inställningar) och välj det igen med Ctrl+O. För en RESTApp ingår tilläggets namn i dess endpoint-URL.',
317
+ '≠ manifest': '≠ manifest',
318
+ 'addon name {addon} · manifest name {names}': 'tilläggsnamn {addon} · manifestnamn {names}',
319
+ '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.',
320
+ "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.',
321
+ '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.',
322
+ '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.',
323
+ "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.',
324
+ "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.',
325
+ '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.',
326
+ '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.',
327
+ '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.',
328
+ '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.',
329
+ '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.',
330
+ '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.',
331
+ // Settings screen
332
+ Language: 'Språk',
333
+ 'Intro animation': 'Introanimation',
334
+ 'Update check': 'Uppdateringskoll',
335
+ 'Addon name warning': 'Varning om tilläggsnamn',
336
+ 'Default signing user': 'Förvald signeringsanvändare',
337
+ 'Default certificate': 'Förvalt certifikat',
338
+ 'The language svc itself speaks.': 'Språket som svc självt använder.',
339
+ 'Play the logo animation when the shell starts.': 'Spela logotypanimationen när skalet startar.',
340
+ 'Look for a newer svc on npm at start.': 'Leta efter en nyare svc på npm vid start.',
341
+ 'Mark the addon name with ≠ manifest when it is none of the names in manifest.json.': 'Markera tilläggsnamnet med ≠ manifest när det inte är något av namnen i manifest.json.',
342
+ 'The developer.sitevision.se account that signs in every project without a signing user of its own.': 'Kontot på developer.sitevision.se som signerar i alla projekt utan egen signeringsanvändare.',
343
+ 'Which certificate signs when the account has several. Empty = the account default.': 'Vilket certifikat som signerar när kontot har flera. Tomt = kontots standard.',
344
+ 'Enter confirm · Esc cancel': 'Enter bekräfta · Esc avbryt',
345
+ 'Not saved: the settings file does not parse.': 'Inte sparat: inställningsfilen går inte att tolka.',
346
+ 'The settings file does not parse and is ignored until it is fixed.': 'Inställningsfilen går inte att tolka och ignoreras tills den är lagad.',
347
+ global: 'global',
348
+ on: 'på',
349
+ off: 'av',
350
+ 'Saved.': 'Sparat.',
351
+ 'stored in {file}': 'sparas i {file}',
352
+ '↑↓ setting · Enter edit · Esc close': '↑↓ inställning · Enter redigera · Esc stäng',
353
+ // Password prompt / login
354
+ 'Press Enter to submit, Esc to cancel': 'Tryck Enter för att skicka, Esc för att avbryta',
355
+ '(Tab to toggle)': '(Tab växlar)',
356
+ 'OAuth2 login': 'OAuth2-inloggning',
357
+ 'Session cookie login': 'Sessionskaka-inloggning',
358
+ 'Waiting for you to finish login in the browser…': 'Väntar på att du loggar in i webbläsaren…',
359
+ "If the browser didn't open, visit:": 'Om webbläsaren inte öppnades, gå till:',
360
+ 'Opening browser…': 'Öppnar webbläsare…',
361
+ '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.',
362
+ 'Capturing session…': 'Fångar session…',
363
+ 'A Chrome window is open at:': 'Ett Chrome-fönster är öppet på:',
364
+ '1. Log in to the site there, single sign-on included.': '1. Logga in på webbplatsen där, även med enkel inloggning.',
365
+ '2. Wait until the site itself has finished loading.': '2. Vänta tills själva webbplatsen har laddat klart.',
366
+ '3. Come back here and press Enter.': '3. Kom tillbaka hit och tryck Enter.',
367
+ '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.',
368
+ 'Press Esc to cancel.': 'Tryck Esc för att avbryta.',
369
+ };
@@ -70,5 +70,6 @@ export function stripJsonComments(input) {
70
70
  * SyntaxError if the content is invalid even after comments are removed.
71
71
  */
72
72
  export function parseJsonc(input) {
73
- return JSON.parse(stripJsonComments(input));
73
+ // Editors on Windows may prepend a BOM, which JSON.parse rejects.
74
+ return JSON.parse(stripJsonComments(input.replace(/^\uFEFF/, '')));
74
75
  }
@@ -1,5 +1,37 @@
1
- import { Entry } from '@napi-rs/keyring';
1
+ import { createRequire } from 'node:module';
2
+ import { debug } from './debug.js';
2
3
  const SERVICE = 'sitevision-cli';
4
+ let EntryImpl;
5
+ // SVC_NO_KEYCHAIN=1 turns the keychain off (documented, for CI). `memory` is
6
+ // for the test suite only: secrets live and die with the process.
7
+ const memory = new Map();
8
+ const memoryEntry = (account) => ({
9
+ getPassword: () => memory.get(account) ?? null,
10
+ setPassword(password) {
11
+ memory.set(account, password);
12
+ },
13
+ deletePassword: () => memory.delete(account),
14
+ });
15
+ // Loaded on first use so a missing native binding never breaks startup.
16
+ function entry(account) {
17
+ const off = process.env['SVC_NO_KEYCHAIN'];
18
+ if (off === 'memory')
19
+ return memoryEntry(account);
20
+ if (off)
21
+ throw new Error('Keychain disabled');
22
+ if (EntryImpl === undefined) {
23
+ try {
24
+ const keyring = createRequire(import.meta.url)('@napi-rs/keyring');
25
+ EntryImpl = keyring.Entry;
26
+ }
27
+ catch {
28
+ EntryImpl = null;
29
+ }
30
+ }
31
+ if (!EntryImpl)
32
+ throw new Error('Keychain unavailable');
33
+ return new EntryImpl(SERVICE, account);
34
+ }
3
35
  function deployAccount(domain, username) {
4
36
  return `deploy:${username}@${domain}`;
5
37
  }
@@ -17,24 +49,40 @@ function sessionCookieAccount(domain, username) {
17
49
  }
18
50
  function safeGet(account) {
19
51
  try {
20
- return new Entry(SERVICE, account).getPassword();
52
+ const value = entry(account).getPassword();
53
+ debug('keychain', `get ${account}: ${value ? 'found' : 'none'}`);
54
+ return value;
21
55
  }
22
- catch {
56
+ catch (error) {
57
+ debug('keychain', `get ${account}: ${error.message}`);
23
58
  return null;
24
59
  }
25
60
  }
61
+ let saveFailed = () => {
62
+ debug('out', 'Could not save to the OS keychain');
63
+ console.warn('\u001B[33mCould not save to the OS keychain; you will be asked again next time.\u001B[0m');
64
+ };
65
+ /** Replace how a failed keychain save is reported (the shell shows a notice). */
66
+ export function onKeychainSaveFailed(listener) {
67
+ saveFailed = listener;
68
+ }
26
69
  function safeSet(account, password) {
27
70
  try {
28
- new Entry(SERVICE, account).setPassword(password);
71
+ entry(account).setPassword(password);
72
+ debug('keychain', `set ${account}`);
29
73
  return true;
30
74
  }
31
- catch {
75
+ catch (error) {
76
+ debug('keychain', `set ${account}: ${error.message}`);
77
+ // Callers mostly ignore the result, so the user hears it from here.
78
+ saveFailed();
32
79
  return false;
33
80
  }
34
81
  }
35
82
  function safeDelete(account) {
36
83
  try {
37
- new Entry(SERVICE, account).deletePassword();
84
+ entry(account).deletePassword();
85
+ debug('keychain', `delete ${account}`);
38
86
  }
39
87
  catch {
40
88
  // ignore