@fluxfiles/node 0.1.16 → 0.1.18
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 +22 -0
- package/dist/index.d.mts +19 -7
- package/dist/index.d.ts +19 -7
- package/dist/index.js +5 -1
- package/dist/index.mjs +5 -1
- package/package.json +1 -1
- package/src/token.ts +9 -1
- package/src/types.ts +19 -7
package/README.md
CHANGED
|
@@ -68,6 +68,28 @@ The core then accepts `POST /api/fm/import-url` for that token (SSRF-guarded,
|
|
|
68
68
|
sharing the quota/dedup/variants pipeline). Server-wide defaults come from
|
|
69
69
|
`FLUXFILES_IMPORT_*` env vars on the core service.
|
|
70
70
|
|
|
71
|
+
### SFTP disk: chmod & SSH terminal
|
|
72
|
+
|
|
73
|
+
When the token targets a FluxFiles server that has an **SFTP disk** configured
|
|
74
|
+
(`SFTP_*` env on that server — see the
|
|
75
|
+
[core README](https://github.com/thai-pc/fluxfiles#sftp-disk-vps--shared-hosting)),
|
|
76
|
+
you can hand a token the SFTP file-manager tools. `chmod` is on by default for SFTP;
|
|
77
|
+
the **SSH terminal** is opt-in (it grants shell access as the SSH user):
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
const token = createToken({
|
|
81
|
+
userId: 'admin-7',
|
|
82
|
+
perms: ['read', 'write'],
|
|
83
|
+
disks: ['sftp'], // an SFTP disk configured on the FluxFiles server
|
|
84
|
+
allowChmod: true, // cPanel-style permissions (default on for SFTP)
|
|
85
|
+
allowTerminal: true, // SSH terminal — opt-in, off by default
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
These are **standalone-core** features: `@fluxfiles/node` mints for a real
|
|
90
|
+
FluxFiles server (Docker / standalone), which serves them — they aren't available
|
|
91
|
+
behind the WordPress / Laravel-proxy adapters.
|
|
92
|
+
|
|
71
93
|
### BYOB — encrypt a user's own bucket credentials
|
|
72
94
|
|
|
73
95
|
```ts
|
package/dist/index.d.mts
CHANGED
|
@@ -96,17 +96,24 @@ interface BaseTokenOptions {
|
|
|
96
96
|
/** Allow editing a file's text content (GET/PUT /api/fm/content). Default **false** — editing
|
|
97
97
|
* config/executable files (wp-config.php, .env, nginx.conf, deploy.sh) is powerful, so it's opt-in. */
|
|
98
98
|
allowCodeEdit?: boolean;
|
|
99
|
-
/** Allow the
|
|
100
|
-
*
|
|
99
|
+
/** Allow the SSH terminal (POST /api/fm/terminal) on an SFTP disk. Default **false** — grants shell
|
|
100
|
+
* access as the SSH user, so it's opt-in. Core-standalone: the token must target a real core
|
|
101
|
+
* (this SDK does), not a proxy adapter that doesn't serve /api/fm/terminal. */
|
|
102
|
+
allowTerminal?: boolean;
|
|
103
|
+
/** Optional self-hosted PTY terminal URL (ttyd / gotty / wetty, or any PTY-over-WebSocket
|
|
104
|
+
* server the operator runs). When set (and `allowTerminal` is true), the UI embeds it for a
|
|
105
|
+
* true interactive terminal instead of the built-in command-runner. Free; must be http(s).
|
|
106
|
+
* Core-standalone only (like `allowTerminal`). */
|
|
107
|
+
terminalPtyUrl?: string;
|
|
108
|
+
/** Allow the Optimization feature (POST /api/fm/optimize) — recompress images to WebP +
|
|
109
|
+
* compress PDFs. **Free/core**; default **false** because it replaces/deletes originals, so
|
|
110
|
+
* it's an opt-in capability. */
|
|
101
111
|
allowOptimize?: boolean;
|
|
102
|
-
/** Auto-optimize images on upload (recompress to WebP in the pipeline). Default false
|
|
103
|
-
*
|
|
112
|
+
/** Auto-optimize images on upload (recompress to WebP in the pipeline). Default false.
|
|
113
|
+
* Free/core. */
|
|
104
114
|
autoOptimize?: boolean;
|
|
105
115
|
/** WebP quality for optimization, 40–95. `0`/omitted = inherit the server default (82). */
|
|
106
116
|
optimizeQuality?: number;
|
|
107
|
-
/** Target format for optimization: `'webp'` (default) or `'avif'` (falls back to
|
|
108
|
-
* WebP when the server build lacks AVIF). */
|
|
109
|
-
optimizeFormat?: 'webp' | 'avif';
|
|
110
117
|
/** Keep the original file when optimizing (default false = replace in place). */
|
|
111
118
|
optimizeKeepOriginal?: boolean;
|
|
112
119
|
/** Skip optimizing a file larger than this many MB (0/omitted = no limit). */
|
|
@@ -167,6 +174,11 @@ interface BaseTokenOptions {
|
|
|
167
174
|
usageTopFoldersCount?: number;
|
|
168
175
|
/** Folder grouping depth for the usage breakdown. `0`/omitted = inherit (1). */
|
|
169
176
|
usageFolderDepth?: number;
|
|
177
|
+
/** Generic escape hatch: any JWT claim by its raw snake_case name (e.g.
|
|
178
|
+
* `{ allow_terminal: true, terminal_pty_url: '…', upload_collision: 'overwrite' }`).
|
|
179
|
+
* Merged last so explicit claims win; the server sanitizes on decode. The single
|
|
180
|
+
* place to set claims that don't have a typed option here. See docs/CONFIG.md. */
|
|
181
|
+
claims?: Record<string, unknown>;
|
|
170
182
|
}
|
|
171
183
|
interface CreateTokenOptions extends BaseTokenOptions {
|
|
172
184
|
/** Disk names the token may access. */
|
package/dist/index.d.ts
CHANGED
|
@@ -96,17 +96,24 @@ interface BaseTokenOptions {
|
|
|
96
96
|
/** Allow editing a file's text content (GET/PUT /api/fm/content). Default **false** — editing
|
|
97
97
|
* config/executable files (wp-config.php, .env, nginx.conf, deploy.sh) is powerful, so it's opt-in. */
|
|
98
98
|
allowCodeEdit?: boolean;
|
|
99
|
-
/** Allow the
|
|
100
|
-
*
|
|
99
|
+
/** Allow the SSH terminal (POST /api/fm/terminal) on an SFTP disk. Default **false** — grants shell
|
|
100
|
+
* access as the SSH user, so it's opt-in. Core-standalone: the token must target a real core
|
|
101
|
+
* (this SDK does), not a proxy adapter that doesn't serve /api/fm/terminal. */
|
|
102
|
+
allowTerminal?: boolean;
|
|
103
|
+
/** Optional self-hosted PTY terminal URL (ttyd / gotty / wetty, or any PTY-over-WebSocket
|
|
104
|
+
* server the operator runs). When set (and `allowTerminal` is true), the UI embeds it for a
|
|
105
|
+
* true interactive terminal instead of the built-in command-runner. Free; must be http(s).
|
|
106
|
+
* Core-standalone only (like `allowTerminal`). */
|
|
107
|
+
terminalPtyUrl?: string;
|
|
108
|
+
/** Allow the Optimization feature (POST /api/fm/optimize) — recompress images to WebP +
|
|
109
|
+
* compress PDFs. **Free/core**; default **false** because it replaces/deletes originals, so
|
|
110
|
+
* it's an opt-in capability. */
|
|
101
111
|
allowOptimize?: boolean;
|
|
102
|
-
/** Auto-optimize images on upload (recompress to WebP in the pipeline). Default false
|
|
103
|
-
*
|
|
112
|
+
/** Auto-optimize images on upload (recompress to WebP in the pipeline). Default false.
|
|
113
|
+
* Free/core. */
|
|
104
114
|
autoOptimize?: boolean;
|
|
105
115
|
/** WebP quality for optimization, 40–95. `0`/omitted = inherit the server default (82). */
|
|
106
116
|
optimizeQuality?: number;
|
|
107
|
-
/** Target format for optimization: `'webp'` (default) or `'avif'` (falls back to
|
|
108
|
-
* WebP when the server build lacks AVIF). */
|
|
109
|
-
optimizeFormat?: 'webp' | 'avif';
|
|
110
117
|
/** Keep the original file when optimizing (default false = replace in place). */
|
|
111
118
|
optimizeKeepOriginal?: boolean;
|
|
112
119
|
/** Skip optimizing a file larger than this many MB (0/omitted = no limit). */
|
|
@@ -167,6 +174,11 @@ interface BaseTokenOptions {
|
|
|
167
174
|
usageTopFoldersCount?: number;
|
|
168
175
|
/** Folder grouping depth for the usage breakdown. `0`/omitted = inherit (1). */
|
|
169
176
|
usageFolderDepth?: number;
|
|
177
|
+
/** Generic escape hatch: any JWT claim by its raw snake_case name (e.g.
|
|
178
|
+
* `{ allow_terminal: true, terminal_pty_url: '…', upload_collision: 'overwrite' }`).
|
|
179
|
+
* Merged last so explicit claims win; the server sanitizes on decode. The single
|
|
180
|
+
* place to set claims that don't have a typed option here. See docs/CONFIG.md. */
|
|
181
|
+
claims?: Record<string, unknown>;
|
|
170
182
|
}
|
|
171
183
|
interface CreateTokenOptions extends BaseTokenOptions {
|
|
172
184
|
/** Disk names the token may access. */
|
package/dist/index.js
CHANGED
|
@@ -171,6 +171,8 @@ function applyTenantOverrides(payload, opts) {
|
|
|
171
171
|
if (opts.allowDownload !== void 0) payload.allow_download = !!opts.allowDownload;
|
|
172
172
|
if (opts.allowChmod !== void 0) payload.allow_chmod = !!opts.allowChmod;
|
|
173
173
|
if (opts.allowCodeEdit !== void 0) payload.allow_code_edit = !!opts.allowCodeEdit;
|
|
174
|
+
if (opts.allowTerminal !== void 0) payload.allow_terminal = !!opts.allowTerminal;
|
|
175
|
+
if (opts.terminalPtyUrl) payload.terminal_pty_url = String(opts.terminalPtyUrl);
|
|
174
176
|
if (opts.allowOptimize !== void 0) payload.allow_optimize = !!opts.allowOptimize;
|
|
175
177
|
if (opts.allowShare !== void 0) payload.allow_share = !!opts.allowShare;
|
|
176
178
|
if (opts.allowAiVision !== void 0) payload.allow_ai_vision = !!opts.allowAiVision;
|
|
@@ -180,7 +182,6 @@ function applyTenantOverrides(payload, opts) {
|
|
|
180
182
|
if (opts.allowC2pa !== void 0) payload.allow_c2pa = !!opts.allowC2pa;
|
|
181
183
|
if (opts.autoOptimize !== void 0) payload.auto_optimize = !!opts.autoOptimize;
|
|
182
184
|
if (opts.optimizeQuality && opts.optimizeQuality > 0) payload.optimize_quality = Math.trunc(opts.optimizeQuality);
|
|
183
|
-
if (opts.optimizeFormat === "avif") payload.optimize_format = "avif";
|
|
184
185
|
if (opts.optimizeKeepOriginal !== void 0) payload.optimize_keep_original = !!opts.optimizeKeepOriginal;
|
|
185
186
|
if (opts.optimizeMaxMb && opts.optimizeMaxMb > 0) payload.optimize_max_mb = Math.trunc(opts.optimizeMaxMb);
|
|
186
187
|
if (opts.pdfLevel && ["screen", "ebook", "printer", "prepress", "default"].includes(opts.pdfLevel)) {
|
|
@@ -209,6 +210,9 @@ function applyTenantOverrides(payload, opts) {
|
|
|
209
210
|
if (opts.usageCriticalThreshold && opts.usageCriticalThreshold > 0) payload.usage_critical_threshold = Math.trunc(opts.usageCriticalThreshold);
|
|
210
211
|
if (opts.usageTopFoldersCount && opts.usageTopFoldersCount > 0) payload.usage_top_folders_count = Math.trunc(opts.usageTopFoldersCount);
|
|
211
212
|
if (opts.usageFolderDepth && opts.usageFolderDepth > 0) payload.usage_folder_depth = Math.trunc(opts.usageFolderDepth);
|
|
213
|
+
if (opts.claims) {
|
|
214
|
+
for (const [k, v] of Object.entries(opts.claims)) if (v !== void 0 && v !== null) payload[k] = v;
|
|
215
|
+
}
|
|
212
216
|
}
|
|
213
217
|
function validateByobDisk(name, config) {
|
|
214
218
|
if (!config || config.driver !== "s3" && config.driver !== "sftp") {
|
package/dist/index.mjs
CHANGED
|
@@ -149,6 +149,8 @@ function applyTenantOverrides(payload, opts) {
|
|
|
149
149
|
if (opts.allowDownload !== void 0) payload.allow_download = !!opts.allowDownload;
|
|
150
150
|
if (opts.allowChmod !== void 0) payload.allow_chmod = !!opts.allowChmod;
|
|
151
151
|
if (opts.allowCodeEdit !== void 0) payload.allow_code_edit = !!opts.allowCodeEdit;
|
|
152
|
+
if (opts.allowTerminal !== void 0) payload.allow_terminal = !!opts.allowTerminal;
|
|
153
|
+
if (opts.terminalPtyUrl) payload.terminal_pty_url = String(opts.terminalPtyUrl);
|
|
152
154
|
if (opts.allowOptimize !== void 0) payload.allow_optimize = !!opts.allowOptimize;
|
|
153
155
|
if (opts.allowShare !== void 0) payload.allow_share = !!opts.allowShare;
|
|
154
156
|
if (opts.allowAiVision !== void 0) payload.allow_ai_vision = !!opts.allowAiVision;
|
|
@@ -158,7 +160,6 @@ function applyTenantOverrides(payload, opts) {
|
|
|
158
160
|
if (opts.allowC2pa !== void 0) payload.allow_c2pa = !!opts.allowC2pa;
|
|
159
161
|
if (opts.autoOptimize !== void 0) payload.auto_optimize = !!opts.autoOptimize;
|
|
160
162
|
if (opts.optimizeQuality && opts.optimizeQuality > 0) payload.optimize_quality = Math.trunc(opts.optimizeQuality);
|
|
161
|
-
if (opts.optimizeFormat === "avif") payload.optimize_format = "avif";
|
|
162
163
|
if (opts.optimizeKeepOriginal !== void 0) payload.optimize_keep_original = !!opts.optimizeKeepOriginal;
|
|
163
164
|
if (opts.optimizeMaxMb && opts.optimizeMaxMb > 0) payload.optimize_max_mb = Math.trunc(opts.optimizeMaxMb);
|
|
164
165
|
if (opts.pdfLevel && ["screen", "ebook", "printer", "prepress", "default"].includes(opts.pdfLevel)) {
|
|
@@ -187,6 +188,9 @@ function applyTenantOverrides(payload, opts) {
|
|
|
187
188
|
if (opts.usageCriticalThreshold && opts.usageCriticalThreshold > 0) payload.usage_critical_threshold = Math.trunc(opts.usageCriticalThreshold);
|
|
188
189
|
if (opts.usageTopFoldersCount && opts.usageTopFoldersCount > 0) payload.usage_top_folders_count = Math.trunc(opts.usageTopFoldersCount);
|
|
189
190
|
if (opts.usageFolderDepth && opts.usageFolderDepth > 0) payload.usage_folder_depth = Math.trunc(opts.usageFolderDepth);
|
|
191
|
+
if (opts.claims) {
|
|
192
|
+
for (const [k, v] of Object.entries(opts.claims)) if (v !== void 0 && v !== null) payload[k] = v;
|
|
193
|
+
}
|
|
190
194
|
}
|
|
191
195
|
function validateByobDisk(name, config) {
|
|
192
196
|
if (!config || config.driver !== "s3" && config.driver !== "sftp") {
|
package/package.json
CHANGED
package/src/token.ts
CHANGED
|
@@ -141,6 +141,10 @@ function applyTenantOverrides(payload: Record<string, unknown>, opts: BaseTokenO
|
|
|
141
141
|
if (opts.allowDownload !== undefined) payload.allow_download = !!opts.allowDownload;
|
|
142
142
|
if (opts.allowChmod !== undefined) payload.allow_chmod = !!opts.allowChmod;
|
|
143
143
|
if (opts.allowCodeEdit !== undefined) payload.allow_code_edit = !!opts.allowCodeEdit;
|
|
144
|
+
// SSH terminal (SFTP disks). Core-standalone — the token must target a real core
|
|
145
|
+
// (Node mints for one), not a proxy adapter that doesn't serve /api/fm/terminal.
|
|
146
|
+
if (opts.allowTerminal !== undefined) payload.allow_terminal = !!opts.allowTerminal;
|
|
147
|
+
if (opts.terminalPtyUrl) payload.terminal_pty_url = String(opts.terminalPtyUrl);
|
|
144
148
|
if (opts.allowOptimize !== undefined) payload.allow_optimize = !!opts.allowOptimize;
|
|
145
149
|
// Other paid-module claims (inert unless the module is installed + licensed).
|
|
146
150
|
if (opts.allowShare !== undefined) payload.allow_share = !!opts.allowShare;
|
|
@@ -151,7 +155,6 @@ function applyTenantOverrides(payload: Record<string, unknown>, opts: BaseTokenO
|
|
|
151
155
|
if (opts.allowC2pa !== undefined) payload.allow_c2pa = !!opts.allowC2pa;
|
|
152
156
|
if (opts.autoOptimize !== undefined) payload.auto_optimize = !!opts.autoOptimize;
|
|
153
157
|
if (opts.optimizeQuality && opts.optimizeQuality > 0) payload.optimize_quality = Math.trunc(opts.optimizeQuality);
|
|
154
|
-
if (opts.optimizeFormat === 'avif') payload.optimize_format = 'avif';
|
|
155
158
|
if (opts.optimizeKeepOriginal !== undefined) payload.optimize_keep_original = !!opts.optimizeKeepOriginal;
|
|
156
159
|
if (opts.optimizeMaxMb && opts.optimizeMaxMb > 0) payload.optimize_max_mb = Math.trunc(opts.optimizeMaxMb);
|
|
157
160
|
if (opts.pdfLevel && ['screen', 'ebook', 'printer', 'prepress', 'default'].includes(opts.pdfLevel)) {
|
|
@@ -182,6 +185,11 @@ function applyTenantOverrides(payload: Record<string, unknown>, opts: BaseTokenO
|
|
|
182
185
|
if (opts.usageCriticalThreshold && opts.usageCriticalThreshold > 0) payload.usage_critical_threshold = Math.trunc(opts.usageCriticalThreshold);
|
|
183
186
|
if (opts.usageTopFoldersCount && opts.usageTopFoldersCount > 0) payload.usage_top_folders_count = Math.trunc(opts.usageTopFoldersCount);
|
|
184
187
|
if (opts.usageFolderDepth && opts.usageFolderDepth > 0) payload.usage_folder_depth = Math.trunc(opts.usageFolderDepth);
|
|
188
|
+
|
|
189
|
+
// Generic escape hatch: ANY claim by its raw (snake_case) name. Merged last so an
|
|
190
|
+
// explicit claim wins over a preset/group default. The server sanitizes on decode.
|
|
191
|
+
// See docs/CONFIG.md for the full claim list.
|
|
192
|
+
if (opts.claims) for (const [k, v] of Object.entries(opts.claims)) if (v !== undefined && v !== null) payload[k] = v;
|
|
185
193
|
}
|
|
186
194
|
|
|
187
195
|
/**
|
package/src/types.ts
CHANGED
|
@@ -100,17 +100,24 @@ export interface BaseTokenOptions {
|
|
|
100
100
|
/** Allow editing a file's text content (GET/PUT /api/fm/content). Default **false** — editing
|
|
101
101
|
* config/executable files (wp-config.php, .env, nginx.conf, deploy.sh) is powerful, so it's opt-in. */
|
|
102
102
|
allowCodeEdit?: boolean;
|
|
103
|
-
/** Allow the
|
|
104
|
-
*
|
|
103
|
+
/** Allow the SSH terminal (POST /api/fm/terminal) on an SFTP disk. Default **false** — grants shell
|
|
104
|
+
* access as the SSH user, so it's opt-in. Core-standalone: the token must target a real core
|
|
105
|
+
* (this SDK does), not a proxy adapter that doesn't serve /api/fm/terminal. */
|
|
106
|
+
allowTerminal?: boolean;
|
|
107
|
+
/** Optional self-hosted PTY terminal URL (ttyd / gotty / wetty, or any PTY-over-WebSocket
|
|
108
|
+
* server the operator runs). When set (and `allowTerminal` is true), the UI embeds it for a
|
|
109
|
+
* true interactive terminal instead of the built-in command-runner. Free; must be http(s).
|
|
110
|
+
* Core-standalone only (like `allowTerminal`). */
|
|
111
|
+
terminalPtyUrl?: string;
|
|
112
|
+
/** Allow the Optimization feature (POST /api/fm/optimize) — recompress images to WebP +
|
|
113
|
+
* compress PDFs. **Free/core**; default **false** because it replaces/deletes originals, so
|
|
114
|
+
* it's an opt-in capability. */
|
|
105
115
|
allowOptimize?: boolean;
|
|
106
|
-
/** Auto-optimize images on upload (recompress to WebP in the pipeline). Default false
|
|
107
|
-
*
|
|
116
|
+
/** Auto-optimize images on upload (recompress to WebP in the pipeline). Default false.
|
|
117
|
+
* Free/core. */
|
|
108
118
|
autoOptimize?: boolean;
|
|
109
119
|
/** WebP quality for optimization, 40–95. `0`/omitted = inherit the server default (82). */
|
|
110
120
|
optimizeQuality?: number;
|
|
111
|
-
/** Target format for optimization: `'webp'` (default) or `'avif'` (falls back to
|
|
112
|
-
* WebP when the server build lacks AVIF). */
|
|
113
|
-
optimizeFormat?: 'webp' | 'avif';
|
|
114
121
|
/** Keep the original file when optimizing (default false = replace in place). */
|
|
115
122
|
optimizeKeepOriginal?: boolean;
|
|
116
123
|
/** Skip optimizing a file larger than this many MB (0/omitted = no limit). */
|
|
@@ -171,6 +178,11 @@ export interface BaseTokenOptions {
|
|
|
171
178
|
usageTopFoldersCount?: number;
|
|
172
179
|
/** Folder grouping depth for the usage breakdown. `0`/omitted = inherit (1). */
|
|
173
180
|
usageFolderDepth?: number;
|
|
181
|
+
/** Generic escape hatch: any JWT claim by its raw snake_case name (e.g.
|
|
182
|
+
* `{ allow_terminal: true, terminal_pty_url: '…', upload_collision: 'overwrite' }`).
|
|
183
|
+
* Merged last so explicit claims win; the server sanitizes on decode. The single
|
|
184
|
+
* place to set claims that don't have a typed option here. See docs/CONFIG.md. */
|
|
185
|
+
claims?: Record<string, unknown>;
|
|
174
186
|
}
|
|
175
187
|
|
|
176
188
|
export interface CreateTokenOptions extends BaseTokenOptions {
|