smplkit 3.0.19 → 3.0.20

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: 8dc0e8067c66c43e659ad29aff4756448763e90c251e300d598762a7aad1130b
4
- data.tar.gz: 0a658e3773fcb670b7891c6fc5b18ffeea16780a3195c8e0aa866132e2018fe9
3
+ metadata.gz: 4fd326702343cd2c8f212f2964214c6c5b12eaf3d38747207a3aa26642b68af8
4
+ data.tar.gz: 1a298755b3fb4d87ec58d09664720ea078595bd77ce11cd7bef20184b4e20f0a
5
5
  SHA512:
6
- metadata.gz: 6f1ef7cc9470990ee57fbe8587fff5f4a0ac5f9ab2199186b4f585fbe8dfc8dc9efd74acc8787f3c4a3fab4b9acc4c2860118e6f5b91c4934f8684d0c8d88f7f
7
- data.tar.gz: 9c8cf307db3e470c047b518aeb079b558d7c19f1687293e1103d1570104fc2c2bfde6f2591f090a94bf46cc3b438123d38e7caa7db2f7b1a923aad91b096e4c5
6
+ metadata.gz: fffd9940159bb8e141024235be5a3c0d9992a7ee23cc1bc454e1baca7d286bc19be8ee7114bd36fbff599f9ea05ed71853891fff43a98dcf97c94c7bc9065b3c
7
+ data.tar.gz: 500a7b954f794cd50c59e4d56e4354e9e5908f8f9e27a09c662d64c74aa64f90a9f1c3d8962314c8d312a5c1d80947db823eab2f859b0d87025caee78a3bddce
@@ -2,10 +2,6 @@
2
2
 
3
3
  module Smplkit
4
4
  module Audit
5
- # Parse the +page[after]+ cursor out of a JSON:API +links.next+
6
- # URL. Returns nil for non-string input or when the link carries
7
- # no cursor parameter; trims trailing query params at the next
8
- # ampersand so they don't leak into the token.
9
5
  # Wrap a generated-audit-API call and translate +ApiError+ into the
10
6
  # +Smplkit::Error+ hierarchy. Connection-level failures (no
11
7
  # response code) become {Smplkit::ConnectionError}; status-coded
@@ -24,6 +20,10 @@ module Smplkit
24
20
  raise
25
21
  end
26
22
 
23
+ # Parse the +page[after]+ cursor out of a JSON:API +links.next+
24
+ # URL. Returns nil for non-string input or when the link carries
25
+ # no cursor parameter; trims trailing query params at the next
26
+ # ampersand so they don't leak into the token.
27
27
  def self.next_cursor(link)
28
28
  return nil unless link.is_a?(String)
29
29
 
@@ -49,23 +49,28 @@ module Smplkit
49
49
  out
50
50
  end
51
51
 
52
- # Public-facing enum for SIEM streaming destination types.
52
+ # Supported SIEM forwarder destination types (ADR-047 §2.12).
53
53
  #
54
- # Mirrors the +ForwarderType+ enum the audit OpenAPI spec emits
55
- # (ADR-047 §2.12). Customers pass these constantsor any string
56
- # in {VALUES} — to the management +forwarders+ surface. The wrapper
57
- # validates membership before round-tripping to the wire.
54
+ # Members are declared in alphabetical order. Customers pass these
55
+ # constants or the equivalent stringto the management
56
+ # +forwarders+ surface; the wrapper validates membership via {coerce}
57
+ # before round-tripping to the wire.
58
58
  module ForwarderType
59
- HTTP = "HTTP"
60
59
  DATADOG = "DATADOG"
60
+ ELASTIC = "ELASTIC"
61
+ HONEYCOMB = "HONEYCOMB"
62
+ HTTP = "HTTP"
63
+ NEW_RELIC = "NEW_RELIC"
61
64
  SPLUNK_HEC = "SPLUNK_HEC"
62
65
  SUMO_LOGIC = "SUMO_LOGIC"
63
- NEW_RELIC = "NEW_RELIC"
64
- HONEYCOMB = "HONEYCOMB"
65
- ELASTIC = "ELASTIC"
66
66
 
67
- VALUES = [HTTP, DATADOG, SPLUNK_HEC, SUMO_LOGIC, NEW_RELIC, HONEYCOMB, ELASTIC].freeze
67
+ VALUES = [DATADOG, ELASTIC, HONEYCOMB, HTTP, NEW_RELIC, SPLUNK_HEC, SUMO_LOGIC].freeze
68
68
 
69
+ # Validate and normalize an input to a wire-format string.
70
+ #
71
+ # @param value [String, nil] a published constant or its literal string.
72
+ # @return [String, nil] the canonical wire value (or +nil+ when input is +nil+).
73
+ # @raise [ArgumentError] when +value+ is not a member of {VALUES}.
69
74
  def self.coerce(value)
70
75
  return nil if value.nil?
71
76
 
@@ -77,7 +82,64 @@ module Smplkit
77
82
  end
78
83
  end
79
84
 
80
- # Public-facing audit event resource. ADR-047 §2.3.1.
85
+ # HTTP verb used by a forwarder's outbound delivery (ADR-047 §2.12).
86
+ #
87
+ # Mirrors the audit spec's +HttpConfigurationMethod+ enum so the
88
+ # +HttpConfiguration#method+ field is constrained to a known value
89
+ # instead of accepting any string. Members are declared in
90
+ # alphabetical order.
91
+ module HttpMethod
92
+ DELETE = "DELETE"
93
+ GET = "GET"
94
+ PATCH = "PATCH"
95
+ POST = "POST"
96
+ PUT = "PUT"
97
+
98
+ VALUES = [DELETE, GET, PATCH, POST, PUT].freeze
99
+
100
+ # Validate and normalize an input to a wire-format string.
101
+ #
102
+ # @param value [String, nil] a published constant or its literal string.
103
+ # @return [String, nil] the canonical wire value (or +nil+ when input is +nil+).
104
+ # @raise [ArgumentError] when +value+ is not a member of {VALUES}.
105
+ def self.coerce(value)
106
+ return nil if value.nil?
107
+
108
+ s = value.to_s
109
+ return s if VALUES.include?(s)
110
+
111
+ raise ArgumentError,
112
+ "Unknown HttpMethod #{value.inspect}; expected one of #{VALUES.inspect}"
113
+ end
114
+ end
115
+
116
+ # A single audit event as returned by the audit service (ADR-047 §2.3.1).
117
+ #
118
+ # @!attribute [rw] id
119
+ # @return [String] Server-assigned UUID for this event.
120
+ # @!attribute [rw] action
121
+ # @return [String] Action slug — e.g. +"user.created"+, +"invoice.paid"+.
122
+ # @!attribute [rw] resource_type
123
+ # @return [String] Type of resource the action operated on — e.g. +"invoice"+.
124
+ # @!attribute [rw] resource_id
125
+ # @return [String] Customer-facing id of the resource the action operated on.
126
+ # @!attribute [rw] occurred_at
127
+ # @return [String] ISO-8601 timestamp of when the action happened, as reported by the source.
128
+ # @!attribute [rw] created_at
129
+ # @return [String] ISO-8601 timestamp of when the audit service first ingested this event.
130
+ # @!attribute [rw] actor_type
131
+ # @return [String, nil] Type of actor (+"user"+, +"api_key"+, +"system"+, …) — +nil+ when unknown.
132
+ # @!attribute [rw] actor_id
133
+ # @return [String, nil] UUID of the actor when the actor is a tracked entity (user, api_key);
134
+ # +nil+ for system or anonymous events.
135
+ # @!attribute [rw] actor_label
136
+ # @return [String, nil] Display label for the actor — typically a name or email.
137
+ # @!attribute [rw] data
138
+ # @return [Hash{String => Object}] Free-form per-event payload defined by the customer.
139
+ # @!attribute [rw] idempotency_key
140
+ # @return [String, nil] Customer-supplied dedupe key, +nil+ if not provided.
141
+ # @!attribute [rw] do_not_forward
142
+ # @return [Boolean] When +true+, skip SIEM forwarder delivery regardless of any matching filter.
81
143
  AuditEvent = Struct.new(
82
144
  :id, :action, :resource_type, :resource_id,
83
145
  :occurred_at, :created_at,
@@ -110,6 +172,13 @@ module Smplkit
110
172
  # the customer-facing key as the resource id (ADR-014). The duplication
111
173
  # keeps SDK consumers from having to dig into the id field when
112
174
  # filtering UI controls; pick whichever name reads better in context.
175
+ #
176
+ # @!attribute [rw] id
177
+ # @return [String] JSON:API resource id (same as +resource_type+).
178
+ # @!attribute [rw] resource_type
179
+ # @return [String] The distinct resource_type slug.
180
+ # @!attribute [rw] created_at
181
+ # @return [String] ISO-8601 timestamp of the earliest sighting for this slug.
113
182
  ResourceType = Struct.new(:id, :resource_type, :created_at, keyword_init: true) do
114
183
  def self.from_resource(resource)
115
184
  attrs = resource.attributes
@@ -127,6 +196,13 @@ module Smplkit
127
196
  # +created_at+ is the earliest sighting; when the parent list call
128
197
  # filtered by +resource_type+, this is the first sighting of that
129
198
  # specific (action, resource_type) triple, not the action overall.
199
+ #
200
+ # @!attribute [rw] id
201
+ # @return [String] JSON:API resource id (same as +action+).
202
+ # @!attribute [rw] action
203
+ # @return [String] The distinct action slug.
204
+ # @!attribute [rw] created_at
205
+ # @return [String] ISO-8601 timestamp of the earliest sighting for this slug.
130
206
  Action = Struct.new(:id, :action, :created_at, keyword_init: true) do
131
207
  def self.from_resource(resource)
132
208
  attrs = resource.attributes
@@ -138,19 +214,41 @@ module Smplkit
138
214
  end
139
215
  end
140
216
 
217
+ # A single name/value HTTP header on a forwarder destination.
218
+ #
219
+ # @!attribute [rw] name
220
+ # @return [String] Header name (e.g. +"Authorization"+, +"DD-API-KEY"+).
221
+ # @!attribute [rw] value
222
+ # @return [String] Header value, plaintext on writes. The audit service
223
+ # encrypts values at rest; reads return them as +"<redacted>"+.
141
224
  HttpHeader = Struct.new(:name, :value, keyword_init: true)
142
225
 
226
+ # Forwarder destination HTTP request shape.
227
+ #
228
+ # @!attribute [rw] method
229
+ # @return [String] HTTP verb used for delivery. Defaults to {HttpMethod::POST}.
230
+ # @!attribute [rw] url
231
+ # @return [String] Destination URL the audit service sends each event to.
232
+ # @!attribute [rw] headers
233
+ # @return [Array<HttpHeader>] Headers attached to every outbound request.
234
+ # Values carry credentials and are encrypted at rest server-side; reads
235
+ # return them redacted.
236
+ # @!attribute [rw] success_status
237
+ # @return [String] Status the destination must return for delivery to count
238
+ # as success — an exact code (+"200"+, +"204"+) or a class (+"2xx"+, +"4xx"+).
239
+ # Defaults to +"2xx"+.
240
+ #
143
241
  # rubocop:disable Lint/StructNewOverride -- ``:method`` matches the
144
242
  # API attribute and shadowing Struct#method is the expected ergonomics.
145
243
  HttpConfiguration = Struct.new(:method, :url, :headers, :success_status, keyword_init: true) do
146
- def initialize(method: "POST", url: "", headers: nil, success_status: "2xx")
147
- super(method: method, url: url, headers: headers || [], success_status: success_status)
244
+ def initialize(method: HttpMethod::POST, url: "", headers: nil, success_status: "2xx")
245
+ super(method: HttpMethod.coerce(method), url: url, headers: headers || [], success_status: success_status)
148
246
  end
149
247
 
150
248
  def self.to_wire(src)
151
249
  h = src.is_a?(Hash) ? new(**src) : src
152
250
  SmplkitGeneratedClient::Audit::HttpConfiguration.new(
153
- method: h.method,
251
+ method: HttpMethod.coerce(h.method),
154
252
  url: h.url,
155
253
  headers: (h.headers || []).map do |hdr|
156
254
  name, value = if hdr.is_a?(Hash)
@@ -169,7 +267,7 @@ module Smplkit
169
267
  return new if src.nil?
170
268
 
171
269
  new(
172
- method: src.method || "POST",
270
+ method: src.method || HttpMethod::POST,
173
271
  url: src.url || "",
174
272
  headers: (src.headers || []).map { |h| HttpHeader.new(name: h.name, value: h.value) },
175
273
  success_status: src.success_status || "2xx"
@@ -178,17 +276,130 @@ module Smplkit
178
276
  end
179
277
  # rubocop:enable Lint/StructNewOverride
180
278
 
181
- # rubocop:disable Lint/StructNewOverride -- ``:filter`` matches the
182
- # API attribute and shadowing Struct#filter is the expected ergonomics.
183
- Forwarder = Struct.new(
184
- :id, :name, :description, :forwarder_type, :enabled,
185
- :filter, :transform_type, :transform, :configuration,
186
- :created_at, :updated_at, :deleted_at, :version,
187
- keyword_init: true
188
- ) do
189
- def self.from_resource(resource)
279
+ # A SIEM streaming forwarder configured on the customer's account.
280
+ #
281
+ # Active-record style: instantiate via
282
+ # +mgmt.audit.forwarders.new_forwarder(...)+, mutate fields directly,
283
+ # and call {#save} to persist or {#delete} to remove. Header values in
284
+ # +configuration.headers+ are returned redacted on reads — the GET path
285
+ # on the audit API replaces every header value with +"<redacted>"+.
286
+ # Re-supply real values before calling {#save}; the SDK does not cache
287
+ # them client-side.
288
+ class Forwarder
289
+ # @return [String, nil] Server-assigned UUID, +nil+ until {#save} has run.
290
+ attr_accessor :id
291
+
292
+ # @return [String] Display name. Free-form.
293
+ attr_accessor :name
294
+
295
+ # @return [String] One of {ForwarderType::VALUES}.
296
+ attr_accessor :forwarder_type
297
+
298
+ # @return [Boolean] When +false+, the audit service skips delivery for
299
+ # this forwarder but still records +filtered_out+ deliveries.
300
+ attr_accessor :enabled
301
+
302
+ # @return [HttpConfiguration] Destination request configuration.
303
+ attr_accessor :configuration
304
+
305
+ # @return [String, nil] Optional free-text description.
306
+ attr_accessor :description
307
+
308
+ # @return [Hash, nil] Optional JSON Logic expression evaluated per event.
309
+ # When set, events that don't match are recorded as +filtered_out+
310
+ # deliveries instead of being delivered to the destination.
311
+ attr_accessor :filter
312
+
313
+ # @return [String, nil] Optional template applied to each event before
314
+ # delivery. Shape depends on {#transform_type}; for +"JSONATA"+, a
315
+ # JSONata expression. +nil+ delivers the event JSON as-is.
316
+ attr_accessor :transform
317
+
318
+ # @return [String, nil] Engine that evaluates {#transform}. Currently
319
+ # only +"JSONATA"+ is supported.
320
+ attr_accessor :transform_type
321
+
322
+ # @return [String, nil] ISO-8601 timestamp of first persist. +nil+ for an unsaved instance.
323
+ attr_accessor :created_at
324
+
325
+ # @return [String, nil] ISO-8601 timestamp of the most recent mutation.
326
+ attr_accessor :updated_at
327
+
328
+ # @return [String, nil] Soft-delete timestamp. +nil+ for live forwarders.
329
+ attr_accessor :deleted_at
330
+
331
+ # @return [Integer, nil] Monotonic version counter, bumped on every server-side write.
332
+ attr_accessor :version
333
+
334
+ def initialize(client = nil, name:, forwarder_type:, configuration:,
335
+ id: nil, enabled: true, description: nil,
336
+ filter: nil, transform: nil, transform_type: nil,
337
+ created_at: nil, updated_at: nil, deleted_at: nil, version: nil)
338
+ @client = client
339
+ @id = id
340
+ @name = name
341
+ @forwarder_type = ForwarderType.coerce(forwarder_type)
342
+ @configuration = configuration
343
+ @enabled = enabled
344
+ @description = description
345
+ @filter = filter
346
+ @transform = transform
347
+ @transform_type = transform_type
348
+ @created_at = created_at
349
+ @updated_at = updated_at
350
+ @deleted_at = deleted_at
351
+ @version = version
352
+ end
353
+
354
+ # Create or update this forwarder on the server.
355
+ #
356
+ # Upsert behavior is driven by {#created_at}: a forwarder with no
357
+ # +created_at+ is created (POST); otherwise it's full-replace updated
358
+ # (PUT). After the call, every field is refreshed from the server
359
+ # response (including newly-assigned +id+, +created_at+, +updated_at+,
360
+ # +version+).
361
+ #
362
+ # @return [self]
363
+ def save
364
+ raise "Forwarder was constructed without a client; cannot save" if @client.nil?
365
+
366
+ updated = @created_at.nil? ? @client._create_forwarder(self) : @client._update_forwarder(self)
367
+ _apply(updated)
368
+ self
369
+ end
370
+ alias save! save
371
+
372
+ # Soft-delete this forwarder on the server.
373
+ #
374
+ # @return [nil]
375
+ def delete
376
+ raise "Forwarder was constructed without a client or id; cannot delete" if @client.nil? || @id.nil?
377
+
378
+ @client.delete(@id)
379
+ end
380
+ alias delete! delete
381
+
382
+ # @api private
383
+ def _apply(other)
384
+ @id = other.id
385
+ @name = other.name
386
+ @forwarder_type = other.forwarder_type
387
+ @configuration = other.configuration
388
+ @enabled = other.enabled
389
+ @description = other.description
390
+ @filter = other.filter
391
+ @transform = other.transform
392
+ @transform_type = other.transform_type
393
+ @created_at = other.created_at
394
+ @updated_at = other.updated_at
395
+ @deleted_at = other.deleted_at
396
+ @version = other.version
397
+ end
398
+
399
+ def self.from_resource(resource, client: nil)
190
400
  a = resource.attributes
191
401
  new(
402
+ client,
192
403
  id: resource.id,
193
404
  name: a.name,
194
405
  description: a.description,
@@ -205,6 +416,5 @@ module Smplkit
205
416
  )
206
417
  end
207
418
  end
208
- # rubocop:enable Lint/StructNewOverride
209
419
  end
210
420
  end
@@ -4,12 +4,12 @@ module Smplkit
4
4
  module Config
5
5
  # Type of a +ConfigItem+ value.
6
6
  module ItemType
7
- STRING = "STRING"
8
- NUMBER = "NUMBER"
9
7
  BOOLEAN = "BOOLEAN"
10
8
  JSON = "JSON"
9
+ NUMBER = "NUMBER"
10
+ STRING = "STRING"
11
11
 
12
- ALL = [STRING, NUMBER, BOOLEAN, JSON].freeze
12
+ ALL = [BOOLEAN, JSON, NUMBER, STRING].freeze
13
13
  end
14
14
 
15
15
  # A single typed item in a +Config+.
@@ -7,16 +7,16 @@ module Smplkit
7
7
  # can validate calls. Raw strings are still accepted for backward
8
8
  # compatibility.
9
9
  module Op
10
+ CONTAINS = "contains"
10
11
  EQ = "=="
11
- NEQ = "!="
12
- LT = "<"
13
- LTE = "<="
14
12
  GT = ">"
15
13
  GTE = ">="
16
14
  IN = "in"
17
- CONTAINS = "contains"
15
+ LT = "<"
16
+ LTE = "<="
17
+ NEQ = "!="
18
18
 
19
- ALL = [EQ, NEQ, LT, LTE, GT, GTE, IN, CONTAINS].freeze
19
+ ALL = [CONTAINS, EQ, GT, GTE, IN, LT, LTE, NEQ].freeze
20
20
  end
21
21
 
22
22
  # A typed entity referenced by targeting rules and registered with smplkit.
@@ -4,11 +4,17 @@ module Smplkit
4
4
  # Log severity levels used by the Smpl Logging service.
5
5
  #
6
6
  # Acts as a string-valued enum: each constant equals its name when used in
7
- # string contexts, and supports comparison via the +ordinal+.
7
+ # string contexts, and supports comparison via the +ordinal+. Members are
8
+ # declared in alphabetical order; severity is encoded in {#ordinal}, not
9
+ # in declaration order.
8
10
  class LogLevel
9
- NAMES = %w[TRACE DEBUG INFO WARN ERROR FATAL SILENT].freeze
11
+ NAMES = %w[DEBUG ERROR FATAL INFO SILENT TRACE WARN].freeze
10
12
 
11
- attr_reader :name, :ordinal
13
+ # @return [String] Canonical level name (e.g. +"INFO"+).
14
+ attr_reader :name
15
+
16
+ # @return [Integer] Severity ordinal — TRACE=0 (lowest) through SILENT=6 (highest).
17
+ attr_reader :ordinal
12
18
 
13
19
  def initialize(name, ordinal)
14
20
  @name = name.freeze
@@ -26,15 +32,15 @@ module Smplkit
26
32
 
27
33
  include Comparable
28
34
 
29
- TRACE = new("TRACE", 0)
30
35
  DEBUG = new("DEBUG", 1)
31
- INFO = new("INFO", 2)
32
- WARN = new("WARN", 3)
33
36
  ERROR = new("ERROR", 4)
34
37
  FATAL = new("FATAL", 5)
38
+ INFO = new("INFO", 2)
35
39
  SILENT = new("SILENT", 6)
40
+ TRACE = new("TRACE", 0)
41
+ WARN = new("WARN", 3)
36
42
 
37
- ALL = [TRACE, DEBUG, INFO, WARN, ERROR, FATAL, SILENT].freeze
43
+ ALL = [DEBUG, ERROR, FATAL, INFO, SILENT, TRACE, WARN].freeze
38
44
 
39
45
  BY_NAME = ALL.to_h { |lvl| [lvl.name, lvl] }.freeze
40
46
 
@@ -8,6 +8,7 @@ module Smplkit
8
8
  # runtime client owns event recording and read-side queries; this
9
9
  # surface owns SIEM forwarder CRUD. ADR-047 §2.7.
10
10
  class AuditNamespace
11
+ # @return [ForwardersNamespace] CRUD surface for +mgmt.audit.forwarders+.
11
12
  attr_reader :forwarders
12
13
 
13
14
  def initialize(api_client)
@@ -19,41 +20,56 @@ module Smplkit
19
20
 
20
21
  # +mgmt.audit.forwarders.*+ — manage the customer's configured SIEM
21
22
  # forwarders.
23
+ #
24
+ # The active-record entry point is {#new_forwarder}: instantiate a
25
+ # draft, mutate fields, then call {Smplkit::Audit::Forwarder#save}.
26
+ # The namespace exposes {#list}, {#get}, and {#delete} directly; the
27
+ # +_create_forwarder+ / +_update_forwarder+ helpers are private and
28
+ # invoked by {Smplkit::Audit::Forwarder#save}.
22
29
  class ForwardersNamespace
23
30
  def initialize(api)
24
31
  @api = api
25
32
  end
26
33
 
27
- # Create a forwarder.
34
+ # Construct an unsaved {Smplkit::Audit::Forwarder} bound to this
35
+ # namespace. Call +#save+ on the returned instance to persist.
28
36
  #
29
37
  # @param name [String] Display name.
30
- # @param forwarder_type [String, Smplkit::Audit::ForwarderType]
31
- # One of the published {Smplkit::Audit::ForwarderType} constants
32
- # (or the equivalent string).
33
- # @param configuration [Smplkit::Audit::HttpConfiguration, Hash]
34
- # Transport-specific delivery configuration. Today every
35
- # forwarder_type uses {HttpConfiguration}; the URL and header
36
- # values inside are stored encrypted server-side and round-trip
37
- # to GET in plaintext.
38
+ # @param forwarder_type [String] One of {Smplkit::Audit::ForwarderType::VALUES}.
39
+ # @param configuration [Smplkit::Audit::HttpConfiguration] Destination
40
+ # request configuration. Headers carry credentials and are encrypted at
41
+ # rest server-side; reads return them redacted.
42
+ # @param enabled [Boolean] Whether the forwarder is active. Defaults +true+.
38
43
  # @param description [String, nil] Optional free-text description.
39
- # @param enabled [Boolean] Whether the forwarder is active.
40
- # @param filter [Hash, nil] Optional JSON Logic filter; events
41
- # that don't match are recorded as +filtered_out+ deliveries.
42
- # @param transform_type [String, nil] Engine that evaluates
43
- # +transform+. Set to +"JSONATA"+ whenever +transform+ is set.
44
- # @param transform [String, nil] Optional template applied to the
45
- # event payload before delivery (for +JSONATA+, a JSONata
46
- # expression). Nil sends the event JSON unchanged.
47
- def create(name:, forwarder_type:, configuration:, description: nil, enabled: true,
48
- filter: nil, transform_type: nil, transform: nil)
49
- body = build_body(nil, name: name, forwarder_type: forwarder_type,
50
- configuration: configuration, description: description,
51
- enabled: enabled, filter: filter,
52
- transform_type: transform_type, transform: transform)
53
- resp = Smplkit::Audit.call_api { @api.create_forwarder(body) }
54
- Smplkit::Audit::Forwarder.from_resource(resp.data)
44
+ # @param filter [Hash, nil] Optional JSON Logic filter; events that don't
45
+ # match are recorded as +filtered_out+ deliveries.
46
+ # @param transform [String, nil] Optional JSONata template applied to the
47
+ # event payload before delivery. Nil sends the event JSON unchanged.
48
+ # @return [Smplkit::Audit::Forwarder]
49
+ def new_forwarder(name:, forwarder_type:, configuration:,
50
+ enabled: true, description: nil,
51
+ filter: nil, transform: nil)
52
+ Smplkit::Audit::Forwarder.new(
53
+ self,
54
+ name: name,
55
+ forwarder_type: forwarder_type,
56
+ configuration: configuration,
57
+ enabled: enabled,
58
+ description: description,
59
+ filter: filter,
60
+ transform: transform,
61
+ transform_type: transform.nil? ? nil : "JSONATA"
62
+ )
55
63
  end
56
64
 
65
+ # List forwarders for the authenticated account.
66
+ #
67
+ # Offset paginated per ADR-014: pass +page_number+ (1-based) and
68
+ # +page_size+ (default 1000, max 1000). Pass +meta_total: true+ to
69
+ # populate +total+ and +total_pages+ in the returned +pagination+
70
+ # block (costs an extra COUNT query server-side).
71
+ #
72
+ # @return [ForwarderListPage]
57
73
  def list(forwarder_type: nil, enabled: nil, page_number: nil, page_size: nil, meta_total: nil)
58
74
  opts = {}
59
75
  opts[:filter_forwarder_type] = Smplkit::Audit::ForwarderType.coerce(forwarder_type) if forwarder_type
@@ -63,51 +79,67 @@ module Smplkit
63
79
  opts[:meta_total] = meta_total unless meta_total.nil?
64
80
 
65
81
  resp = Smplkit::Audit.call_api { @api.list_forwarders(opts) }
66
- forwarders = (resp.data || []).map { |r| Smplkit::Audit::Forwarder.from_resource(r) }
82
+ forwarders = (resp.data || []).map do |r|
83
+ Smplkit::Audit::Forwarder.from_resource(r, client: self)
84
+ end
67
85
  ForwarderListPage.new(forwarders, Smplkit::Audit.extract_pagination(resp.meta))
68
86
  end
69
87
 
88
+ # Fetch a single forwarder by id. The returned instance is bound to
89
+ # this namespace, so +forwarder.save+ and +forwarder.delete+ work.
90
+ #
91
+ # @param forwarder_id [String]
92
+ # @return [Smplkit::Audit::Forwarder]
70
93
  def get(forwarder_id)
71
94
  resp = Smplkit::Audit.call_api { @api.get_forwarder(forwarder_id) }
72
- Smplkit::Audit::Forwarder.from_resource(resp.data)
95
+ Smplkit::Audit::Forwarder.from_resource(resp.data, client: self)
73
96
  end
74
97
 
75
- # Full-replace update. PUT semantics — every field is overwritten.
98
+ # Soft-delete a forwarder.
76
99
  #
77
- # The URL and header values inside +configuration+ are returned in
78
- # plaintext on GET, so a fetched forwarder can be round-tripped to
79
- # PUT without re-entering secrets.
80
- def update(forwarder_id, name:, forwarder_type:, configuration:, description: nil,
81
- enabled: true, filter: nil, transform_type: nil, transform: nil)
82
- body = build_body(forwarder_id, name: name, forwarder_type: forwarder_type,
83
- configuration: configuration, description: description,
84
- enabled: enabled, filter: filter,
85
- transform_type: transform_type, transform: transform)
86
- resp = Smplkit::Audit.call_api { @api.update_forwarder(forwarder_id, body) }
87
- Smplkit::Audit::Forwarder.from_resource(resp.data)
88
- end
89
-
100
+ # @param forwarder_id [String]
101
+ # @return [nil]
90
102
  def delete(forwarder_id)
91
103
  Smplkit::Audit.call_api { @api.delete_forwarder(forwarder_id) }
92
104
  nil
93
105
  end
94
106
 
107
+ # @api private — POST a new forwarder. Called by
108
+ # {Smplkit::Audit::Forwarder#save} on unsaved instances.
109
+ def _create_forwarder(forwarder)
110
+ resp = Smplkit::Audit.call_api { @api.create_forwarder(build_body(forwarder)) }
111
+ Smplkit::Audit::Forwarder.from_resource(resp.data, client: self)
112
+ end
113
+
114
+ # @api private — Full-replace PUT for an existing forwarder. Called
115
+ # by {Smplkit::Audit::Forwarder#save} on instances with +created_at+.
116
+ #
117
+ # Header values must be re-supplied as plaintext; the GET path
118
+ # redacts them, so a PUT body containing +"<redacted>"+ would
119
+ # persist that literal. Track real header values client-side and
120
+ # round-trip them.
121
+ def _update_forwarder(forwarder)
122
+ raise ArgumentError, "cannot update a Forwarder with no id" if forwarder.id.nil?
123
+
124
+ resp = Smplkit::Audit.call_api { @api.update_forwarder(forwarder.id, build_body(forwarder)) }
125
+ Smplkit::Audit::Forwarder.from_resource(resp.data, client: self)
126
+ end
127
+
95
128
  private
96
129
 
97
- def build_body(id, name:, forwarder_type:, configuration:, description:, enabled:,
98
- filter:, transform_type:, transform:)
130
+ def build_body(forwarder)
99
131
  attrs = SmplkitGeneratedClient::Audit::Forwarder.new(
100
- name: name,
101
- description: description,
102
- forwarder_type: Smplkit::Audit::ForwarderType.coerce(forwarder_type),
103
- enabled: enabled,
104
- filter: filter,
105
- transform_type: transform_type,
106
- transform: transform,
107
- configuration: Smplkit::Audit::HttpConfiguration.to_wire(configuration)
132
+ name: forwarder.name,
133
+ description: forwarder.description,
134
+ forwarder_type: Smplkit::Audit::ForwarderType.coerce(forwarder.forwarder_type),
135
+ enabled: forwarder.enabled,
136
+ filter: forwarder.filter,
137
+ transform_type: forwarder.transform_type,
138
+ transform: forwarder.transform,
139
+ configuration: Smplkit::Audit::HttpConfiguration.to_wire(forwarder.configuration)
108
140
  )
109
141
  resource = SmplkitGeneratedClient::Audit::ForwarderResource.new(
110
- id: id ? id.to_s : "",
142
+ id: forwarder.id ? forwarder.id.to_s : "",
111
143
  type: "forwarder",
112
144
  attributes: attrs
113
145
  )
@@ -115,6 +147,13 @@ module Smplkit
115
147
  end
116
148
  end
117
149
 
150
+ # A single page returned from {ForwardersNamespace#list}.
151
+ #
152
+ # @!attribute [rw] forwarders
153
+ # @return [Array<Smplkit::Audit::Forwarder>] Forwarders in this page.
154
+ # @!attribute [rw] pagination
155
+ # @return [Hash] +meta.pagination+ block (+:page+, +:size+, and — only when
156
+ # the caller passed +meta_total: true+ — +:total+ / +:total_pages+).
118
157
  ForwarderListPage = Struct.new(:forwarders, :pagination)
119
158
  end
120
159
  end
@@ -9,10 +9,10 @@ module Smplkit
9
9
  # +AD_HOC+ environments are transient targets (preview branches, individual
10
10
  # developer sandboxes) that should not appear in the standard ordering.
11
11
  module EnvironmentClassification
12
- STANDARD = "STANDARD"
13
12
  AD_HOC = "AD_HOC"
13
+ STANDARD = "STANDARD"
14
14
 
15
- ALL = [STANDARD, AD_HOC].freeze
15
+ ALL = [AD_HOC, STANDARD].freeze
16
16
  end
17
17
 
18
18
  HEX_RE = /\A#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})\z/
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smplkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.19
4
+ version: 3.0.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - Smpl Solutions LLC