draftgo-cli 4.0.1 → 4.0.23

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.
Files changed (79) hide show
  1. package/README.md +87 -11
  2. package/package.json +9 -4
  3. package/resources/custom-service-sdk/ai.go +520 -0
  4. package/resources/custom-service-sdk/ai_test.go +156 -0
  5. package/resources/custom-service-sdk/auth_test.go +56 -0
  6. package/resources/custom-service-sdk/billing.go +596 -0
  7. package/resources/custom-service-sdk/billing_test.go +150 -0
  8. package/resources/custom-service-sdk/go.mod +3 -0
  9. package/resources/custom-service-sdk/manifest.json +77 -0
  10. package/resources/custom-service-sdk/platform.go +345 -0
  11. package/resources/custom-service-sdk/platform_logger_test.go +24 -0
  12. package/resources/custom-service-sdk/registration_test.go +39 -0
  13. package/resources/custom-service-sdk/resources.go +246 -0
  14. package/resources/custom-service-sdk/resources_billing_test.go +115 -0
  15. package/resources/custom-service-sdk/resources_files_test.go +57 -0
  16. package/resources/custom-service-sdk/resources_scope_test.go +87 -0
  17. package/resources/custom-service-sdk/sdk.go +208 -0
  18. package/resources/skill/SKILL.md +36 -88
  19. package/resources/skill/init/SKILL.md +4 -4
  20. package/resources/skill/manifest.json +5 -1
  21. package/resources/skill/references/aihub.md +25 -2
  22. package/resources/skill/references/app-api.md +56 -6
  23. package/resources/skill/references/architecture.md +2 -2
  24. package/resources/skill/references/chat-sdk.md +4 -2
  25. package/resources/skill/references/checkout.md +17 -3
  26. package/resources/skill/references/custom-services.md +112 -47
  27. package/resources/skill/references/data.md +19 -4
  28. package/resources/skill/references/delivery.md +33 -0
  29. package/resources/skill/references/diagnostics.md +51 -0
  30. package/resources/skill/references/frontend.md +34 -46
  31. package/resources/skill/references/mcp.md +33 -5
  32. package/resources/skill/references/methods.md +189 -0
  33. package/resources/skill/references/modules.md +37 -9
  34. package/resources/skill/references/runtime.md +23 -1
  35. package/src/cli.js +24 -0
  36. package/src/commandRegistry.js +9 -1
  37. package/src/commands/api.js +21 -10
  38. package/src/commands/apiKey.js +34 -0
  39. package/src/commands/capabilities.js +93 -0
  40. package/src/commands/checkout.js +1 -1
  41. package/src/commands/commit.js +1 -1
  42. package/src/commands/components.js +550 -0
  43. package/src/commands/conflict.js +1 -1
  44. package/src/commands/connect.js +18 -8
  45. package/src/commands/customService.js +20 -4
  46. package/src/commands/dataRange.js +33 -0
  47. package/src/commands/delete.js +12 -1
  48. package/src/commands/diff.js +18 -2
  49. package/src/commands/grant.js +29 -0
  50. package/src/commands/group.js +38 -0
  51. package/src/commands/help.js +64 -20
  52. package/src/commands/init.js +3 -3
  53. package/src/commands/map.js +145 -17
  54. package/src/commands/mcp.js +2 -2
  55. package/src/commands/reconcile.js +1 -1
  56. package/src/commands/role.js +32 -0
  57. package/src/commands/space.js +41 -0
  58. package/src/commands/status.js +110 -7
  59. package/src/commands/update.js +23 -11
  60. package/src/commands/verify.js +75 -0
  61. package/src/commands/worklog.js +6 -2
  62. package/src/consoleEncoding.js +34 -0
  63. package/src/contractCompatibility.js +57 -0
  64. package/src/customServices.js +138 -18
  65. package/src/diffReport.js +106 -0
  66. package/src/index.js +2 -0
  67. package/src/localRuntime/compose.js +14 -17
  68. package/src/localRuntime/index.js +22 -23
  69. package/src/localRuntime/services.js +27 -36
  70. package/src/mcp/client.js +11 -2
  71. package/src/mcp/protocol.js +22 -2
  72. package/src/mcp/tools.js +14 -1
  73. package/src/platforms.js +9 -0
  74. package/src/projectConfig.js +6 -4
  75. package/src/releaseInstall.js +105 -0
  76. package/src/updateCheck.js +48 -28
  77. package/src/worklog.js +2 -1
  78. package/src/worktree/backend.js +1 -1
  79. package/src/worktree/index.js +7 -2
@@ -0,0 +1,56 @@
1
+ package sdk
2
+
3
+ import (
4
+ "context"
5
+ "errors"
6
+ "testing"
7
+ )
8
+
9
+ type authRecordingClient struct {
10
+ operation string
11
+ args map[string]any
12
+ err error
13
+ }
14
+
15
+ func (client *authRecordingClient) Call(_ context.Context, operation string, args any) (any, error) {
16
+ client.operation = operation
17
+ client.args, _ = args.(map[string]any)
18
+ return true, client.err
19
+ }
20
+
21
+ func TestAuthAssertionsUseHostAuthorization(t *testing.T) {
22
+ client := &authRecordingClient{}
23
+ draftgo := NewContext(context.Background(), nil, map[string]any{
24
+ "id": float64(7), "is_admin": false, "role_code": "member",
25
+ }, nil, client)
26
+
27
+ if err := draftgo.Auth.RequireAdmin(); err != nil {
28
+ t.Fatal(err)
29
+ }
30
+ if client.operation != "auth.require_admin" {
31
+ t.Fatalf("operation = %q", client.operation)
32
+ }
33
+ if err := draftgo.Auth.RequireRole(" workspace_owner "); err != nil {
34
+ t.Fatal(err)
35
+ }
36
+ if client.operation != "auth.require_role" || client.args["role"] != "workspace_owner" {
37
+ t.Fatalf("operation=%q args=%#v", client.operation, client.args)
38
+ }
39
+
40
+ client.err = errors.New("denied by host")
41
+ if err := draftgo.Auth.RequireAdmin(); err == nil || err.Error() != "denied by host" {
42
+ t.Fatalf("host denial was not returned: %v", err)
43
+ }
44
+ }
45
+
46
+ func TestAdminAuthCallCarriesScopedElevation(t *testing.T) {
47
+ client := &authRecordingClient{}
48
+ draftgo := NewContext(context.Background(), nil, nil, nil, client)
49
+
50
+ if err := draftgo.Admin.Auth.RequireAdmin(); err != nil {
51
+ t.Fatal(err)
52
+ }
53
+ if client.operation != "auth.require_admin" || client.args["__draftgo_admin"] != true {
54
+ t.Fatalf("operation=%q args=%#v", client.operation, client.args)
55
+ }
56
+ }
@@ -0,0 +1,596 @@
1
+ package sdk
2
+
3
+ import (
4
+ "context"
5
+ )
6
+
7
+ // BillingAPI is the stable money/payment/entitlement and AI usage boundary
8
+ // for custom services. Product catalog and checkout rules remain service-owned.
9
+ type BillingAPI interface {
10
+ CreatePaymentOrder(context.Context, PaymentOrderRequest) (PaymentIntent, error)
11
+ QueryPaymentOrder(context.Context, string) (PaymentOrder, error)
12
+ ClosePaymentOrder(context.Context, string) error
13
+ RefundPaymentOrder(context.Context, RefundRequest) (map[string]any, error)
14
+ ListPaymentRefunds(context.Context, string) (map[string]any, error)
15
+ ListPaymentOrders(context.Context, map[string]any) (map[string]any, error)
16
+ GetAccount(context.Context) (Account, error)
17
+ ListJournal(context.Context, map[string]any) (map[string]any, error)
18
+ CreditAccount(context.Context, MoneyOperationRequest) (JournalResult, error)
19
+ DebitAccount(context.Context, MoneyOperationRequest) (JournalResult, error)
20
+ HoldFunds(context.Context, MoneyOperationRequest) (HoldResult, error)
21
+ SettleHold(context.Context, HoldOperationRequest) (JournalResult, error)
22
+ ReleaseHold(context.Context, HoldOperationRequest) error
23
+ ReverseJournal(context.Context, ReversalRequest) (JournalResult, error)
24
+ GrantEntitlement(context.Context, EntitlementGrantRequest) (map[string]any, error)
25
+ ConsumeEntitlement(context.Context, EntitlementConsumeRequest) (map[string]any, error)
26
+ RevokeEntitlement(context.Context, EntitlementRevokeRequest) error
27
+ ListEntitlements(context.Context, BillingSubject, map[string]any) (map[string]any, error)
28
+ CreatePlan(context.Context, PlanRequest) (Plan, error)
29
+ GetPlan(context.Context, int64) (Plan, error)
30
+ ListPlans(context.Context, PlanQuery) ([]Plan, error)
31
+ UpdatePlan(context.Context, int64, PlanUpdateRequest) (Plan, error)
32
+ SetPlanStatus(context.Context, int64, string) (Plan, error)
33
+ CreateSubscription(context.Context, SubscriptionRequest) (Subscription, error)
34
+ GetSubscription(context.Context, int64) (Subscription, error)
35
+ ListSubscriptions(context.Context, SubscriptionQuery) ([]Subscription, error)
36
+ ChangeSubscriptionPlan(context.Context, int64, SubscriptionChangeRequest) (Subscription, error)
37
+ PauseSubscription(context.Context, int64) (Subscription, error)
38
+ ResumeSubscription(context.Context, int64) (Subscription, error)
39
+ CancelSubscription(context.Context, int64) (Subscription, error)
40
+ FulfillSubscriptionPayment(context.Context, SubscriptionPaymentFulfillmentRequest) (Subscription, error)
41
+ GetAIPricing(context.Context, map[string]any) (map[string]any, error)
42
+ ListAIPriceVersions(context.Context, map[string]any) (map[string]any, error)
43
+ CreateAIPriceVersion(context.Context, AIPriceVersionRequest) (AIPriceVersion, error)
44
+ EstimateAI(context.Context, AIEstimateRequest) (AIEstimate, error)
45
+ StartAIBilling(context.Context, AIBillingStartRequest) (AIBillingSession, error)
46
+ SettleAIBilling(context.Context, AISettlementRequest) (AIBillingSession, error)
47
+ CancelAIBilling(context.Context, string, string) error
48
+ GetAIUsage(context.Context, map[string]any) (map[string]any, error)
49
+ GetAICosts(context.Context, map[string]any) (map[string]any, error)
50
+ }
51
+
52
+ var _ BillingAPI = billingClient{}
53
+
54
+ type PaymentOrderRequest struct {
55
+ BusinessOrderID string `json:"business_order_id"`
56
+ ProductRef string `json:"product_ref,omitempty"`
57
+ FulfillmentRef string `json:"fulfillment_ref,omitempty"`
58
+ AmountMinor int64 `json:"amount_minor"`
59
+ Provider string `json:"provider,omitempty"`
60
+ Description string `json:"description,omitempty"`
61
+ ReturnURL string `json:"return_url,omitempty"`
62
+ NotifyURL string `json:"notify_url,omitempty"`
63
+ IdempotencyKey string `json:"idempotency_key"`
64
+ Metadata map[string]any `json:"metadata,omitempty"`
65
+ }
66
+
67
+ type PaymentIntent struct {
68
+ OrderID string `json:"order_id"`
69
+ Provider string `json:"provider"`
70
+ Status string `json:"status"`
71
+ AmountMinor int64 `json:"amount_minor"`
72
+ PayURL string `json:"pay_url,omitempty"`
73
+ QRCode string `json:"qr_code,omitempty"`
74
+ Params map[string]any `json:"params,omitempty"`
75
+ }
76
+ type PaymentOrder struct {
77
+ ID string `json:"id"`
78
+ BusinessOrderID string `json:"business_order_id"`
79
+ Ownership ResourceOwnership `json:"ownership"`
80
+ PayerUserID int64 `json:"payer_user_id"`
81
+ CreatedBy int64 `json:"created_by"`
82
+ Provider string `json:"provider"`
83
+ ProviderTradeNo string `json:"provider_trade_no,omitempty"`
84
+ Status string `json:"status"`
85
+ AmountMinor int64 `json:"amount_minor"`
86
+ ProductRef string `json:"product_ref,omitempty"`
87
+ FulfillmentRef string `json:"fulfillment_ref,omitempty"`
88
+ Metadata map[string]any `json:"metadata,omitempty"`
89
+ ExpiresAt string `json:"expires_at,omitempty"`
90
+ PaidAt string `json:"paid_at,omitempty"`
91
+ CreatedAt string `json:"created_at,omitempty"`
92
+ UpdatedAt string `json:"updated_at,omitempty"`
93
+ }
94
+ type RefundRequest struct {
95
+ PaymentOrderID string `json:"payment_order_id"`
96
+ AmountMinor int64 `json:"amount_minor,omitempty"`
97
+ Reason string `json:"reason,omitempty"`
98
+ IdempotencyKey string `json:"idempotency_key"`
99
+ }
100
+ type Account struct {
101
+ BalanceMinor int64 `json:"balance_minor"`
102
+ AvailableMinor int64 `json:"available_minor"`
103
+ }
104
+ type MoneyOperationRequest struct {
105
+ AmountMinor int64 `json:"amount_minor"`
106
+ Reference string `json:"reference,omitempty"`
107
+ Reason string `json:"reason,omitempty"`
108
+ IdempotencyKey string `json:"idempotency_key"`
109
+ RequestID string `json:"request_id,omitempty"`
110
+ ExpiresAt string `json:"expires_at,omitempty"`
111
+ Metadata map[string]any `json:"metadata,omitempty"`
112
+ }
113
+ type JournalResult struct {
114
+ JournalID string `json:"journal_id"`
115
+ BalanceMinor int64 `json:"balance_minor"`
116
+ }
117
+ type HoldResult struct {
118
+ HoldID string `json:"hold_id"`
119
+ AmountMinor int64 `json:"amount_minor"`
120
+ AvailableMinor int64 `json:"available_minor"`
121
+ }
122
+ type HoldOperationRequest struct {
123
+ HoldID string `json:"hold_id"`
124
+ AmountMinor int64 `json:"amount_minor,omitempty"`
125
+ Reason string `json:"reason,omitempty"`
126
+ IdempotencyKey string `json:"idempotency_key"`
127
+ Metadata map[string]any `json:"metadata,omitempty"`
128
+ }
129
+ type ReversalRequest struct {
130
+ JournalID string `json:"journal_id"`
131
+ Reason string `json:"reason"`
132
+ IdempotencyKey string `json:"idempotency_key"`
133
+ Metadata map[string]any `json:"metadata,omitempty"`
134
+ }
135
+ type EntitlementGrantRequest struct {
136
+ Subject BillingSubject `json:"subject"`
137
+ Code string `json:"code"`
138
+ Quantity int64 `json:"quantity"`
139
+ ExpiresAt string `json:"expires_at,omitempty"`
140
+ SourceRef string `json:"source_ref,omitempty"`
141
+ IdempotencyKey string `json:"idempotency_key"`
142
+ }
143
+ type EntitlementConsumeRequest struct {
144
+ Subject BillingSubject `json:"subject"`
145
+ Code string `json:"code"`
146
+ Quantity int64 `json:"quantity"`
147
+ Reference string `json:"reference,omitempty"`
148
+ IdempotencyKey string `json:"idempotency_key"`
149
+ }
150
+ type EntitlementRevokeRequest struct {
151
+ Subject BillingSubject `json:"subject"`
152
+ Code string `json:"code"`
153
+ Quantity int64 `json:"quantity,omitempty"`
154
+ Reference string `json:"reference,omitempty"`
155
+ IdempotencyKey string `json:"idempotency_key"`
156
+ }
157
+
158
+ type BillingSubject struct {
159
+ Type string `json:"subject_type"`
160
+ ID string `json:"subject_id"`
161
+ }
162
+
163
+ type PlanRequest struct {
164
+ Code string `json:"code"`
165
+ Name string `json:"name"`
166
+ Status string `json:"status,omitempty"`
167
+ PriceMinor int64 `json:"price_minor"`
168
+ BillingCycle string `json:"billing_cycle"`
169
+ Entitlements map[string]any `json:"entitlements,omitempty"`
170
+ }
171
+
172
+ type PlanUpdateRequest struct {
173
+ Name *string `json:"name,omitempty"`
174
+ Status *string `json:"status,omitempty"`
175
+ PriceMinor *int64 `json:"price_minor,omitempty"`
176
+ BillingCycle *string `json:"billing_cycle,omitempty"`
177
+ Entitlements *map[string]any `json:"entitlements,omitempty"`
178
+ }
179
+
180
+ type PlanQuery struct {
181
+ Status string `json:"status,omitempty"`
182
+ Search string `json:"search,omitempty"`
183
+ }
184
+
185
+ type Plan struct {
186
+ ID int64 `json:"id"`
187
+ Code string `json:"code"`
188
+ Name string `json:"name"`
189
+ Status string `json:"status"`
190
+ PriceMinor int64 `json:"price_minor"`
191
+ BillingCycle string `json:"billing_cycle"`
192
+ Entitlements map[string]any `json:"entitlements"`
193
+ CreatedAt string `json:"created_at"`
194
+ UpdatedAt string `json:"updated_at"`
195
+ }
196
+
197
+ type SubscriptionRequest struct {
198
+ PlanID int64 `json:"plan_id"`
199
+ Subject BillingSubject `json:"subject"`
200
+ CurrentPeriodStart string `json:"current_period_start,omitempty"`
201
+ CurrentPeriodEnd string `json:"current_period_end,omitempty"`
202
+ SourceType string `json:"source_type,omitempty"`
203
+ SourceID string `json:"source_id,omitempty"`
204
+ IdempotencyKey string `json:"idempotency_key"`
205
+ }
206
+
207
+ type SubscriptionChangeRequest struct {
208
+ PlanID int64 `json:"plan_id"`
209
+ CurrentPeriodStart string `json:"current_period_start,omitempty"`
210
+ CurrentPeriodEnd string `json:"current_period_end,omitempty"`
211
+ }
212
+
213
+ type SubscriptionPaymentFulfillmentRequest struct {
214
+ PaymentOrderID string `json:"payment_order_id"`
215
+ PlanID int64 `json:"plan_id"`
216
+ }
217
+
218
+ type SubscriptionQuery struct {
219
+ PlanID int64 `json:"plan_id,omitempty"`
220
+ Status string `json:"status,omitempty"`
221
+ SubjectType string `json:"subject_type,omitempty"`
222
+ SubjectID string `json:"subject_id,omitempty"`
223
+ }
224
+
225
+ type Subscription struct {
226
+ ID int64 `json:"id"`
227
+ PlanID int64 `json:"plan_id"`
228
+ Subject BillingSubject `json:"subject"`
229
+ CreatedBy int64 `json:"created_by"`
230
+ Status string `json:"status"`
231
+ CurrentPeriodStart string `json:"current_period_start"`
232
+ CurrentPeriodEnd string `json:"current_period_end"`
233
+ SourceType string `json:"source_type"`
234
+ SourceID string `json:"source_id"`
235
+ IdempotencyKey string `json:"idempotency_key"`
236
+ CreatedAt string `json:"created_at"`
237
+ UpdatedAt string `json:"updated_at"`
238
+ }
239
+
240
+ type AIEstimateRequest struct {
241
+ ModelID int64 `json:"model_id,omitempty"`
242
+ Model string `json:"model,omitempty"`
243
+ AgentID int64 `json:"agent_id,omitempty"`
244
+ Mode string `json:"mode,omitempty"`
245
+ InputTokens int64 `json:"input_tokens,omitempty"`
246
+ OutputTokens int64 `json:"output_tokens,omitempty"`
247
+ Requests int64 `json:"requests,omitempty"`
248
+ ImageUnits int64 `json:"image_units,omitempty"`
249
+ AudioSeconds int64 `json:"audio_seconds,omitempty"`
250
+ }
251
+ type AIPriceVersionRequest struct {
252
+ Model string `json:"model_key,omitempty"`
253
+ Agent string `json:"agent_key,omitempty"`
254
+ Version string `json:"version"`
255
+ BillingMode string `json:"billing_mode"`
256
+ BillingEnabled bool `json:"billing_enabled"`
257
+ InputPriceMinorPerMillion int64 `json:"input_price_minor_per_million,omitempty"`
258
+ OutputPriceMinorPerMillion int64 `json:"output_price_minor_per_million,omitempty"`
259
+ CachedInputPriceMinorPerMillion int64 `json:"cached_input_price_minor_per_million,omitempty"`
260
+ CacheCreationPriceMinorPerMillion int64 `json:"cache_creation_price_minor_per_million,omitempty"`
261
+ ImagePriceMinor int64 `json:"image_price_minor,omitempty"`
262
+ AudioPriceMinor int64 `json:"audio_price_minor,omitempty"`
263
+ AudioOutputPriceMinor int64 `json:"audio_output_price_minor,omitempty"`
264
+ RequestPriceMinor int64 `json:"request_price_minor,omitempty"`
265
+ ProviderCostMode string `json:"provider_cost_mode,omitempty"`
266
+ ProviderInputCostMinorPerMillion int64 `json:"provider_input_cost_minor_per_million,omitempty"`
267
+ ProviderOutputCostMinorPerMillion int64 `json:"provider_output_cost_minor_per_million,omitempty"`
268
+ ProviderCachedInputCostMinorPerMillion int64 `json:"provider_cached_input_cost_minor_per_million,omitempty"`
269
+ ProviderCacheCreationCostMinorPerMillion int64 `json:"provider_cache_creation_cost_minor_per_million,omitempty"`
270
+ ProviderImageCostMinor int64 `json:"provider_image_cost_minor,omitempty"`
271
+ ProviderAudioCostMinor int64 `json:"provider_audio_cost_minor,omitempty"`
272
+ ProviderAudioOutputCostMinor int64 `json:"provider_audio_output_cost_minor,omitempty"`
273
+ ProviderRequestCostMinor int64 `json:"provider_request_cost_minor,omitempty"`
274
+ }
275
+ type AIPriceVersion struct {
276
+ ID string `json:"id"`
277
+ Model string `json:"model_key"`
278
+ Agent string `json:"agent_key"`
279
+ Version string `json:"version"`
280
+ BillingMode string `json:"billing_mode"`
281
+ BillingEnabled bool `json:"billing_enabled"`
282
+ InputPriceMinorPerMillion int64 `json:"input_price_minor_per_million"`
283
+ OutputPriceMinorPerMillion int64 `json:"output_price_minor_per_million"`
284
+ CachedInputPriceMinorPerMillion int64 `json:"cached_input_price_minor_per_million"`
285
+ CacheCreationPriceMinorPerMillion int64 `json:"cache_creation_price_minor_per_million"`
286
+ ImagePriceMinor int64 `json:"image_price_minor"`
287
+ AudioPriceMinor int64 `json:"audio_price_minor"`
288
+ AudioOutputPriceMinor int64 `json:"audio_output_price_minor"`
289
+ RequestPriceMinor int64 `json:"request_price_minor"`
290
+ ProviderCostMode string `json:"provider_cost_mode"`
291
+ ProviderInputCostMinorPerMillion int64 `json:"provider_input_cost_minor_per_million"`
292
+ ProviderOutputCostMinorPerMillion int64 `json:"provider_output_cost_minor_per_million"`
293
+ ProviderCachedInputCostMinorPerMillion int64 `json:"provider_cached_input_cost_minor_per_million"`
294
+ ProviderCacheCreationCostMinorPerMillion int64 `json:"provider_cache_creation_cost_minor_per_million"`
295
+ ProviderImageCostMinor int64 `json:"provider_image_cost_minor"`
296
+ ProviderAudioCostMinor int64 `json:"provider_audio_cost_minor"`
297
+ ProviderAudioOutputCostMinor int64 `json:"provider_audio_output_cost_minor"`
298
+ ProviderRequestCostMinor int64 `json:"provider_request_cost_minor"`
299
+ Status string `json:"status"`
300
+ EffectiveFrom string `json:"effective_from,omitempty"`
301
+ }
302
+
303
+ type AIEstimate struct {
304
+ AmountMinor int64 `json:"amount_minor"`
305
+ PriceVersion string `json:"price_version"`
306
+ Breakdown map[string]any `json:"breakdown,omitempty"`
307
+ }
308
+ type AIBillingStartRequest struct {
309
+ IdempotencyKey string `json:"idempotency_key"`
310
+ RequestID string `json:"request_id,omitempty"`
311
+ AgentID int64 `json:"agent_id,omitempty"`
312
+ ModelID int64 `json:"model_id,omitempty"`
313
+ Model string `json:"model,omitempty"`
314
+ EstimatedMinor int64 `json:"estimated_minor,omitempty"`
315
+ Metadata map[string]any `json:"metadata,omitempty"`
316
+ }
317
+ type AIBillingSession struct {
318
+ ID string `json:"id"`
319
+ Status string `json:"status"`
320
+ ReservedMinor int64 `json:"reserved_minor"`
321
+ SettledMinor int64 `json:"settled_minor"`
322
+ PriceVersion string `json:"price_version"`
323
+ }
324
+ type AISettlementRequest struct {
325
+ SessionID string `json:"session_id"`
326
+ Usage map[string]any `json:"usage"`
327
+ ActualMinor int64 `json:"actual_minor,omitempty"`
328
+ Status string `json:"status,omitempty"`
329
+ IdempotencyKey string `json:"idempotency_key"`
330
+ Metadata map[string]any `json:"metadata,omitempty"`
331
+ }
332
+
333
+ type billingClient struct{ platformClient }
334
+
335
+ func (p billingClient) request(ctx context.Context, operation string, args any) (map[string]any, error) {
336
+ value, err := p.call(ctx, operation, args)
337
+ return mapResult(value), err
338
+ }
339
+ func (p billingClient) CreatePaymentOrder(ctx context.Context, in PaymentOrderRequest) (PaymentIntent, error) {
340
+ value, err := p.request(ctx, "billing.payment.create", in)
341
+ return paymentIntent(value), err
342
+ }
343
+ func (p billingClient) QueryPaymentOrder(ctx context.Context, id string) (PaymentOrder, error) {
344
+ value, err := p.request(ctx, "billing.payment.query", map[string]any{"order_id": id})
345
+ return paymentOrder(value), err
346
+ }
347
+ func (p billingClient) ClosePaymentOrder(ctx context.Context, id string) error {
348
+ _, err := p.request(ctx, "billing.payment.close", map[string]any{"order_id": id})
349
+ return err
350
+ }
351
+ func (p billingClient) RefundPaymentOrder(ctx context.Context, in RefundRequest) (map[string]any, error) {
352
+ return p.request(ctx, "billing.payment.refund", in)
353
+ }
354
+ func (p billingClient) ListPaymentRefunds(ctx context.Context, orderID string) (map[string]any, error) {
355
+ return p.request(ctx, "billing.payment.refunds.list", map[string]any{"payment_order_id": orderID})
356
+ }
357
+ func (p billingClient) ListPaymentOrders(ctx context.Context, query map[string]any) (map[string]any, error) {
358
+ return p.request(ctx, "billing.payment.list", map[string]any{"query": query})
359
+ }
360
+ func (p billingClient) GetAccount(ctx context.Context) (Account, error) {
361
+ value, err := p.request(ctx, "billing.account.get", map[string]any{})
362
+ return account(value), err
363
+ }
364
+ func (p billingClient) ListJournal(ctx context.Context, query map[string]any) (map[string]any, error) {
365
+ return p.request(ctx, "billing.journal.list", map[string]any{"query": query})
366
+ }
367
+ func (p billingClient) CreditAccount(ctx context.Context, in MoneyOperationRequest) (JournalResult, error) {
368
+ value, err := p.request(ctx, "billing.account.credit", in)
369
+ return journalResult(value), err
370
+ }
371
+ func (p billingClient) DebitAccount(ctx context.Context, in MoneyOperationRequest) (JournalResult, error) {
372
+ value, err := p.request(ctx, "billing.account.debit", in)
373
+ return journalResult(value), err
374
+ }
375
+ func (p billingClient) HoldFunds(ctx context.Context, in MoneyOperationRequest) (HoldResult, error) {
376
+ value, err := p.request(ctx, "billing.account.hold", in)
377
+ return holdResult(value), err
378
+ }
379
+ func (p billingClient) SettleHold(ctx context.Context, in HoldOperationRequest) (JournalResult, error) {
380
+ value, err := p.request(ctx, "billing.account.hold.settle", in)
381
+ return journalResult(value), err
382
+ }
383
+ func (p billingClient) ReleaseHold(ctx context.Context, in HoldOperationRequest) error {
384
+ _, err := p.request(ctx, "billing.account.hold.release", in)
385
+ return err
386
+ }
387
+ func (p billingClient) ReverseJournal(ctx context.Context, in ReversalRequest) (JournalResult, error) {
388
+ value, err := p.request(ctx, "billing.journal.reverse", in)
389
+ return journalResult(value), err
390
+ }
391
+ func (p billingClient) GrantEntitlement(ctx context.Context, in EntitlementGrantRequest) (map[string]any, error) {
392
+ return p.request(ctx, "billing.entitlement.grant", in)
393
+ }
394
+ func (p billingClient) ConsumeEntitlement(ctx context.Context, in EntitlementConsumeRequest) (map[string]any, error) {
395
+ return p.request(ctx, "billing.entitlement.consume", in)
396
+ }
397
+ func (p billingClient) RevokeEntitlement(ctx context.Context, in EntitlementRevokeRequest) error {
398
+ _, err := p.request(ctx, "billing.entitlement.revoke", in)
399
+ return err
400
+ }
401
+ func (p billingClient) ListEntitlements(ctx context.Context, subject BillingSubject, query map[string]any) (map[string]any, error) {
402
+ return p.request(ctx, "billing.entitlement.list", map[string]any{"subject_type": subject.Type, "subject_id": subject.ID, "query": query})
403
+ }
404
+ func (p billingClient) CreatePlan(ctx context.Context, in PlanRequest) (Plan, error) {
405
+ value, err := p.request(ctx, "billing.plan.create", in)
406
+ return billingPlan(value), err
407
+ }
408
+ func (p billingClient) GetPlan(ctx context.Context, id int64) (Plan, error) {
409
+ value, err := p.request(ctx, "billing.plan.get", map[string]any{"id": id})
410
+ return billingPlan(value), err
411
+ }
412
+ func (p billingClient) ListPlans(ctx context.Context, query PlanQuery) ([]Plan, error) {
413
+ value, err := p.request(ctx, "billing.plan.list", map[string]any{"query": query})
414
+ return billingPlans(value), err
415
+ }
416
+ func (p billingClient) UpdatePlan(ctx context.Context, id int64, in PlanUpdateRequest) (Plan, error) {
417
+ value, err := p.request(ctx, "billing.plan.update", map[string]any{"id": id, "data": in})
418
+ return billingPlan(value), err
419
+ }
420
+ func (p billingClient) SetPlanStatus(ctx context.Context, id int64, status string) (Plan, error) {
421
+ value, err := p.request(ctx, "billing.plan.status", map[string]any{"id": id, "status": status})
422
+ return billingPlan(value), err
423
+ }
424
+ func (p billingClient) CreateSubscription(ctx context.Context, in SubscriptionRequest) (Subscription, error) {
425
+ value, err := p.request(ctx, "billing.subscription.create", in)
426
+ return billingSubscription(value), err
427
+ }
428
+ func (p billingClient) GetSubscription(ctx context.Context, id int64) (Subscription, error) {
429
+ value, err := p.request(ctx, "billing.subscription.get", map[string]any{"id": id})
430
+ return billingSubscription(value), err
431
+ }
432
+ func (p billingClient) ListSubscriptions(ctx context.Context, query SubscriptionQuery) ([]Subscription, error) {
433
+ value, err := p.request(ctx, "billing.subscription.list", map[string]any{"query": query})
434
+ return billingSubscriptions(value), err
435
+ }
436
+ func (p billingClient) ChangeSubscriptionPlan(ctx context.Context, id int64, in SubscriptionChangeRequest) (Subscription, error) {
437
+ value, err := p.request(ctx, "billing.subscription.change_plan", map[string]any{"id": id, "data": in})
438
+ return billingSubscription(value), err
439
+ }
440
+ func (p billingClient) PauseSubscription(ctx context.Context, id int64) (Subscription, error) {
441
+ value, err := p.request(ctx, "billing.subscription.pause", map[string]any{"id": id})
442
+ return billingSubscription(value), err
443
+ }
444
+ func (p billingClient) ResumeSubscription(ctx context.Context, id int64) (Subscription, error) {
445
+ value, err := p.request(ctx, "billing.subscription.resume", map[string]any{"id": id})
446
+ return billingSubscription(value), err
447
+ }
448
+ func (p billingClient) CancelSubscription(ctx context.Context, id int64) (Subscription, error) {
449
+ value, err := p.request(ctx, "billing.subscription.cancel", map[string]any{"id": id})
450
+ return billingSubscription(value), err
451
+ }
452
+ func (p billingClient) FulfillSubscriptionPayment(ctx context.Context, in SubscriptionPaymentFulfillmentRequest) (Subscription, error) {
453
+ value, err := p.request(ctx, "billing.subscription.fulfill_payment", in)
454
+ return billingSubscription(value), err
455
+ }
456
+ func (p billingClient) GetAIPricing(ctx context.Context, query map[string]any) (map[string]any, error) {
457
+ return p.request(ctx, "billing.ai.pricing.get", map[string]any{"query": query})
458
+ }
459
+ func (p billingClient) ListAIPriceVersions(ctx context.Context, query map[string]any) (map[string]any, error) {
460
+ return p.request(ctx, "billing.ai.pricing.list", map[string]any{"query": query})
461
+ }
462
+ func (p billingClient) CreateAIPriceVersion(ctx context.Context, in AIPriceVersionRequest) (AIPriceVersion, error) {
463
+ value, err := p.request(ctx, "billing.ai.pricing.create", in)
464
+ return aiPriceVersion(value), err
465
+ }
466
+ func (p billingClient) EstimateAI(ctx context.Context, in AIEstimateRequest) (AIEstimate, error) {
467
+ value, err := p.request(ctx, "billing.ai.estimate", in)
468
+ return aiEstimate(value), err
469
+ }
470
+ func (p billingClient) StartAIBilling(ctx context.Context, in AIBillingStartRequest) (AIBillingSession, error) {
471
+ value, err := p.request(ctx, "billing.ai.session.start", in)
472
+ return aiSession(value), err
473
+ }
474
+ func (p billingClient) SettleAIBilling(ctx context.Context, in AISettlementRequest) (AIBillingSession, error) {
475
+ value, err := p.request(ctx, "billing.ai.session.settle", in)
476
+ return aiSession(value), err
477
+ }
478
+ func (p billingClient) CancelAIBilling(ctx context.Context, id, key string) error {
479
+ _, err := p.request(ctx, "billing.ai.session.cancel", map[string]any{"session_id": id, "idempotency_key": key})
480
+ return err
481
+ }
482
+ func (p billingClient) GetAIUsage(ctx context.Context, query map[string]any) (map[string]any, error) {
483
+ return p.request(ctx, "billing.ai.usage.list", map[string]any{"query": query})
484
+ }
485
+ func (p billingClient) GetAICosts(ctx context.Context, query map[string]any) (map[string]any, error) {
486
+ return p.request(ctx, "billing.ai.costs.list", map[string]any{"query": query})
487
+ }
488
+
489
+ func paymentIntent(v map[string]any) PaymentIntent {
490
+ return PaymentIntent{OrderID: fmtString(v["order_id"]), Provider: fmtString(v["provider"]), Status: fmtString(v["status"]), AmountMinor: asInt64(v["amount_minor"]), PayURL: fmtString(v["pay_url"]), QRCode: fmtString(v["qr_code"]), Params: mapResult(v["params"])}
491
+ }
492
+ func paymentOrder(v map[string]any) PaymentOrder {
493
+ return PaymentOrder{
494
+ ID: fmtString(v["id"]), BusinessOrderID: fmtString(v["business_order_id"]),
495
+ Ownership: resourceOwnership(v), PayerUserID: asInt64(v["payer_user_id"]), CreatedBy: asInt64(v["created_by"]),
496
+ Provider: fmtString(v["provider"]), ProviderTradeNo: fmtString(v["provider_trade_no"]),
497
+ Status: fmtString(v["status"]), AmountMinor: asInt64(v["amount_minor"]),
498
+ ProductRef: fmtString(v["product_ref"]), FulfillmentRef: fmtString(v["fulfillment_ref"]), Metadata: mapResult(v["metadata"]),
499
+ ExpiresAt: fmtString(v["expires_at"]), PaidAt: fmtString(v["paid_at"]), CreatedAt: fmtString(v["created_at"]), UpdatedAt: fmtString(v["updated_at"]),
500
+ }
501
+ }
502
+ func account(v map[string]any) Account {
503
+ return Account{BalanceMinor: asInt64(v["balance_minor"]), AvailableMinor: asInt64(v["available_minor"])}
504
+ }
505
+ func journalResult(v map[string]any) JournalResult {
506
+ return JournalResult{JournalID: fmtString(v["journal_id"]), BalanceMinor: asInt64(v["balance_minor"])}
507
+ }
508
+ func holdResult(v map[string]any) HoldResult {
509
+ return HoldResult{HoldID: fmtString(v["hold_id"]), AmountMinor: asInt64(v["amount_minor"]), AvailableMinor: asInt64(v["available_minor"])}
510
+ }
511
+ func billingPlan(v map[string]any) Plan {
512
+ return Plan{
513
+ ID: asInt64(v["id"]),
514
+ Code: fmtString(v["code"]),
515
+ Name: fmtString(v["name"]),
516
+ Status: fmtString(v["status"]),
517
+ PriceMinor: asInt64(v["price_minor"]),
518
+ BillingCycle: fmtString(v["billing_cycle"]),
519
+ Entitlements: mapResult(v["entitlements"]),
520
+ CreatedAt: fmtString(v["created_at"]),
521
+ UpdatedAt: fmtString(v["updated_at"]),
522
+ }
523
+ }
524
+ func billingPlans(v map[string]any) []Plan {
525
+ items := mapSlice(v["items"])
526
+ result := make([]Plan, 0, len(items))
527
+ for _, item := range items {
528
+ result = append(result, billingPlan(item))
529
+ }
530
+ return result
531
+ }
532
+ func billingSubscription(v map[string]any) Subscription {
533
+ return Subscription{
534
+ ID: asInt64(v["id"]),
535
+ PlanID: asInt64(v["plan_id"]),
536
+ Subject: BillingSubject{Type: fmtString(v["subject_type"]), ID: fmtString(v["subject_id"])},
537
+ CreatedBy: asInt64(v["created_by"]),
538
+ Status: fmtString(v["status"]),
539
+ CurrentPeriodStart: fmtString(v["current_period_start"]),
540
+ CurrentPeriodEnd: fmtString(v["current_period_end"]),
541
+ SourceType: fmtString(v["source_type"]),
542
+ SourceID: fmtString(v["source_id"]),
543
+ IdempotencyKey: fmtString(v["idempotency_key"]),
544
+ CreatedAt: fmtString(v["created_at"]),
545
+ UpdatedAt: fmtString(v["updated_at"]),
546
+ }
547
+ }
548
+ func billingSubscriptions(v map[string]any) []Subscription {
549
+ items := mapSlice(v["items"])
550
+ result := make([]Subscription, 0, len(items))
551
+ for _, item := range items {
552
+ result = append(result, billingSubscription(item))
553
+ }
554
+ return result
555
+ }
556
+ func int64Slice(value any) []int64 {
557
+ switch items := value.(type) {
558
+ case []int64:
559
+ return append([]int64(nil), items...)
560
+ case []any:
561
+ result := make([]int64, 0, len(items))
562
+ for _, item := range items {
563
+ result = append(result, asInt64(item))
564
+ }
565
+ return result
566
+ default:
567
+ return nil
568
+ }
569
+ }
570
+ func aiEstimate(v map[string]any) AIEstimate {
571
+ return AIEstimate{AmountMinor: asInt64(v["amount_minor"]), PriceVersion: fmtString(v["price_version"]), Breakdown: mapResult(v["breakdown"])}
572
+ }
573
+ func aiPriceVersion(v map[string]any) AIPriceVersion {
574
+ return AIPriceVersion{ID: fmtString(v["id"]), Model: fmtString(v["model_key"]), Agent: fmtString(v["agent_key"]), Version: fmtString(v["version"]), BillingMode: fmtString(v["billing_mode"]), BillingEnabled: asBool(v["billing_enabled"]), InputPriceMinorPerMillion: asInt64(v["input_price_minor_per_million"]), OutputPriceMinorPerMillion: asInt64(v["output_price_minor_per_million"]), CachedInputPriceMinorPerMillion: asInt64(v["cached_input_price_minor_per_million"]), CacheCreationPriceMinorPerMillion: asInt64(v["cache_creation_price_minor_per_million"]), ImagePriceMinor: asInt64(v["image_price_minor"]), AudioPriceMinor: asInt64(v["audio_price_minor"]), AudioOutputPriceMinor: asInt64(v["audio_output_price_minor"]), RequestPriceMinor: asInt64(v["request_price_minor"]), ProviderCostMode: fmtString(v["provider_cost_mode"]), ProviderInputCostMinorPerMillion: asInt64(v["provider_input_cost_minor_per_million"]), ProviderOutputCostMinorPerMillion: asInt64(v["provider_output_cost_minor_per_million"]), ProviderCachedInputCostMinorPerMillion: asInt64(v["provider_cached_input_cost_minor_per_million"]), ProviderCacheCreationCostMinorPerMillion: asInt64(v["provider_cache_creation_cost_minor_per_million"]), ProviderImageCostMinor: asInt64(v["provider_image_cost_minor"]), ProviderAudioCostMinor: asInt64(v["provider_audio_cost_minor"]), ProviderAudioOutputCostMinor: asInt64(v["provider_audio_output_cost_minor"]), ProviderRequestCostMinor: asInt64(v["provider_request_cost_minor"]), Status: fmtString(v["status"]), EffectiveFrom: fmtString(v["effective_from"])}
575
+ }
576
+ func aiSession(v map[string]any) AIBillingSession {
577
+ return AIBillingSession{ID: fmtString(v["id"]), Status: fmtString(v["status"]), ReservedMinor: asInt64(v["reserved_minor"]), SettledMinor: asInt64(v["settled_minor"]), PriceVersion: fmtString(v["price_version"])}
578
+ }
579
+ func asInt64(v any) int64 {
580
+ switch n := v.(type) {
581
+ case int64:
582
+ return n
583
+ case int:
584
+ return int64(n)
585
+ case float64:
586
+ return int64(n)
587
+ case float32:
588
+ return int64(n)
589
+ default:
590
+ return 0
591
+ }
592
+ }
593
+ func asBool(v any) bool {
594
+ value, _ := v.(bool)
595
+ return value
596
+ }