api2convert 10.3.1 → 10.3.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 050c52e2ed3addf46de0b0008d0a233c49001ff7b65e437a73288687b48b2142
4
- data.tar.gz: 0dc7d74ea29cd2f98c618f31ef177766aaeeb3590ca2acc3df569201f1270602
3
+ metadata.gz: ada5e8eb2a1a367508025bfec543c9a730126291aa80ccff236f26a50947a2f5
4
+ data.tar.gz: b58f2ae36378bc937debe2f781576931a392ec18f47b80143fb1a07673075d0d
5
5
  SHA512:
6
- metadata.gz: f6b0bcd3554022246ae7b99d8c52a65d6f8d122772ec397865592437470c35ff92663baebc8957c4227c4bee85ffdcae23829abc05822aa023dcf71abe81819b
7
- data.tar.gz: c440475c94830650a2f9d81ef1a0573fafa05892cbea86c83812ade8528714ec812fb9441b8b7cb7f423a58b7e337b3e9b1639d365609d42cb7885d2e9ad4101
6
+ metadata.gz: efa67a69ac2e792e450a4f82dcccab941fd222dcb0c5014490b483fc7ec4bd845e1d3f4302f551f17bf67fbab2f4ef1cf79e30784df449bef93350657a3ddc39
7
+ data.tar.gz: 5d8a30b8597043b8b79489efa38866dbb3ce5d1da28659bb63a54b4136a40136f8bac7b3b8ded35f9c30f736ba463929bf1ff615b1f9cdaeb3388f329cc298d2
data/README.md CHANGED
@@ -112,7 +112,7 @@ client.convert("report.docx", "pdf", output_targets: [target])
112
112
  # Delivered to the bucket — the job completes with no local output to save.
113
113
  ```
114
114
 
115
- `azure`, `ftp` and `google_cloud` have matching input factories; output uses the
115
+ `azure` and `google_cloud` have matching input factories; output uses the
116
116
  generic `OutputTarget` for every provider. Credentials are redacted in
117
117
  `inspect`/errors and never printed.
118
118
 
data/docs/CHANGELOG.md CHANGED
@@ -4,6 +4,42 @@ All notable changes to the API2Convert Ruby SDK are documented here. The five
4
4
  official SDKs (PHP, Python, Java, Node.js, Ruby) version together against the
5
5
  shared [`SDK_CONTRACT.md`](SDK_CONTRACT.md).
6
6
 
7
+ ## [10.3.3] - 2026-11-06
8
+
9
+ ### Removed
10
+
11
+ - The FTP cloud provider, because FTP is being retired from the API: `CloudInput.ftp` and
12
+ `CloudProvider::FTP`. Code that uses them raises `NoMethodError` or `NameError` and needs another
13
+ provider. Reading stays tolerant: jobs created with `ftp` earlier still load.
14
+
15
+ ## [10.3.2] - 2026-08-12
16
+
17
+ ### Fixed
18
+
19
+ - Replaced the trailing-separator regex trims (`%r{/+\z}`) in `config.rb`, `result.rb` and
20
+ `file_uploader.rb` with a linear reverse scan (`Support::Strings.trim_trailing`). CodeQL
21
+ flagged the patterns as polynomial ReDoS: a string ending in a long run of separators cost
22
+ O(n²), and `job.server` comes from the API while `base_url` comes from caller config.
23
+ Identical semantics, linear time.
24
+
25
+ ## [10.3.1] - 2026-07-12
26
+
27
+ - Ships the cloud-storage examples added to the README (READMEs are included in the published
28
+ gem). No functional or API change from 10.3.0.
29
+
30
+ ## [10.3.0] - 2026-07-12
31
+
32
+ ### Added
33
+
34
+ - Cloud-storage connectors: typed `CloudInput` + `OutputTarget` (SDK contract D-5).
35
+ - On-brand `x-api2convert-*` request headers.
36
+
37
+ ### Fixed
38
+
39
+ - Bounded the control-plane response-body read; atomic save, download error typing and numeric
40
+ overflow safety (Track B robustness); a 3xx on the authenticated JSON path now raises a typed
41
+ error instead of returning an empty model.
42
+
7
43
  ## [10.2.1] - 2026-07-08
8
44
 
9
45
  - Lock-step version bump to keep all API2Convert SDKs on 10.2.1. No library changes since 10.2.0
data/docs/SDK_CONTRACT.md CHANGED
@@ -29,13 +29,13 @@ Two layers make up an SDK:
29
29
  - **Add remote input**: `POST /jobs/{id}/input` `{ type:'remote', source:'https://…' }`.
30
30
  - **Cloud input** (import from customer storage): `POST /jobs/{id}/input` (or inline in `create`)
31
31
  `{ type:'cloud', source:<provider>, parameters:{…}, credentials:{…} }`, `<provider> ∈ {amazons3,
32
- azure, ftp, googlecloud}`; plus `{ type:'gdrive_picker', source:<drive-file-id>,
32
+ azure, googlecloud}`; plus `{ type:'gdrive_picker', source:<drive-file-id>,
33
33
  credentials:{token}, content_type? }` for Google Drive. The API validates a cloud descriptor
34
34
  **asynchronously** — it accepts any descriptor on create (`201`) and later fails a bad one on the
35
35
  input (`status:failed`, generic `code 99`); it never echoes a credential value.
36
36
  - **Cloud output** (deliver to customer storage): a `conversion[]` may carry
37
37
  `output_target:[{ type:<provider>, parameters:{…}, credentials:{…} }]`, `<provider> ∈ {amazons3,
38
- googlecloud, azure, ftp, youtube, gdrive}`. `status` (`waiting|uploading|completed|failed`) is
38
+ googlecloud, azure, youtube, gdrive}`. `status` (`waiting|uploading|completed|failed`) is
39
39
  server-set and read-only — never sent on create. The job reaches `completed` only after the upload
40
40
  succeeds (a failed upload → `failed`); an output-target conversion produces **no** local output.
41
41
  - **Start**: `PATCH /jobs/{id}` `{ process:true }`.
@@ -102,14 +102,14 @@ wire descriptors above; per-provider keys are **not** validated synchronously se
102
102
  typed surface is the client's only pre-flight structure.
103
103
 
104
104
  - **Provider vocabulary** — one shared `CloudProvider` concept (per-language spelling): `amazons3,
105
- azure, ftp, gdrive, googlecloud, youtube`. It is **build-side vocabulary only** — read models keep
105
+ azure, gdrive, googlecloud, youtube`. It is **build-side vocabulary only** — read models keep
106
106
  `source`/`type`/`status` as raw strings, and an unknown provider from the server round-trips
107
107
  untyped (never throws).
108
108
  - **Cloud input** — a `CloudInput` builder emits `{ type:cloud, source, parameters, credentials }`
109
109
  and hands off to `addInput` / the create path. It ships per-provider named constructors whose
110
110
  signatures carry each provider's required keys **verbatim** (flat/lowercase, as the API expects):
111
111
  `amazonS3(bucket, file, accesskeyid, secretaccesskey)`,
112
- `azure(container, file, accountname, accountkey)`, `ftp(host, file, username, password)`,
112
+ `azure(container, file, accountname, accountkey)`,
113
113
  `googleCloud(projectid, bucket, file, keyfile)`. The required keys are **constructor arguments**,
114
114
  not a runtime gate — the builder never rejects a descriptor the permissive server would accept, and
115
115
  a generic `parameters`/`credentials` map stays reachable for optional/forward-compat keys. Google
@@ -12,18 +12,17 @@ module Api2Convert
12
12
  # there is deliberately no strict parse.
13
13
  #
14
14
  # Import support (a {Model::CloudInput} factory) exists for {AMAZON_S3},
15
- # {AZURE}, {FTP} and {GOOGLE_CLOUD}. {GDRIVE} and {YOUTUBE} are **output-only**
15
+ # {AZURE} and {GOOGLE_CLOUD}. {GDRIVE} and {YOUTUBE} are **output-only**
16
16
  # (they validate as an output `type` but have no downloader); Google Drive
17
17
  # *input* uses the separate `gdrive_picker` input type.
18
18
  module CloudProvider
19
19
  AMAZON_S3 = "amazons3"
20
20
  AZURE = "azure"
21
- FTP = "ftp"
22
21
  GDRIVE = "gdrive"
23
22
  GOOGLE_CLOUD = "googlecloud"
24
23
  YOUTUBE = "youtube"
25
24
 
26
25
  # The full provider vocabulary, in canonical order.
27
- ALL = [AMAZON_S3, AZURE, FTP, GDRIVE, GOOGLE_CLOUD, YOUTUBE].freeze
26
+ ALL = [AMAZON_S3, AZURE, GDRIVE, GOOGLE_CLOUD, YOUTUBE].freeze
28
27
  end
29
28
  end
@@ -41,7 +41,7 @@ module Api2Convert
41
41
 
42
42
  new(
43
43
  api_key: api_key,
44
- base_url: (base_url.nil? ? DEFAULT_BASE_URL : base_url).sub(%r{/+\z}, ""),
44
+ base_url: Support::Strings.trim_trailing(base_url.nil? ? DEFAULT_BASE_URL : base_url, "/"),
45
45
  timeout: [1, (timeout.nil? ? 30 : timeout).to_i].max,
46
46
  max_retries: [0, (max_retries.nil? ? 2 : max_retries).to_i].max,
47
47
  poll_interval: interval,
@@ -63,15 +63,6 @@ module Api2Convert
63
63
  )
64
64
  end
65
65
 
66
- # Import from an FTP server.
67
- def self.ftp(host:, file:, username:, password:, parameters: {}, credentials: {})
68
- new(
69
- source: CloudProvider::FTP,
70
- parameters: { "host" => host, "file" => file }.merge(parameters),
71
- credentials: { "username" => username, "password" => password }.merge(credentials)
72
- )
73
- end
74
-
75
66
  # Import from Google Cloud Storage.
76
67
  def self.google_cloud(projectid:, bucket:, file:, keyfile:, parameters: {}, credentials: {})
77
68
  new(
@@ -128,7 +128,7 @@ module Api2Convert
128
128
  path_or_dir.end_with?(File::SEPARATOR)
129
129
  if looks_like_dir
130
130
  name = safe_name(@output.filename) || safe_name(@output.id) || "output"
131
- return File.join(path_or_dir.sub(%r{[/\\]+\z}, ""), name)
131
+ return File.join(Support::Strings.trim_trailing(path_or_dir, "/\\"), name)
132
132
  end
133
133
  path_or_dir
134
134
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Api2Convert
4
+ module Support
5
+ # Small string helpers shared across the SDK. Internal, not part of the public API.
6
+ module Strings
7
+ module_function
8
+
9
+ # Strip every trailing character contained in +chars+ from +value+.
10
+ #
11
+ # Deliberately a scan rather than a regex: %r{/+\z} and friends backtrack, so a
12
+ # string ending in a long run of separators costs O(n^2) to match (CodeQL's
13
+ # +rb/polynomial-redos+). +job.server+ arrives from the API and +base_url+ from
14
+ # caller config, so neither is worth a quadratic path. This is a single reverse
15
+ # scan — O(n), no backtracking, identical result.
16
+ def trim_trailing(value, chars)
17
+ last = value.length
18
+ last -= 1 while last.positive? && chars.include?(value[last - 1])
19
+ last == value.length ? value : value[0, last]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -29,7 +29,7 @@ module Api2Convert
29
29
 
30
30
  io, resolved_name, opened = resolve(file, filename)
31
31
  seekable = io.respond_to?(:rewind)
32
- url = "#{job.server.sub(%r{/+\z}, "")}/upload-file/#{job.id}"
32
+ url = "#{Support::Strings.trim_trailing(job.server, "/")}/upload-file/#{job.id}"
33
33
  token = job.token
34
34
  boundary = "----Api2Convert#{SecureRandom.hex(16)}"
35
35
 
@@ -4,5 +4,5 @@ module Api2Convert
4
4
  # The SDK version. Kept in lock-step with the sibling SDKs (PHP, Python, Java,
5
5
  # Node.js): all official ports implement the same `docs/SDK_CONTRACT.md` and
6
6
  # version together.
7
- VERSION = "10.3.1"
7
+ VERSION = "10.3.3"
8
8
  end
data/lib/api2convert.rb CHANGED
@@ -20,6 +20,7 @@ require_relative "api2convert/version"
20
20
  require_relative "api2convert/errors"
21
21
  require_relative "api2convert/config"
22
22
  require_relative "api2convert/support/data"
23
+ require_relative "api2convert/support/strings"
23
24
  require_relative "api2convert/support/secret"
24
25
  require_relative "api2convert/support/redactor"
25
26
  require_relative "api2convert/job_status"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api2convert
3
3
  version: !ruby/object:Gem::Version
4
- version: 10.3.1
4
+ version: 10.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Qaamgo Media GmbH
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-07-12 00:00:00.000000000 Z
11
+ date: 2026-11-06 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Convert, compress and transform images, documents, audio, video, ebooks,
14
14
  archives and CAD — and run operations like OCR, merge, thumbnail and website capture
@@ -73,6 +73,7 @@ files:
73
73
  - lib/api2convert/support/data.rb
74
74
  - lib/api2convert/support/redactor.rb
75
75
  - lib/api2convert/support/secret.rb
76
+ - lib/api2convert/support/strings.rb
76
77
  - lib/api2convert/upload/file_uploader.rb
77
78
  - lib/api2convert/upload/multipart_stream.rb
78
79
  - lib/api2convert/version.rb