relmio 0.3.0 → 0.4.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.
@@ -0,0 +1,442 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <meta
7
+ name="description"
8
+ content="Install a loopback-only Relmio endpoint for the OpenAI API or the official Codex App Server."
9
+ />
10
+ <title>Relmio | Local Endpoint Setup</title>
11
+ <link
12
+ rel="icon"
13
+ href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cpath fill='%23137c74' d='M7 8h19l31 24H41L26 20v10L7 17Z'/%3E%3Cpath fill='%2312211f' d='M7 47l19-13v10l15-12h16L26 56H7Z'/%3E%3C/svg%3E"
14
+ />
15
+ <link rel="stylesheet" href="/styles.css" />
16
+ <link rel="stylesheet" href="/local.css" />
17
+ <script src="/local.js" type="module"></script>
18
+ </head>
19
+ <body class="local-wizard" data-current-step="1">
20
+ <a class="skip-link" href="#main-content">Skip to local setup</a>
21
+
22
+ <header class="site-header">
23
+ <div class="brand">
24
+ <svg
25
+ class="brand-mark"
26
+ viewBox="0 0 64 64"
27
+ aria-hidden="true"
28
+ focusable="false"
29
+ >
30
+ <path fill="#137c74" d="M7 8h19l31 24H41L26 20v10L7 17Z" />
31
+ <path fill="#12211f" d="M7 47l19-13v10l15-12h16L26 56H7Z" />
32
+ </svg>
33
+ <span>Relmio</span>
34
+ </div>
35
+ <span class="local-badge">Bound to this computer only</span>
36
+ </header>
37
+
38
+ <main id="main-content" class="shell" tabindex="-1">
39
+ <aside class="rail" aria-label="Local setup progress and safety">
40
+ <section class="intro" aria-labelledby="page-title">
41
+ <h1 id="page-title">Run Relmio on localhost</h1>
42
+ <p class="lede">
43
+ Choose the official credential path that matches your client. Both
44
+ options run in a hardened Docker container and bind only to
45
+ <code>127.0.0.1</code>.
46
+ </p>
47
+ </section>
48
+
49
+ <nav class="steps" aria-label="Local setup progress">
50
+ <ol>
51
+ <li data-step-marker="1" aria-current="step">
52
+ <span>1</span><em>Choose</em>
53
+ </li>
54
+ <li data-step-marker="2"><span>2</span><em>Review</em></li>
55
+ <li data-step-marker="3"><span>3</span><em>Install</em></li>
56
+ <li data-step-marker="4"><span>4</span><em>Ready</em></li>
57
+ </ol>
58
+ </nav>
59
+
60
+ <div class="toast-stack" aria-label="Local setup notifications">
61
+ <aside class="toast safety-note" aria-label="Local-only guarantee">
62
+ <strong>Loopback-only guarantee</strong>
63
+ <span>
64
+ Relmio publishes the selected port on <code>127.0.0.1</code>, not
65
+ your LAN or the public internet.
66
+ </span>
67
+ </aside>
68
+
69
+ <aside
70
+ id="trust-warning"
71
+ class="toast safety-note backup-note"
72
+ aria-label="Credential boundary"
73
+ >
74
+ <strong>Two different credentials</strong>
75
+ <span>
76
+ A ChatGPT subscription is not an OpenAI Platform API key.
77
+ Relmio never converts one into the other.
78
+ </span>
79
+ </aside>
80
+
81
+ <div id="global-message" class="toast message" role="status" aria-live="polite">
82
+ <span id="global-message-text">Checking local Docker…</span>
83
+ </div>
84
+
85
+ <div
86
+ id="global-error"
87
+ class="toast error"
88
+ role="alert"
89
+ tabindex="-1"
90
+ hidden
91
+ >
92
+ <span id="global-error-text"></span>
93
+ </div>
94
+ </div>
95
+ </aside>
96
+
97
+ <section class="panel" data-step="1" aria-labelledby="choose-title">
98
+ <div class="panel-heading">
99
+ <h2 id="choose-title" tabindex="-1">Choose the local endpoint</h2>
100
+ <p>
101
+ Docker stays on this computer. Relmio checks it without changing
102
+ any running containers.
103
+ </p>
104
+ </div>
105
+
106
+ <div class="status-row" aria-live="polite">
107
+ <span id="docker-indicator" class="status-dot" aria-hidden="true"></span>
108
+ <div>
109
+ <strong id="docker-status-title">Checking Docker…</strong>
110
+ <p id="docker-status-detail">Looking for Docker Engine and Compose.</p>
111
+ </div>
112
+ </div>
113
+
114
+ <aside class="policy-note">
115
+ <strong>macOS, Linux, or WSL2 required</strong>
116
+ <p>
117
+ Native Windows is not supported because this feature requires POSIX
118
+ owner-only file permissions for local credentials.
119
+ </p>
120
+ </aside>
121
+
122
+ <form id="target-form">
123
+ <fieldset class="target-picker">
124
+ <legend>Credential and protocol</legend>
125
+
126
+ <label class="target-card">
127
+ <input type="radio" name="target" value="openai-api" checked />
128
+ <span class="target-card-copy">
129
+ <strong>OpenAI API endpoint</strong>
130
+ <span class="target-meta">Stable · apps and web apps</span>
131
+ <span>
132
+ OpenAI-compatible <code>/v1</code>, backed only by your
133
+ OpenAI Platform API key. Platform API usage is billed
134
+ separately from ChatGPT.
135
+ </span>
136
+ </span>
137
+ </label>
138
+
139
+ <label class="target-card warning-card">
140
+ <input type="radio" name="target" value="codex-chatgpt" />
141
+ <span class="target-card-copy">
142
+ <strong>Codex App Server</strong>
143
+ <span class="target-meta">Experimental · trusted native apps only</span>
144
+ <span>
145
+ Official Codex JSON-RPC over WebSocket, using ChatGPT sign-in.
146
+ This is not an OpenAI-compatible <code>/v1</code> endpoint and
147
+ browsers cannot connect directly. Codex App Server WebSocket is experimental and unsupported for production workloads.
148
+ </span>
149
+ </span>
150
+ </label>
151
+ </fieldset>
152
+
153
+ <div class="field-grid local-fields">
154
+ <label class="field compact">
155
+ <span>Local port</span>
156
+ <input
157
+ id="local-port"
158
+ name="port"
159
+ type="number"
160
+ min="1024"
161
+ max="65535"
162
+ value="12435"
163
+ required
164
+ />
165
+ <small>Published only on <code>127.0.0.1</code>.</small>
166
+ </label>
167
+
168
+ <label id="origins-field" class="field">
169
+ <span>Allowed browser origins <small>(optional, one per line)</small></span>
170
+ <textarea
171
+ id="allowed-origins"
172
+ name="allowedOrigins"
173
+ rows="3"
174
+ maxlength="20480"
175
+ spellcheck="false"
176
+ placeholder="http://localhost:3000"
177
+ ></textarea>
178
+ <small>
179
+ Exact origins only, such as <code>http://localhost:3000</code>.
180
+ Native apps can leave this empty.
181
+ </small>
182
+ </label>
183
+ </div>
184
+
185
+ <aside id="target-guidance" class="policy-note" aria-live="polite">
186
+ <strong id="target-guidance-title">Uses an OpenAI Platform API key</strong>
187
+ <p id="target-guidance-detail">
188
+ Your key is seeded over stdin into a private Docker volume and
189
+ is never returned to the browser. A separate local client
190
+ credential is generated for your apps.
191
+ </p>
192
+ </aside>
193
+
194
+ <div class="actions">
195
+ <a id="back-to-vps" class="button ghost">Back to VPS setup</a>
196
+ <button id="review-button" class="button primary" type="submit" disabled>
197
+ Review local plan
198
+ </button>
199
+ </div>
200
+ </form>
201
+ </section>
202
+
203
+ <section class="panel" data-step="2" aria-labelledby="review-title" hidden>
204
+ <div class="panel-heading">
205
+ <h2 id="review-title" tabindex="-1">Review the exact local plan</h2>
206
+ <p>No file or container has been changed yet.</p>
207
+ </div>
208
+
209
+ <dl class="result-list review-details">
210
+ <div>
211
+ <dt>Endpoint</dt>
212
+ <dd><code id="review-endpoint"></code></dd>
213
+ </div>
214
+ <div>
215
+ <dt>Protocol</dt>
216
+ <dd id="review-protocol"></dd>
217
+ </div>
218
+ <div>
219
+ <dt>Upstream sign-in</dt>
220
+ <dd id="review-auth"></dd>
221
+ </div>
222
+ <div>
223
+ <dt>Browser clients</dt>
224
+ <dd id="review-browser"></dd>
225
+ </div>
226
+ <div id="review-origins-row">
227
+ <dt>Allowed origins</dt>
228
+ <dd id="review-origins"></dd>
229
+ </div>
230
+ <div>
231
+ <dt>Managed files</dt>
232
+ <dd><code id="review-path"></code></dd>
233
+ </div>
234
+ </dl>
235
+
236
+ <div class="review-grid local-review-grid">
237
+ <section>
238
+ <h3>Relmio will</h3>
239
+ <ul class="check-list">
240
+ <li>Build one target-specific Docker image.</li>
241
+ <li>Bind the selected port exactly to <code>127.0.0.1</code>.</li>
242
+ <li>Generate a separate one-time client credential.</li>
243
+ <li>Keep provider credentials in private Docker volumes.</li>
244
+ </ul>
245
+ </section>
246
+ <section>
247
+ <h3>Relmio will not</h3>
248
+ <ul class="no-list">
249
+ <li>Publish the endpoint to your LAN or internet.</li>
250
+ <li>Turn ChatGPT credentials into Platform API credentials.</li>
251
+ <li>Modify or restart your n8n container.</li>
252
+ <li>Reuse the existing Hostinger deployment.</li>
253
+ </ul>
254
+ </section>
255
+ </div>
256
+
257
+ <aside id="review-policy" class="policy-note"></aside>
258
+
259
+ <div class="approval">
260
+ <label class="check-row">
261
+ <input id="install-confirm" type="checkbox" />
262
+ <span>
263
+ I reviewed this exact loopback plan and authorize Relmio to write
264
+ its managed local files and start this Docker container.
265
+ </span>
266
+ </label>
267
+ </div>
268
+
269
+ <div class="actions">
270
+ <button class="button ghost back-button" type="button" data-back="1">
271
+ Back
272
+ </button>
273
+ <button id="install-settings-button" class="button primary" type="button" disabled>
274
+ Continue to install
275
+ </button>
276
+ </div>
277
+ </section>
278
+
279
+ <section class="panel" data-step="3" aria-labelledby="install-title" hidden>
280
+ <div class="panel-heading">
281
+ <h2 id="install-title" tabindex="-1">Install the local container</h2>
282
+ <p id="install-intro">
283
+ Enter the OpenAI Platform API key that this endpoint will use
284
+ upstream. It is sent only to this local Relmio process.
285
+ </p>
286
+ </div>
287
+
288
+ <div id="api-key-field" class="field-grid single">
289
+ <label class="field">
290
+ <span>OpenAI Platform API key</span>
291
+ <input
292
+ id="platform-api-key"
293
+ name="apiKey"
294
+ type="password"
295
+ autocomplete="off"
296
+ spellcheck="false"
297
+ maxlength="512"
298
+ pattern="sk-[A-Za-z0-9_\-]{32,509}"
299
+ required
300
+ />
301
+ <small>
302
+ The browser field is cleared as soon as installation starts. The
303
+ Platform key is never displayed in the result.
304
+ </small>
305
+ </label>
306
+ </div>
307
+
308
+ <aside id="codex-install-warning" class="high-trust-warning" hidden>
309
+ <strong>High-trust capability</strong>
310
+ <p>
311
+ Anyone holding the generated client credential can control Codex
312
+ inside its isolated container, act through your signed-in ChatGPT
313
+ session, and may be able to recover that container's ChatGPT session
314
+ credential. Treat this capability like your ChatGPT password and
315
+ give it only to a trusted native local app.
316
+ </p>
317
+ </aside>
318
+
319
+ <div class="actions">
320
+ <button class="button ghost back-button" type="button" data-back="2">
321
+ Back
322
+ </button>
323
+ <button id="install-button" class="button primary" type="button">
324
+ Install on this computer
325
+ </button>
326
+ </div>
327
+ </section>
328
+
329
+ <section class="panel success-panel" data-step="4" aria-labelledby="done-title" hidden>
330
+ <div class="success-heading">
331
+ <div class="success-mark" aria-hidden="true">✓</div>
332
+ <div class="panel-heading">
333
+ <h2 id="done-title" tabindex="-1">Local endpoint is ready</h2>
334
+ <p id="done-detail">Copy the client settings into your local app.</p>
335
+ </div>
336
+ </div>
337
+
338
+ <aside class="one-time-note">
339
+ <strong>Copy this credential now</strong>
340
+ <p>
341
+ Relmio shows the generated client credential only in this install
342
+ response. It cannot recover it after you leave this page.
343
+ </p>
344
+ </aside>
345
+
346
+ <dl class="result-list">
347
+ <div>
348
+ <dt>Endpoint</dt>
349
+ <dd class="result-value">
350
+ <code id="result-endpoint"></code>
351
+ <button
352
+ class="button secondary copy-value"
353
+ type="button"
354
+ data-copy-target="result-endpoint"
355
+ data-copy-label="endpoint"
356
+ aria-label="Copy local endpoint"
357
+ >
358
+ Copy
359
+ </button>
360
+ </dd>
361
+ </div>
362
+ <div>
363
+ <dt>Client credential</dt>
364
+ <dd class="result-value">
365
+ <code id="result-credential"></code>
366
+ <button
367
+ class="button secondary copy-value"
368
+ type="button"
369
+ data-copy-target="result-credential"
370
+ data-copy-label="client credential"
371
+ aria-label="Copy client credential"
372
+ >
373
+ Copy
374
+ </button>
375
+ </dd>
376
+ </div>
377
+ </dl>
378
+
379
+ <aside id="codex-production-warning" class="high-trust-warning" hidden>
380
+ <strong>Experimental WebSocket transport</strong>
381
+ <p>
382
+ Codex App Server WebSocket is experimental and unsupported for production workloads.
383
+ </p>
384
+ </aside>
385
+
386
+ <section id="codex-login" class="codex-login" aria-labelledby="codex-login-title" hidden>
387
+ <h3 id="codex-login-title">Sign the container in to ChatGPT</h3>
388
+ <p>
389
+ Relmio starts the official Codex device-code flow. The ChatGPT
390
+ credential stays in the isolated Codex Docker volume and is not an
391
+ OpenAI Platform API key.
392
+ </p>
393
+ <button id="codex-login-button" class="button primary" type="button">
394
+ Start ChatGPT sign-in
395
+ </button>
396
+
397
+ <div id="device-code-result" class="device-code-result" hidden>
398
+ <p>
399
+ Open the official OpenAI page and enter this one-time code:
400
+ </p>
401
+ <div class="device-code-row">
402
+ <code id="device-code"></code>
403
+ <button
404
+ class="button secondary copy-value"
405
+ type="button"
406
+ data-copy-target="device-code"
407
+ data-copy-label="device code"
408
+ aria-label="Copy device code"
409
+ >
410
+ Copy
411
+ </button>
412
+ </div>
413
+ <a
414
+ id="device-code-link"
415
+ class="button secondary"
416
+ target="_blank"
417
+ rel="noopener noreferrer"
418
+ >
419
+ Open OpenAI device sign-in
420
+ </a>
421
+ <p id="device-code-status" class="device-code-status" role="status" aria-live="polite">
422
+ Waiting for sign-in…
423
+ </p>
424
+ </div>
425
+ </section>
426
+
427
+ <aside id="client-warning" class="final-note"></aside>
428
+
429
+ <div class="actions">
430
+ <a id="return-to-vps" class="button secondary">Set up the VPS version</a>
431
+ </div>
432
+ </section>
433
+ </main>
434
+
435
+ <footer>
436
+ <p>
437
+ Relmio keeps the OpenAI Platform API path and ChatGPT/Codex path
438
+ separate so each uses its intended credential and protocol.
439
+ </p>
440
+ </footer>
441
+ </body>
442
+ </html>