schematichq 1.4.5 → 1.4.6
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 +4 -4
- data/.fern/metadata.json +2 -2
- data/.fern/replay.lock +20 -495
- data/WASM_VERSION +1 -1
- data/lib/schematic/billing/client.rb +102 -2
- data/lib/schematic/billing/types/delete_billing_coupon_response.rb +12 -0
- data/lib/schematic/billing/types/delete_billing_customer_response.rb +12 -0
- data/lib/schematic/billing/types/delete_billing_invoice_response.rb +12 -0
- data/lib/schematic/billing/types/list_billing_prices_params.rb +1 -0
- data/lib/schematic/billing/types/list_billing_prices_request.rb +1 -0
- data/lib/schematic/billing/types/list_billing_product_prices_params.rb +1 -0
- data/lib/schematic/billing/types/list_billing_product_prices_request.rb +1 -0
- data/lib/schematic/client.rb +1 -1
- data/lib/schematic/datastream/merge.rb +3 -4
- data/lib/schematic/types/account_member_permission.rb +0 -1
- data/lib/schematic/types/check_flags_response_data.rb +1 -0
- data/lib/schematic/types/company_credit_balance.rb +11 -0
- data/lib/schematic/types/company_subscription_response_data.rb +1 -0
- data/lib/schematic/types/feature_entitlement.rb +2 -0
- data/lib/schematic/types/rulesengine_feature_entitlement.rb +2 -0
- data/lib/schematic/types/test_webhook_response_data.rb +10 -0
- data/lib/schematic/version.rb +1 -1
- data/lib/schematic/wasm/rulesengine.wasm +0 -0
- data/lib/schematic/webhooks/client.rb +37 -0
- data/lib/schematic/webhooks/types/send_test_webhook_action_response.rb +12 -0
- data/lib/schematic/webhooks/types/test_webhook_request_body.rb +12 -0
- data/lib/schematic.rb +7 -0
- data/reference.md +221 -0
- metadata +9 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6229824d941e4fc71c6c6c7bd9849d843c8aaee72140238da1b24084abe2c4e6
|
|
4
|
+
data.tar.gz: ed47a6602419d5d1b74f5d2513cdf9c1dc40651418285833b5f7672e8fbaeb46
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fba8e4ee8af143a05af7c33950fb3b977db5aa634df7a469f6a67e2697d0b53ad88e94d7e485f5fb14d55f1bb6684dcb60b192d88c2be3e3cf650ef08bb95670
|
|
7
|
+
data.tar.gz: 7c7ba025d48148e3720c059526eb969a3a0f83ae5994c3ad657dc3d88e43954993eb074bae4b21b0c199837d3021ac192d716873963a09739a456f524bb5e471
|
data/.fern/metadata.json
CHANGED
data/.fern/replay.lock
CHANGED
|
@@ -12,498 +12,23 @@ generations:
|
|
|
12
12
|
cli_version: unknown
|
|
13
13
|
generator_versions:
|
|
14
14
|
fernapi/fern-ruby-sdk: 1.1.13
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
+ # fields change in another part of the company we sync them here to match
|
|
36
|
-
+ # server behavior (see schematic-python merge.partial_company):
|
|
37
|
-
+ # - credit_remaining <- credit_balances[credit_id]
|
|
38
|
-
+ # - usage <- metric value matching (event_name, metric_period, month_reset)
|
|
39
|
-
+ # Both are skipped when the partial also sends entitlements wholesale.
|
|
40
|
-
def partial_company(existing, partial_data)
|
|
41
|
-
return existing unless partial_data.is_a?(Hash)
|
|
42
|
-
|
|
43
|
-
result = deep_copy(existing)
|
|
44
|
-
+ entitlements_in_partial = partial_data.key?(:entitlements) || partial_data.key?("entitlements")
|
|
45
|
-
+ updated_balances = nil
|
|
46
|
-
+ metrics_updated = false
|
|
47
|
-
|
|
48
|
-
partial_data.each do |key, value|
|
|
49
|
-
sym_key = key.to_sym
|
|
50
|
-
if COMPANY_MAP_FIELDS.include?(sym_key)
|
|
51
|
-
result[sym_key] ||= {}
|
|
52
|
-
result[sym_key] = result[sym_key].merge(value) if value.is_a?(Hash)
|
|
53
|
-
+ updated_balances = (value.is_a?(Hash) ? value : {}) if sym_key == :credit_balances
|
|
54
|
-
elsif COMPANY_ARRAY_FIELDS.include?(sym_key)
|
|
55
|
-
result[sym_key] = value if value.is_a?(Array)
|
|
56
|
-
elsif sym_key == :metrics
|
|
57
|
-
result[sym_key] = upsert_metrics(result[sym_key] || [], value || [])
|
|
58
|
-
+ metrics_updated = true
|
|
59
|
-
else
|
|
60
|
-
result[sym_key] = value
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
+ if (updated_balances || metrics_updated) && !entitlements_in_partial
|
|
65
|
-
+ result[:entitlements] = sync_entitlements(
|
|
66
|
-
+ result[:entitlements], result[:metrics], updated_balances, metrics_updated
|
|
67
|
-
+ )
|
|
68
|
-
+ end
|
|
69
|
-
+
|
|
70
|
-
result
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
@@ -90,6 +107,60 @@ module Schematic
|
|
74
|
-
def get_metric_field(metric, field)
|
|
75
|
-
metric[field] || metric[field.to_s]
|
|
76
|
-
end
|
|
77
|
-
+
|
|
78
|
-
+ # Re-derive entitlement usage / credit_remaining from the merged metrics
|
|
79
|
-
+ # and the just-updated credit balances. Mirrors schematic-python so that
|
|
80
|
-
+ # entitlement usage reflects DataStream track events immediately.
|
|
81
|
-
+ def sync_entitlements(entitlements, metrics, updated_balances, metrics_updated)
|
|
82
|
-
+ return entitlements unless entitlements.is_a?(Array) && !entitlements.empty?
|
|
83
|
-
+
|
|
84
|
-
+ metrics_lookup = {}
|
|
85
|
-
+ if metrics_updated && metrics.is_a?(Array)
|
|
86
|
-
+ metrics.each do |metric|
|
|
87
|
-
+ next unless metric.is_a?(Hash)
|
|
88
|
-
+
|
|
89
|
-
+ key = [
|
|
90
|
-
+ get_metric_field(metric, :event_subtype) || "",
|
|
91
|
-
+ get_metric_field(metric, :period) || "",
|
|
92
|
-
+ get_metric_field(metric, :month_reset) || ""
|
|
93
|
-
+ ]
|
|
94
|
-
+ value = get_metric_field(metric, :value)
|
|
95
|
-
+ metrics_lookup[key] = value.nil? ? 0 : value
|
|
96
|
-
+ end
|
|
97
|
-
+ end
|
|
98
|
-
+
|
|
99
|
-
+ entitlements.map do |ent|
|
|
100
|
-
+ next ent unless ent.is_a?(Hash)
|
|
101
|
-
+
|
|
102
|
-
+ new_ent = deep_copy(ent)
|
|
103
|
-
+
|
|
104
|
-
+ credit_id = get_metric_field(ent, :credit_id)
|
|
105
|
-
+ if updated_balances && credit_id
|
|
106
|
-
+ present, balance = fetch_balance(updated_balances, credit_id)
|
|
107
|
-
+ new_ent[:credit_remaining] = balance if present
|
|
108
|
-
+ end
|
|
109
|
-
+
|
|
110
|
-
+ event_name = get_metric_field(ent, :event_name)
|
|
111
|
-
+ unless metrics_lookup.empty? || event_name.nil?
|
|
112
|
-
+ period = get_metric_field(ent, :metric_period) || "all_time"
|
|
113
|
-
+ month_reset = get_metric_field(ent, :month_reset) || "first_of_month"
|
|
114
|
-
+ matched = metrics_lookup[[event_name, period, month_reset]]
|
|
115
|
-
+ new_ent[:usage] = matched unless matched.nil?
|
|
116
|
-
+ end
|
|
117
|
-
+
|
|
118
|
-
+ new_ent
|
|
119
|
-
+ end
|
|
120
|
-
+ end
|
|
121
|
-
+
|
|
122
|
-
+ # credit_balances keys may be symbols (deep_copy symbolizes) while an
|
|
123
|
-
+ # entitlement's credit_id is always a string, so check both forms.
|
|
124
|
-
+ def fetch_balance(balances, credit_id)
|
|
125
|
-
+ return [true, balances[credit_id]] if balances.key?(credit_id)
|
|
126
|
-
+ return [true, balances[credit_id.to_sym]] if balances.key?(credit_id.to_sym)
|
|
127
|
-
+ return [true, balances[credit_id.to_s]] if balances.key?(credit_id.to_s)
|
|
128
|
-
+
|
|
129
|
-
+ [false, nil]
|
|
130
|
-
+ end
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
theirs_snapshot:
|
|
135
|
-
lib/schematic/datastream/merge.rb: |
|
|
136
|
-
# frozen_string_literal: true
|
|
137
|
-
|
|
138
|
-
require "json"
|
|
139
|
-
|
|
140
|
-
module Schematic
|
|
141
|
-
module DataStream
|
|
142
|
-
module Merge
|
|
143
|
-
module_function
|
|
144
|
-
|
|
145
|
-
def deep_copy(obj)
|
|
146
|
-
JSON.parse(JSON.generate(obj), symbolize_names: true)
|
|
147
|
-
rescue StandardError
|
|
148
|
-
obj.dup
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
COMPANY_MAP_FIELDS = %i[credit_balances keys traits].freeze
|
|
152
|
-
COMPANY_ARRAY_FIELDS = %i[billing_product_ids entitlements plan_ids plan_version_ids rules].freeze
|
|
153
|
-
|
|
154
|
-
# Partials don't carry refreshed entitlements, so when their derived
|
|
155
|
-
# fields change in another part of the company we sync them here to match
|
|
156
|
-
# server behavior (see schematic-python merge.partial_company):
|
|
157
|
-
# - credit_remaining <- credit_balances[credit_id]
|
|
158
|
-
# - usage <- metric value matching (event_name, metric_period, month_reset)
|
|
159
|
-
# Both are skipped when the partial also sends entitlements wholesale.
|
|
160
|
-
def partial_company(existing, partial_data)
|
|
161
|
-
return existing unless partial_data.is_a?(Hash)
|
|
162
|
-
|
|
163
|
-
result = deep_copy(existing)
|
|
164
|
-
entitlements_in_partial = partial_data.key?(:entitlements) || partial_data.key?("entitlements")
|
|
165
|
-
updated_balances = nil
|
|
166
|
-
metrics_updated = false
|
|
167
|
-
|
|
168
|
-
partial_data.each do |key, value|
|
|
169
|
-
sym_key = key.to_sym
|
|
170
|
-
if COMPANY_MAP_FIELDS.include?(sym_key)
|
|
171
|
-
result[sym_key] ||= {}
|
|
172
|
-
result[sym_key] = result[sym_key].merge(value) if value.is_a?(Hash)
|
|
173
|
-
updated_balances = (value.is_a?(Hash) ? value : {}) if sym_key == :credit_balances
|
|
174
|
-
elsif COMPANY_ARRAY_FIELDS.include?(sym_key)
|
|
175
|
-
result[sym_key] = value if value.is_a?(Array)
|
|
176
|
-
elsif sym_key == :metrics
|
|
177
|
-
result[sym_key] = upsert_metrics(result[sym_key] || [], value || [])
|
|
178
|
-
metrics_updated = true
|
|
179
|
-
else
|
|
180
|
-
result[sym_key] = value
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
if (updated_balances || metrics_updated) && !entitlements_in_partial
|
|
185
|
-
result[:entitlements] = sync_entitlements(
|
|
186
|
-
result[:entitlements], result[:metrics], updated_balances, metrics_updated
|
|
187
|
-
)
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
result
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
USER_MAP_FIELDS = %i[keys traits].freeze
|
|
194
|
-
|
|
195
|
-
def partial_user(existing, partial_data)
|
|
196
|
-
return existing unless partial_data.is_a?(Hash)
|
|
197
|
-
|
|
198
|
-
result = deep_copy(existing)
|
|
199
|
-
|
|
200
|
-
partial_data.each do |key, value|
|
|
201
|
-
sym_key = key.to_sym
|
|
202
|
-
if USER_MAP_FIELDS.include?(sym_key)
|
|
203
|
-
result[sym_key] ||= {}
|
|
204
|
-
result[sym_key] = result[sym_key].merge(value) if value.is_a?(Hash)
|
|
205
|
-
elsif sym_key == :rules
|
|
206
|
-
result[sym_key] = value if value.is_a?(Array)
|
|
207
|
-
else
|
|
208
|
-
result[sym_key] = value
|
|
209
|
-
end
|
|
210
|
-
end
|
|
211
|
-
|
|
212
|
-
result
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
def upsert_metrics(existing, incoming)
|
|
216
|
-
return incoming if existing.nil? || existing.empty?
|
|
217
|
-
return existing if incoming.nil? || incoming.empty?
|
|
218
|
-
|
|
219
|
-
result = existing.map { |metric| deep_copy(metric) }
|
|
220
|
-
|
|
221
|
-
incoming.each do |inc_metric|
|
|
222
|
-
match_idx = result.index do |ex|
|
|
223
|
-
metrics_match?(ex, inc_metric)
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
if match_idx
|
|
227
|
-
result[match_idx] = inc_metric
|
|
228
|
-
else
|
|
229
|
-
result << inc_metric
|
|
230
|
-
end
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
result
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
def metrics_match?(left, right)
|
|
237
|
-
get_metric_field(left, :event_subtype) == get_metric_field(right, :event_subtype) &&
|
|
238
|
-
get_metric_field(left, :period) == get_metric_field(right, :period) &&
|
|
239
|
-
get_metric_field(left, :month_reset) == get_metric_field(right, :month_reset)
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
def get_metric_field(metric, field)
|
|
243
|
-
metric[field] || metric[field.to_s]
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
# Re-derive entitlement usage / credit_remaining from the merged metrics
|
|
247
|
-
# and the just-updated credit balances. Mirrors schematic-python so that
|
|
248
|
-
# entitlement usage reflects DataStream track events immediately.
|
|
249
|
-
def sync_entitlements(entitlements, metrics, updated_balances, metrics_updated)
|
|
250
|
-
return entitlements unless entitlements.is_a?(Array) && !entitlements.empty?
|
|
251
|
-
|
|
252
|
-
metrics_lookup = {}
|
|
253
|
-
if metrics_updated && metrics.is_a?(Array)
|
|
254
|
-
metrics.each do |metric|
|
|
255
|
-
next unless metric.is_a?(Hash)
|
|
256
|
-
|
|
257
|
-
key = [
|
|
258
|
-
get_metric_field(metric, :event_subtype) || "",
|
|
259
|
-
get_metric_field(metric, :period) || "",
|
|
260
|
-
get_metric_field(metric, :month_reset) || ""
|
|
261
|
-
]
|
|
262
|
-
value = get_metric_field(metric, :value)
|
|
263
|
-
metrics_lookup[key] = value.nil? ? 0 : value
|
|
264
|
-
end
|
|
265
|
-
end
|
|
266
|
-
|
|
267
|
-
entitlements.map do |ent|
|
|
268
|
-
next ent unless ent.is_a?(Hash)
|
|
269
|
-
|
|
270
|
-
new_ent = deep_copy(ent)
|
|
271
|
-
|
|
272
|
-
credit_id = get_metric_field(ent, :credit_id)
|
|
273
|
-
if updated_balances && credit_id
|
|
274
|
-
present, balance = fetch_balance(updated_balances, credit_id)
|
|
275
|
-
new_ent[:credit_remaining] = balance if present
|
|
276
|
-
end
|
|
277
|
-
|
|
278
|
-
event_name = get_metric_field(ent, :event_name)
|
|
279
|
-
unless metrics_lookup.empty? || event_name.nil?
|
|
280
|
-
period = get_metric_field(ent, :metric_period) || "all_time"
|
|
281
|
-
month_reset = get_metric_field(ent, :month_reset) || "first_of_month"
|
|
282
|
-
matched = metrics_lookup[[event_name, period, month_reset]]
|
|
283
|
-
new_ent[:usage] = matched unless matched.nil?
|
|
284
|
-
end
|
|
285
|
-
|
|
286
|
-
new_ent
|
|
287
|
-
end
|
|
288
|
-
end
|
|
289
|
-
|
|
290
|
-
# credit_balances keys may be symbols (deep_copy symbolizes) while an
|
|
291
|
-
# entitlement's credit_id is always a string, so check both forms.
|
|
292
|
-
def fetch_balance(balances, credit_id)
|
|
293
|
-
return [true, balances[credit_id]] if balances.key?(credit_id)
|
|
294
|
-
return [true, balances[credit_id.to_sym]] if balances.key?(credit_id.to_sym)
|
|
295
|
-
return [true, balances[credit_id.to_s]] if balances.key?(credit_id.to_s)
|
|
296
|
-
|
|
297
|
-
[false, nil]
|
|
298
|
-
end
|
|
299
|
-
end
|
|
300
|
-
end
|
|
301
|
-
end
|
|
302
|
-
status: unresolved
|
|
303
|
-
- id: patch-46462128
|
|
304
|
-
content_hash: sha256:94f06e4e687a0908d3f305a4d605d9dc1271db6ed83014a10b86be900187dd83
|
|
305
|
-
original_commit: 46462128cacb25b73fac7770060cf427ff0d9e6d
|
|
306
|
-
original_message: add tests and address nits
|
|
307
|
-
original_author: Christopher Brady <chris@schematichq.com>
|
|
308
|
-
base_generation: e75de47f4e4f08f8e683366dd9b3936bc5c6452f
|
|
309
|
-
files:
|
|
310
|
-
- lib/schematic/datastream/merge.rb
|
|
311
|
-
patch_content: |
|
|
312
|
-
diff --git a/lib/schematic/datastream/merge.rb b/lib/schematic/datastream/merge.rb
|
|
313
|
-
index 7f1084d..f4dd4e5 100644
|
|
314
|
-
--- a/lib/schematic/datastream/merge.rb
|
|
315
|
-
+++ b/lib/schematic/datastream/merge.rb
|
|
316
|
-
@@ -46,7 +46,7 @@ module Schematic
|
|
317
|
-
end
|
|
318
|
-
end
|
|
319
|
-
|
|
320
|
-
- if (updated_balances || metrics_updated) && !entitlements_in_partial
|
|
321
|
-
+ if (updated_balances&.any? || metrics_updated) && !entitlements_in_partial
|
|
322
|
-
result[:entitlements] = sync_entitlements(
|
|
323
|
-
result[:entitlements], result[:metrics], updated_balances, metrics_updated
|
|
324
|
-
)
|
|
325
|
-
@@ -152,12 +152,12 @@ module Schematic
|
|
326
|
-
end
|
|
327
|
-
end
|
|
328
|
-
|
|
329
|
-
- # credit_balances keys may be symbols (deep_copy symbolizes) while an
|
|
330
|
-
- # entitlement's credit_id is always a string, so check both forms.
|
|
331
|
-
+ # The partial's credit_balances may be keyed by string or symbol depending
|
|
332
|
-
+ # on how the message was parsed, while an entitlement's credit_id is a
|
|
333
|
-
+ # string value, so check both key forms.
|
|
334
|
-
def fetch_balance(balances, credit_id)
|
|
335
|
-
return [true, balances[credit_id]] if balances.key?(credit_id)
|
|
336
|
-
return [true, balances[credit_id.to_sym]] if balances.key?(credit_id.to_sym)
|
|
337
|
-
- return [true, balances[credit_id.to_s]] if balances.key?(credit_id.to_s)
|
|
338
|
-
|
|
339
|
-
[false, nil]
|
|
340
|
-
end
|
|
341
|
-
theirs_snapshot:
|
|
342
|
-
lib/schematic/datastream/merge.rb: |
|
|
343
|
-
# frozen_string_literal: true
|
|
344
|
-
|
|
345
|
-
require "json"
|
|
346
|
-
|
|
347
|
-
module Schematic
|
|
348
|
-
module DataStream
|
|
349
|
-
module Merge
|
|
350
|
-
module_function
|
|
351
|
-
|
|
352
|
-
def deep_copy(obj)
|
|
353
|
-
JSON.parse(JSON.generate(obj), symbolize_names: true)
|
|
354
|
-
rescue StandardError
|
|
355
|
-
obj.dup
|
|
356
|
-
end
|
|
357
|
-
|
|
358
|
-
COMPANY_MAP_FIELDS = %i[credit_balances keys traits].freeze
|
|
359
|
-
COMPANY_ARRAY_FIELDS = %i[billing_product_ids entitlements plan_ids plan_version_ids rules].freeze
|
|
360
|
-
|
|
361
|
-
# Partials don't carry refreshed entitlements, so when their derived
|
|
362
|
-
# fields change in another part of the company we sync them here to match
|
|
363
|
-
# server behavior (see schematic-python merge.partial_company):
|
|
364
|
-
# - credit_remaining <- credit_balances[credit_id]
|
|
365
|
-
# - usage <- metric value matching (event_name, metric_period, month_reset)
|
|
366
|
-
# Both are skipped when the partial also sends entitlements wholesale.
|
|
367
|
-
def partial_company(existing, partial_data)
|
|
368
|
-
return existing unless partial_data.is_a?(Hash)
|
|
369
|
-
|
|
370
|
-
result = deep_copy(existing)
|
|
371
|
-
entitlements_in_partial = partial_data.key?(:entitlements) || partial_data.key?("entitlements")
|
|
372
|
-
updated_balances = nil
|
|
373
|
-
metrics_updated = false
|
|
374
|
-
|
|
375
|
-
partial_data.each do |key, value|
|
|
376
|
-
sym_key = key.to_sym
|
|
377
|
-
if COMPANY_MAP_FIELDS.include?(sym_key)
|
|
378
|
-
result[sym_key] ||= {}
|
|
379
|
-
result[sym_key] = result[sym_key].merge(value) if value.is_a?(Hash)
|
|
380
|
-
updated_balances = (value.is_a?(Hash) ? value : {}) if sym_key == :credit_balances
|
|
381
|
-
elsif COMPANY_ARRAY_FIELDS.include?(sym_key)
|
|
382
|
-
result[sym_key] = value if value.is_a?(Array)
|
|
383
|
-
elsif sym_key == :metrics
|
|
384
|
-
result[sym_key] = upsert_metrics(result[sym_key] || [], value || [])
|
|
385
|
-
metrics_updated = true
|
|
386
|
-
else
|
|
387
|
-
result[sym_key] = value
|
|
388
|
-
end
|
|
389
|
-
end
|
|
390
|
-
|
|
391
|
-
if (updated_balances&.any? || metrics_updated) && !entitlements_in_partial
|
|
392
|
-
result[:entitlements] = sync_entitlements(
|
|
393
|
-
result[:entitlements], result[:metrics], updated_balances, metrics_updated
|
|
394
|
-
)
|
|
395
|
-
end
|
|
396
|
-
|
|
397
|
-
result
|
|
398
|
-
end
|
|
399
|
-
|
|
400
|
-
USER_MAP_FIELDS = %i[keys traits].freeze
|
|
401
|
-
|
|
402
|
-
def partial_user(existing, partial_data)
|
|
403
|
-
return existing unless partial_data.is_a?(Hash)
|
|
404
|
-
|
|
405
|
-
result = deep_copy(existing)
|
|
406
|
-
|
|
407
|
-
partial_data.each do |key, value|
|
|
408
|
-
sym_key = key.to_sym
|
|
409
|
-
if USER_MAP_FIELDS.include?(sym_key)
|
|
410
|
-
result[sym_key] ||= {}
|
|
411
|
-
result[sym_key] = result[sym_key].merge(value) if value.is_a?(Hash)
|
|
412
|
-
elsif sym_key == :rules
|
|
413
|
-
result[sym_key] = value if value.is_a?(Array)
|
|
414
|
-
else
|
|
415
|
-
result[sym_key] = value
|
|
416
|
-
end
|
|
417
|
-
end
|
|
418
|
-
|
|
419
|
-
result
|
|
420
|
-
end
|
|
421
|
-
|
|
422
|
-
def upsert_metrics(existing, incoming)
|
|
423
|
-
return incoming if existing.nil? || existing.empty?
|
|
424
|
-
return existing if incoming.nil? || incoming.empty?
|
|
425
|
-
|
|
426
|
-
result = existing.map { |metric| deep_copy(metric) }
|
|
427
|
-
|
|
428
|
-
incoming.each do |inc_metric|
|
|
429
|
-
match_idx = result.index do |ex|
|
|
430
|
-
metrics_match?(ex, inc_metric)
|
|
431
|
-
end
|
|
432
|
-
|
|
433
|
-
if match_idx
|
|
434
|
-
result[match_idx] = inc_metric
|
|
435
|
-
else
|
|
436
|
-
result << inc_metric
|
|
437
|
-
end
|
|
438
|
-
end
|
|
439
|
-
|
|
440
|
-
result
|
|
441
|
-
end
|
|
442
|
-
|
|
443
|
-
def metrics_match?(left, right)
|
|
444
|
-
get_metric_field(left, :event_subtype) == get_metric_field(right, :event_subtype) &&
|
|
445
|
-
get_metric_field(left, :period) == get_metric_field(right, :period) &&
|
|
446
|
-
get_metric_field(left, :month_reset) == get_metric_field(right, :month_reset)
|
|
447
|
-
end
|
|
448
|
-
|
|
449
|
-
def get_metric_field(metric, field)
|
|
450
|
-
metric[field] || metric[field.to_s]
|
|
451
|
-
end
|
|
452
|
-
|
|
453
|
-
# Re-derive entitlement usage / credit_remaining from the merged metrics
|
|
454
|
-
# and the just-updated credit balances. Mirrors schematic-python so that
|
|
455
|
-
# entitlement usage reflects DataStream track events immediately.
|
|
456
|
-
def sync_entitlements(entitlements, metrics, updated_balances, metrics_updated)
|
|
457
|
-
return entitlements unless entitlements.is_a?(Array) && !entitlements.empty?
|
|
458
|
-
|
|
459
|
-
metrics_lookup = {}
|
|
460
|
-
if metrics_updated && metrics.is_a?(Array)
|
|
461
|
-
metrics.each do |metric|
|
|
462
|
-
next unless metric.is_a?(Hash)
|
|
463
|
-
|
|
464
|
-
key = [
|
|
465
|
-
get_metric_field(metric, :event_subtype) || "",
|
|
466
|
-
get_metric_field(metric, :period) || "",
|
|
467
|
-
get_metric_field(metric, :month_reset) || ""
|
|
468
|
-
]
|
|
469
|
-
value = get_metric_field(metric, :value)
|
|
470
|
-
metrics_lookup[key] = value.nil? ? 0 : value
|
|
471
|
-
end
|
|
472
|
-
end
|
|
473
|
-
|
|
474
|
-
entitlements.map do |ent|
|
|
475
|
-
next ent unless ent.is_a?(Hash)
|
|
476
|
-
|
|
477
|
-
new_ent = deep_copy(ent)
|
|
478
|
-
|
|
479
|
-
credit_id = get_metric_field(ent, :credit_id)
|
|
480
|
-
if updated_balances && credit_id
|
|
481
|
-
present, balance = fetch_balance(updated_balances, credit_id)
|
|
482
|
-
new_ent[:credit_remaining] = balance if present
|
|
483
|
-
end
|
|
484
|
-
|
|
485
|
-
event_name = get_metric_field(ent, :event_name)
|
|
486
|
-
unless metrics_lookup.empty? || event_name.nil?
|
|
487
|
-
period = get_metric_field(ent, :metric_period) || "all_time"
|
|
488
|
-
month_reset = get_metric_field(ent, :month_reset) || "first_of_month"
|
|
489
|
-
matched = metrics_lookup[[event_name, period, month_reset]]
|
|
490
|
-
new_ent[:usage] = matched unless matched.nil?
|
|
491
|
-
end
|
|
492
|
-
|
|
493
|
-
new_ent
|
|
494
|
-
end
|
|
495
|
-
end
|
|
496
|
-
|
|
497
|
-
# The partial's credit_balances may be keyed by string or symbol depending
|
|
498
|
-
# on how the message was parsed, while an entitlement's credit_id is a
|
|
499
|
-
# string value, so check both key forms.
|
|
500
|
-
def fetch_balance(balances, credit_id)
|
|
501
|
-
return [true, balances[credit_id]] if balances.key?(credit_id)
|
|
502
|
-
return [true, balances[credit_id.to_sym]] if balances.key?(credit_id.to_sym)
|
|
503
|
-
|
|
504
|
-
[false, nil]
|
|
505
|
-
end
|
|
506
|
-
end
|
|
507
|
-
end
|
|
508
|
-
end
|
|
509
|
-
status: unresolved
|
|
15
|
+
- commit_sha: 3f7bc10e75ced0491ab79b97ad6728099789257f
|
|
16
|
+
tree_hash: c0da19d256703af10c64a60eb7b5bac46c309176
|
|
17
|
+
timestamp: 2026-06-16T15:23:35.904Z
|
|
18
|
+
cli_version: unknown
|
|
19
|
+
generator_versions:
|
|
20
|
+
fernapi/fern-ruby-sdk: 1.1.13
|
|
21
|
+
- commit_sha: 7ff89cac80a7358534185779ed4992b755919d97
|
|
22
|
+
tree_hash: 0067d3b0febf9fcc16a4e73c0b6df32358a38c52
|
|
23
|
+
timestamp: 2026-06-22T12:02:24.084Z
|
|
24
|
+
cli_version: unknown
|
|
25
|
+
generator_versions:
|
|
26
|
+
fernapi/fern-ruby-sdk: 1.1.13
|
|
27
|
+
- commit_sha: 8487841eae05855059210650ab3ee913538f1afc
|
|
28
|
+
tree_hash: 391a12403ced58b9d8dfaa76de05467a95b1b8f9
|
|
29
|
+
timestamp: 2026-06-22T18:51:25.550Z
|
|
30
|
+
cli_version: unknown
|
|
31
|
+
generator_versions:
|
|
32
|
+
fernapi/fern-ruby-sdk: 1.1.13
|
|
33
|
+
current_generation: 8487841eae05855059210650ab3ee913538f1afc
|
|
34
|
+
patches: []
|
data/WASM_VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.4.0
|