@fluxfiles/node 0.1.2 → 0.1.4

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 CHANGED
@@ -48,6 +48,26 @@ const token = createToken({
48
48
  });
49
49
  ```
50
50
 
51
+ ### Enable Import from URL
52
+
53
+ Import-from-URL is **off by default**. Turn it on for a token by setting the
54
+ import options — no server-side per-tenant config is needed:
55
+
56
+ ```ts
57
+ const token = createToken({
58
+ userId: 'user-42',
59
+ perms: ['read', 'write'],
60
+ allowUrlImport: true, // required — enables the feature
61
+ maxImportMb: 20, // optional — cap per import (MB)
62
+ importUrlAllowlist: ['*.unsplash.com'], // optional — restrict source hosts
63
+ // importPath, importRateLimit, importConcurrency also supported
64
+ });
65
+ ```
66
+
67
+ The core then accepts `POST /api/fm/import-url` for that token (SSRF-guarded,
68
+ sharing the quota/dedup/variants pipeline). Server-wide defaults come from
69
+ `FLUXFILES_IMPORT_*` env vars on the core service.
70
+
51
71
  ### BYOB — encrypt a user's own bucket credentials
52
72
 
53
73
  ```ts
package/dist/index.d.mts CHANGED
@@ -41,6 +41,25 @@ interface BaseTokenOptions {
41
41
  rateWrite?: number;
42
42
  /** Per-tenant image variant widths, e.g. `{ thumb: 150, medium: 768, large: 1920 }`. Omit to inherit. */
43
43
  variants?: Partial<Record<'thumb' | 'medium' | 'large', number>> | null;
44
+ /** Enable Import-from-URL for this tenant (`POST /api/fm/import-url`). Default off. */
45
+ allowUrlImport?: boolean;
46
+ /** Max size per URL import, in MB (same unit as `maxUploadMb`). `0`/omitted = inherit (50). */
47
+ maxImportMb?: number;
48
+ /** Restrict imports to these host globs, e.g. `['*.unsplash.com']`. Omit = any public host. */
49
+ importUrlAllowlist?: string[];
50
+ /** Force imports into this path, ignoring the request path. */
51
+ importPath?: string;
52
+ /** Import-specific rate limit (req/min) and max concurrent imports. `0`/omitted = inherit. */
53
+ importRateLimit?: number;
54
+ importConcurrency?: number;
55
+ /** Enable inline video/audio preview for this tenant. Omit to inherit the default (true). */
56
+ mediaPreview?: boolean;
57
+ /** Presigned media-URL TTL (seconds) — longer so a long video doesn't expire mid-play. `0`/omitted = inherit (7200). */
58
+ previewUrlTtl?: number;
59
+ /** Max file size (MB) eligible for inline preview; larger media shows a download placeholder. `0`/omitted = inherit (500). */
60
+ maxPreviewMb?: number;
61
+ /** TTL (seconds) for per-file gated-local stream tokens. `0`/omitted = inherit (3600). */
62
+ streamTokenTtl?: number;
44
63
  }
45
64
  interface CreateTokenOptions extends BaseTokenOptions {
46
65
  /** Disk names the token may access. */
package/dist/index.d.ts CHANGED
@@ -41,6 +41,25 @@ interface BaseTokenOptions {
41
41
  rateWrite?: number;
42
42
  /** Per-tenant image variant widths, e.g. `{ thumb: 150, medium: 768, large: 1920 }`. Omit to inherit. */
43
43
  variants?: Partial<Record<'thumb' | 'medium' | 'large', number>> | null;
44
+ /** Enable Import-from-URL for this tenant (`POST /api/fm/import-url`). Default off. */
45
+ allowUrlImport?: boolean;
46
+ /** Max size per URL import, in MB (same unit as `maxUploadMb`). `0`/omitted = inherit (50). */
47
+ maxImportMb?: number;
48
+ /** Restrict imports to these host globs, e.g. `['*.unsplash.com']`. Omit = any public host. */
49
+ importUrlAllowlist?: string[];
50
+ /** Force imports into this path, ignoring the request path. */
51
+ importPath?: string;
52
+ /** Import-specific rate limit (req/min) and max concurrent imports. `0`/omitted = inherit. */
53
+ importRateLimit?: number;
54
+ importConcurrency?: number;
55
+ /** Enable inline video/audio preview for this tenant. Omit to inherit the default (true). */
56
+ mediaPreview?: boolean;
57
+ /** Presigned media-URL TTL (seconds) — longer so a long video doesn't expire mid-play. `0`/omitted = inherit (7200). */
58
+ previewUrlTtl?: number;
59
+ /** Max file size (MB) eligible for inline preview; larger media shows a download placeholder. `0`/omitted = inherit (500). */
60
+ maxPreviewMb?: number;
61
+ /** TTL (seconds) for per-file gated-local stream tokens. `0`/omitted = inherit (3600). */
62
+ streamTokenTtl?: number;
44
63
  }
45
64
  interface CreateTokenOptions extends BaseTokenOptions {
46
65
  /** Disk names the token may access. */
package/dist/index.js CHANGED
@@ -142,6 +142,18 @@ function applyTenantOverrides(payload, opts) {
142
142
  if (opts.rateWrite && opts.rateWrite > 0) payload.rate_write = Math.trunc(opts.rateWrite);
143
143
  const variants = sanitizeVariants(opts.variants);
144
144
  if (variants) payload.variants = variants;
145
+ if (opts.allowUrlImport) payload.allow_url_import = true;
146
+ if (opts.maxImportMb && opts.maxImportMb > 0) payload.max_import_mb = Math.trunc(opts.maxImportMb);
147
+ if (opts.importRateLimit && opts.importRateLimit > 0) payload.import_rate_limit = Math.trunc(opts.importRateLimit);
148
+ if (opts.importConcurrency && opts.importConcurrency > 0) payload.import_concurrency = Math.trunc(opts.importConcurrency);
149
+ if (opts.importPath) payload.import_path = String(opts.importPath);
150
+ if (Array.isArray(opts.importUrlAllowlist) && opts.importUrlAllowlist.length) {
151
+ payload.import_url_allowlist = opts.importUrlAllowlist.map((h) => String(h));
152
+ }
153
+ if (opts.mediaPreview !== void 0) payload.media_preview = !!opts.mediaPreview;
154
+ if (opts.previewUrlTtl && opts.previewUrlTtl > 0) payload.preview_url_ttl = Math.trunc(opts.previewUrlTtl);
155
+ if (opts.maxPreviewMb && opts.maxPreviewMb > 0) payload.max_preview_mb = Math.trunc(opts.maxPreviewMb);
156
+ if (opts.streamTokenTtl && opts.streamTokenTtl > 0) payload.stream_token_ttl = Math.trunc(opts.streamTokenTtl);
145
157
  }
146
158
  function validateByobDisk(name, config) {
147
159
  if (!config || config.driver !== "s3") {
package/dist/index.mjs CHANGED
@@ -120,6 +120,18 @@ function applyTenantOverrides(payload, opts) {
120
120
  if (opts.rateWrite && opts.rateWrite > 0) payload.rate_write = Math.trunc(opts.rateWrite);
121
121
  const variants = sanitizeVariants(opts.variants);
122
122
  if (variants) payload.variants = variants;
123
+ if (opts.allowUrlImport) payload.allow_url_import = true;
124
+ if (opts.maxImportMb && opts.maxImportMb > 0) payload.max_import_mb = Math.trunc(opts.maxImportMb);
125
+ if (opts.importRateLimit && opts.importRateLimit > 0) payload.import_rate_limit = Math.trunc(opts.importRateLimit);
126
+ if (opts.importConcurrency && opts.importConcurrency > 0) payload.import_concurrency = Math.trunc(opts.importConcurrency);
127
+ if (opts.importPath) payload.import_path = String(opts.importPath);
128
+ if (Array.isArray(opts.importUrlAllowlist) && opts.importUrlAllowlist.length) {
129
+ payload.import_url_allowlist = opts.importUrlAllowlist.map((h) => String(h));
130
+ }
131
+ if (opts.mediaPreview !== void 0) payload.media_preview = !!opts.mediaPreview;
132
+ if (opts.previewUrlTtl && opts.previewUrlTtl > 0) payload.preview_url_ttl = Math.trunc(opts.previewUrlTtl);
133
+ if (opts.maxPreviewMb && opts.maxPreviewMb > 0) payload.max_preview_mb = Math.trunc(opts.maxPreviewMb);
134
+ if (opts.streamTokenTtl && opts.streamTokenTtl > 0) payload.stream_token_ttl = Math.trunc(opts.streamTokenTtl);
123
135
  }
124
136
  function validateByobDisk(name, config) {
125
137
  if (!config || config.driver !== "s3") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluxfiles/node",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Server-side Node/TypeScript SDK for minting FluxFiles JWTs (plain + BYOB), byte-compatible with the PHP core",
5
5
  "license": "MIT",
6
6
  "sideEffects": false,
@@ -16,7 +16,8 @@
16
16
  },
17
17
  "files": [
18
18
  "dist",
19
- "src"
19
+ "src",
20
+ "LICENSE"
20
21
  ],
21
22
  "engines": {
22
23
  "node": ">=16"
package/src/token.ts CHANGED
@@ -104,6 +104,22 @@ function applyTenantOverrides(payload: Record<string, unknown>, opts: BaseTokenO
104
104
  if (opts.rateWrite && opts.rateWrite > 0) payload.rate_write = Math.trunc(opts.rateWrite);
105
105
  const variants = sanitizeVariants(opts.variants);
106
106
  if (variants) payload.variants = variants;
107
+
108
+ // URL-import claims (the server sanitizes/clamps these on decode).
109
+ if (opts.allowUrlImport) payload.allow_url_import = true;
110
+ if (opts.maxImportMb && opts.maxImportMb > 0) payload.max_import_mb = Math.trunc(opts.maxImportMb);
111
+ if (opts.importRateLimit && opts.importRateLimit > 0) payload.import_rate_limit = Math.trunc(opts.importRateLimit);
112
+ if (opts.importConcurrency && opts.importConcurrency > 0) payload.import_concurrency = Math.trunc(opts.importConcurrency);
113
+ if (opts.importPath) payload.import_path = String(opts.importPath);
114
+ if (Array.isArray(opts.importUrlAllowlist) && opts.importUrlAllowlist.length) {
115
+ payload.import_url_allowlist = opts.importUrlAllowlist.map((h) => String(h));
116
+ }
117
+
118
+ // Media-preview claims (the server sanitizes/clamps these on decode).
119
+ if (opts.mediaPreview !== undefined) payload.media_preview = !!opts.mediaPreview;
120
+ if (opts.previewUrlTtl && opts.previewUrlTtl > 0) payload.preview_url_ttl = Math.trunc(opts.previewUrlTtl);
121
+ if (opts.maxPreviewMb && opts.maxPreviewMb > 0) payload.max_preview_mb = Math.trunc(opts.maxPreviewMb);
122
+ if (opts.streamTokenTtl && opts.streamTokenTtl > 0) payload.stream_token_ttl = Math.trunc(opts.streamTokenTtl);
107
123
  }
108
124
 
109
125
  /**
package/src/types.ts CHANGED
@@ -43,6 +43,25 @@ export interface BaseTokenOptions {
43
43
  rateWrite?: number;
44
44
  /** Per-tenant image variant widths, e.g. `{ thumb: 150, medium: 768, large: 1920 }`. Omit to inherit. */
45
45
  variants?: Partial<Record<'thumb' | 'medium' | 'large', number>> | null;
46
+ /** Enable Import-from-URL for this tenant (`POST /api/fm/import-url`). Default off. */
47
+ allowUrlImport?: boolean;
48
+ /** Max size per URL import, in MB (same unit as `maxUploadMb`). `0`/omitted = inherit (50). */
49
+ maxImportMb?: number;
50
+ /** Restrict imports to these host globs, e.g. `['*.unsplash.com']`. Omit = any public host. */
51
+ importUrlAllowlist?: string[];
52
+ /** Force imports into this path, ignoring the request path. */
53
+ importPath?: string;
54
+ /** Import-specific rate limit (req/min) and max concurrent imports. `0`/omitted = inherit. */
55
+ importRateLimit?: number;
56
+ importConcurrency?: number;
57
+ /** Enable inline video/audio preview for this tenant. Omit to inherit the default (true). */
58
+ mediaPreview?: boolean;
59
+ /** Presigned media-URL TTL (seconds) — longer so a long video doesn't expire mid-play. `0`/omitted = inherit (7200). */
60
+ previewUrlTtl?: number;
61
+ /** Max file size (MB) eligible for inline preview; larger media shows a download placeholder. `0`/omitted = inherit (500). */
62
+ maxPreviewMb?: number;
63
+ /** TTL (seconds) for per-file gated-local stream tokens. `0`/omitted = inherit (3600). */
64
+ streamTokenTtl?: number;
46
65
  }
47
66
 
48
67
  export interface CreateTokenOptions extends BaseTokenOptions {