@unstoppabledomains/ud-cli 0.1.22 → 0.1.24

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.
@@ -2340,7 +2340,7 @@
2340
2340
  "post": {
2341
2341
  "operationId": "dnsHostingList",
2342
2342
  "summary": "List hosting configurations",
2343
- "description": "List hosting/forwarding configurations (UD Profile, redirects).",
2343
+ "description": "List hosting/forwarding configurations (redirects, reverse proxy, hosted sites, UD Profile).",
2344
2344
  "tags": [
2345
2345
  "DNS Management"
2346
2346
  ],
@@ -2393,7 +2393,7 @@
2393
2393
  "post": {
2394
2394
  "operationId": "dnsHostingAdd",
2395
2395
  "summary": "Add hosting configuration (bulk)",
2396
- "description": "Configure hosting for one or more domains: for-sale listing page, permanent redirect (301), or temporary redirect (302). Supports up to 50 domains per request.",
2396
+ "description": "Configure hosting for one or more domains: for-sale listing page, permanent redirect (301), temporary redirect (302), or reverse proxy. Supports up to 50 domains per request.",
2397
2397
  "tags": [
2398
2398
  "DNS Management"
2399
2399
  ],
@@ -2430,13 +2430,14 @@
2430
2430
  "enum": [
2431
2431
  "LISTING_PAGE",
2432
2432
  "REDIRECT_301",
2433
- "REDIRECT_302"
2433
+ "REDIRECT_302",
2434
+ "REVERSE_PROXY"
2434
2435
  ],
2435
2436
  "description": "Hosting type"
2436
2437
  },
2437
2438
  "targetUrl": {
2438
2439
  "type": "string",
2439
- "description": "Redirect URL (required for redirects)"
2440
+ "description": "Destination URL (required for REDIRECT_301, REDIRECT_302, REVERSE_PROXY)"
2440
2441
  },
2441
2442
  "subName": {
2442
2443
  "type": "string",
@@ -3050,6 +3051,11 @@
3050
3051
  "minItems": 1,
3051
3052
  "maxItems": 50,
3052
3053
  "description": "Array of domains (1-50)"
3054
+ },
3055
+ "instructions": {
3056
+ "type": "string",
3057
+ "maxLength": 2000,
3058
+ "description": "Optional custom instructions to guide AI generation (e.g., tone, color scheme, content focus). Applied to all domains in the request."
3053
3059
  }
3054
3060
  }
3055
3061
  }
@@ -3105,7 +3111,7 @@
3105
3111
  "post": {
3106
3112
  "operationId": "landerStatus",
3107
3113
  "summary": "Check AI lander generation status",
3108
- "description": "Check the status of AI landing page generation for one or more domains. Returns pending, generating, hosted, failed, or none.",
3114
+ "description": "Check the status of AI landing page generation for one or more domains. Returns pending, generating, processing, hosted, failed, or none.",
3109
3115
  "tags": [
3110
3116
  "AI Lander"
3111
3117
  ],
@@ -3169,6 +3175,7 @@
3169
3175
  "enum": [
3170
3176
  "pending",
3171
3177
  "generating",
3178
+ "processing",
3172
3179
  "hosted",
3173
3180
  "failed",
3174
3181
  "none"
@@ -3194,6 +3201,217 @@
3194
3201
  }
3195
3202
  }
3196
3203
  },
3204
+ "/mcp/v1/actions/ud_domain_upload_lander": {
3205
+ "post": {
3206
+ "operationId": "uploadLander",
3207
+ "summary": "Upload custom landing page content to domains",
3208
+ "description": "Upload custom landing page content for one or more domains. Accepts either raw HTML (htmlContent) for single-page landers or base64-encoded zip files (zipContent) for multi-file sites. Existing lander content is replaced.",
3209
+ "tags": [
3210
+ "AI Lander"
3211
+ ],
3212
+ "security": [
3213
+ {
3214
+ "bearerAuth": []
3215
+ }
3216
+ ],
3217
+ "requestBody": {
3218
+ "required": true,
3219
+ "content": {
3220
+ "application/json": {
3221
+ "schema": {
3222
+ "type": "object",
3223
+ "required": [
3224
+ "domains"
3225
+ ],
3226
+ "properties": {
3227
+ "domains": {
3228
+ "type": "array",
3229
+ "items": {
3230
+ "type": "object",
3231
+ "required": [
3232
+ "name"
3233
+ ],
3234
+ "properties": {
3235
+ "name": {
3236
+ "type": "string",
3237
+ "minLength": 1,
3238
+ "description": "Domain name to upload lander content for (e.g., \"example.com\")"
3239
+ },
3240
+ "htmlContent": {
3241
+ "type": "string",
3242
+ "minLength": 1,
3243
+ "description": "Raw HTML string for a single-page lander (max 1MB). Preferred for AI-generated content. Provide this OR zipContent."
3244
+ },
3245
+ "zipContent": {
3246
+ "type": "string",
3247
+ "minLength": 1,
3248
+ "description": "Base64-encoded zip file containing lander content (max ~1MB). Provide this OR htmlContent."
3249
+ }
3250
+ }
3251
+ },
3252
+ "minItems": 1,
3253
+ "maxItems": 50,
3254
+ "description": "Array of domains with content (1-50). Each domain must have exactly one of htmlContent or zipContent."
3255
+ }
3256
+ }
3257
+ }
3258
+ }
3259
+ }
3260
+ },
3261
+ "responses": {
3262
+ "200": {
3263
+ "description": "Upload results",
3264
+ "content": {
3265
+ "application/json": {
3266
+ "schema": {
3267
+ "type": "object",
3268
+ "properties": {
3269
+ "results": {
3270
+ "type": "array",
3271
+ "items": {
3272
+ "type": "object",
3273
+ "properties": {
3274
+ "domain": {
3275
+ "type": "string"
3276
+ },
3277
+ "success": {
3278
+ "type": "boolean"
3279
+ },
3280
+ "status": {
3281
+ "type": "string",
3282
+ "enum": [
3283
+ "processing"
3284
+ ],
3285
+ "description": "Status after upload. \"processing\" means content is uploaded and hosting config is propagating."
3286
+ },
3287
+ "error": {
3288
+ "type": "string"
3289
+ }
3290
+ }
3291
+ }
3292
+ },
3293
+ "successCount": {
3294
+ "type": "number"
3295
+ },
3296
+ "failureCount": {
3297
+ "type": "number"
3298
+ }
3299
+ }
3300
+ }
3301
+ }
3302
+ }
3303
+ },
3304
+ "401": {
3305
+ "description": "Authentication required"
3306
+ }
3307
+ }
3308
+ }
3309
+ },
3310
+ "/mcp/v1/actions/ud_domain_download_lander": {
3311
+ "post": {
3312
+ "operationId": "downloadLander",
3313
+ "summary": "Download landing page content from domains",
3314
+ "description": "Download existing hosted lander files from one or more domains. Single-page landers return raw HTML (htmlContent); multi-file sites return a base64-encoded zip (zipContent).",
3315
+ "tags": [
3316
+ "AI Lander"
3317
+ ],
3318
+ "security": [
3319
+ {
3320
+ "bearerAuth": []
3321
+ }
3322
+ ],
3323
+ "requestBody": {
3324
+ "required": true,
3325
+ "content": {
3326
+ "application/json": {
3327
+ "schema": {
3328
+ "type": "object",
3329
+ "required": [
3330
+ "domains"
3331
+ ],
3332
+ "properties": {
3333
+ "domains": {
3334
+ "type": "array",
3335
+ "items": {
3336
+ "type": "object",
3337
+ "required": [
3338
+ "name"
3339
+ ],
3340
+ "properties": {
3341
+ "name": {
3342
+ "type": "string",
3343
+ "minLength": 1,
3344
+ "description": "Domain name to download lander content for (e.g., \"example.com\")"
3345
+ }
3346
+ }
3347
+ },
3348
+ "minItems": 1,
3349
+ "maxItems": 50,
3350
+ "description": "Array of domains (1-50)"
3351
+ }
3352
+ }
3353
+ }
3354
+ }
3355
+ }
3356
+ },
3357
+ "responses": {
3358
+ "200": {
3359
+ "description": "Download results",
3360
+ "content": {
3361
+ "application/json": {
3362
+ "schema": {
3363
+ "type": "object",
3364
+ "properties": {
3365
+ "results": {
3366
+ "type": "array",
3367
+ "items": {
3368
+ "type": "object",
3369
+ "properties": {
3370
+ "domain": {
3371
+ "type": "string"
3372
+ },
3373
+ "success": {
3374
+ "type": "boolean"
3375
+ },
3376
+ "format": {
3377
+ "type": "string",
3378
+ "enum": [
3379
+ "html",
3380
+ "zip"
3381
+ ],
3382
+ "description": "Content format: \"html\" for single-page landers, \"zip\" for multi-file sites"
3383
+ },
3384
+ "htmlContent": {
3385
+ "type": "string",
3386
+ "description": "Raw HTML string (when format is \"html\")"
3387
+ },
3388
+ "zipContent": {
3389
+ "type": "string",
3390
+ "description": "Base64-encoded zip file (when format is \"zip\")"
3391
+ },
3392
+ "error": {
3393
+ "type": "string"
3394
+ }
3395
+ }
3396
+ }
3397
+ },
3398
+ "successCount": {
3399
+ "type": "number"
3400
+ },
3401
+ "failureCount": {
3402
+ "type": "number"
3403
+ }
3404
+ }
3405
+ }
3406
+ }
3407
+ }
3408
+ },
3409
+ "401": {
3410
+ "description": "Authentication required"
3411
+ }
3412
+ }
3413
+ }
3414
+ },
3197
3415
  "/mcp/v1/actions/ud_domain_remove_lander": {
3198
3416
  "post": {
3199
3417
  "operationId": "removeLander",
@@ -3285,6 +3503,144 @@
3285
3503
  }
3286
3504
  }
3287
3505
  }
3506
+ },
3507
+ "/api/oauth/signup": {
3508
+ "post": {
3509
+ "operationId": "oauthSignup",
3510
+ "summary": "Create an account via email and password (headless)",
3511
+ "description": "Step 1 of headless account creation. Registers a new user with email and password, sends a verification code via email, and returns a signup_session_token. Use POST /api/oauth/signup/verify with the token and code to get OAuth tokens. Returns identical responses for new and existing users to prevent account enumeration.",
3512
+ "tags": [
3513
+ "Account"
3514
+ ],
3515
+ "security": [],
3516
+ "requestBody": {
3517
+ "required": true,
3518
+ "content": {
3519
+ "application/json": {
3520
+ "schema": {
3521
+ "type": "object",
3522
+ "required": [
3523
+ "email",
3524
+ "password"
3525
+ ],
3526
+ "properties": {
3527
+ "email": {
3528
+ "type": "string",
3529
+ "format": "email",
3530
+ "description": "Email address for the new account"
3531
+ },
3532
+ "password": {
3533
+ "type": "string",
3534
+ "minLength": 8,
3535
+ "description": "Password with at least 8 characters, one uppercase, one lowercase, one digit, and one special character"
3536
+ }
3537
+ }
3538
+ }
3539
+ }
3540
+ }
3541
+ },
3542
+ "responses": {
3543
+ "200": {
3544
+ "description": "Signup session created",
3545
+ "content": {
3546
+ "application/json": {
3547
+ "schema": {
3548
+ "type": "object",
3549
+ "properties": {
3550
+ "signup_session_token": {
3551
+ "type": "string",
3552
+ "description": "Token to use with /api/oauth/signup/verify"
3553
+ },
3554
+ "expires_in": {
3555
+ "type": "number",
3556
+ "description": "Session TTL in seconds (900)"
3557
+ }
3558
+ }
3559
+ }
3560
+ }
3561
+ }
3562
+ },
3563
+ "400": {
3564
+ "description": "Invalid email, password, or disposable email"
3565
+ },
3566
+ "429": {
3567
+ "description": "Rate limit exceeded"
3568
+ }
3569
+ }
3570
+ }
3571
+ },
3572
+ "/api/oauth/signup/verify": {
3573
+ "post": {
3574
+ "operationId": "oauthSignupVerify",
3575
+ "summary": "Verify signup code and get OAuth tokens",
3576
+ "description": "Step 2 of headless account creation. Exchanges the signup_session_token and the 6-character verification code (sent via email) for OAuth access and refresh tokens.",
3577
+ "tags": [
3578
+ "Account"
3579
+ ],
3580
+ "security": [],
3581
+ "requestBody": {
3582
+ "required": true,
3583
+ "content": {
3584
+ "application/json": {
3585
+ "schema": {
3586
+ "type": "object",
3587
+ "required": [
3588
+ "signup_session_token",
3589
+ "verification_code"
3590
+ ],
3591
+ "properties": {
3592
+ "signup_session_token": {
3593
+ "type": "string",
3594
+ "description": "Token from POST /api/oauth/signup"
3595
+ },
3596
+ "verification_code": {
3597
+ "type": "string",
3598
+ "description": "6-character alphanumeric code from the verification email"
3599
+ }
3600
+ }
3601
+ }
3602
+ }
3603
+ }
3604
+ },
3605
+ "responses": {
3606
+ "200": {
3607
+ "description": "OAuth tokens issued",
3608
+ "content": {
3609
+ "application/json": {
3610
+ "schema": {
3611
+ "type": "object",
3612
+ "properties": {
3613
+ "access_token": {
3614
+ "type": "string"
3615
+ },
3616
+ "token_type": {
3617
+ "type": "string",
3618
+ "enum": [
3619
+ "Bearer"
3620
+ ]
3621
+ },
3622
+ "expires_in": {
3623
+ "type": "number"
3624
+ },
3625
+ "refresh_token": {
3626
+ "type": "string"
3627
+ },
3628
+ "scope": {
3629
+ "type": "string"
3630
+ }
3631
+ }
3632
+ }
3633
+ }
3634
+ }
3635
+ },
3636
+ "400": {
3637
+ "description": "Invalid or expired session, wrong code, or too many attempts"
3638
+ },
3639
+ "429": {
3640
+ "description": "Rate limit exceeded"
3641
+ }
3642
+ }
3643
+ }
3288
3644
  }
3289
3645
  },
3290
3646
  "components": {
@@ -4125,6 +4481,10 @@
4125
4481
  "checkoutUrl": {
4126
4482
  "type": "string"
4127
4483
  },
4484
+ "expiresIn": {
4485
+ "type": "number",
4486
+ "description": "Seconds until the magic link expires (URL is single-use)"
4487
+ },
4128
4488
  "cartSummary": {
4129
4489
  "type": "object",
4130
4490
  "properties": {
@@ -4161,7 +4521,11 @@
4161
4521
  "properties": {
4162
4522
  "url": {
4163
4523
  "type": "string",
4164
- "description": "URL to the payment management page"
4524
+ "description": "Authenticated magic link URL to the payment management page (single-use, valid for 60 seconds)"
4525
+ },
4526
+ "expiresIn": {
4527
+ "type": "number",
4528
+ "description": "Seconds until the magic link expires (URL is single-use)"
4165
4529
  },
4166
4530
  "instructions": {
4167
4531
  "type": "string",
@@ -4735,7 +5099,7 @@
4735
5099
  },
4736
5100
  "transferStatus": {
4737
5101
  "type": "string",
4738
- "description": "Domain transfer status:\n \"none\" - No active transfer\n \"pending\" - Transfer in progress"
5102
+ "description": "Domain transfer status:\n\u2022 \"none\" - No active transfer\n\u2022 \"pending\" - Transfer in progress"
4739
5103
  },
4740
5104
  "isExternallyOwned": {
4741
5105
  "type": "boolean",
@@ -4781,7 +5145,7 @@
4781
5145
  },
4782
5146
  "status": {
4783
5147
  "type": "string",
4784
- "description": "Listing status:\n \"open\" - Live on marketplace, ready for purchase (user-custodied domains)\n \"open-not-signed\" - Live on marketplace, ready for purchase (UD-custodied domains, no user action needed)\n \"open-on-request\" - Accepting offers only, no fixed price\n \"draft\" - Not yet published\n \"waiting-for-approval\" - Pending wallet signature from owner\n \"pending-admin-approval\" - Under review (high-value listings)\n \"pending\" - Sale in progress\n \"canceled\" - Listing was canceled\nNote: Both \"open\" and \"open-not-signed\" mean the listing is active and purchasable."
5148
+ "description": "Listing status:\n\u2022 \"open\" - Live on marketplace, ready for purchase (user-custodied domains)\n\u2022 \"open-not-signed\" - Live on marketplace, ready for purchase (UD-custodied domains, no user action needed)\n\u2022 \"open-on-request\" - Accepting offers only, no fixed price\n\u2022 \"draft\" - Not yet published\n\u2022 \"waiting-for-approval\" - Pending wallet signature from owner\n\u2022 \"pending-admin-approval\" - Under review (high-value listings)\n\u2022 \"pending\" - Sale in progress\n\u2022 \"canceled\" - Listing was canceled\nNote: Both \"open\" and \"open-not-signed\" mean the listing is active and purchasable."
4785
5149
  },
4786
5150
  "createdAt": {
4787
5151
  "type": "string",
@@ -4806,7 +5170,7 @@
4806
5170
  "properties": {
4807
5171
  "status": {
4808
5172
  "type": "string",
4809
- "description": "Auto-renewal subscription status:\n \"active\" - Subscription active, will auto-renew\n \"pending\" - Payment collected, waiting for domain registration\n \"update_required\" - Payment method needs updating (card expired/declined)\n \"expired\" - Subscription expired, domain renewal overdue\n \"cancelled\" - Subscription cancelled, will not auto-renew"
5173
+ "description": "Auto-renewal subscription status:\n\u2022 \"active\" - Subscription active, will auto-renew\n\u2022 \"pending\" - Payment collected, waiting for domain registration\n\u2022 \"update_required\" - Payment method needs updating (card expired/declined)\n\u2022 \"expired\" - Subscription expired, domain renewal overdue\n\u2022 \"cancelled\" - Subscription cancelled, will not auto-renew"
4810
5174
  },
4811
5175
  "expiresAt": {
4812
5176
  "type": [
@@ -5500,9 +5864,11 @@
5500
5864
  "type": {
5501
5865
  "type": "string",
5502
5866
  "enum": [
5867
+ "GCS_HOSTED",
5503
5868
  "LISTING_PAGE",
5504
5869
  "REDIRECT_301",
5505
5870
  "REDIRECT_302",
5871
+ "REVERSE_PROXY",
5506
5872
  "UD_PROFILE",
5507
5873
  "STOREFRONT"
5508
5874
  ]
@@ -5519,7 +5885,7 @@
5519
5885
  "string",
5520
5886
  "null"
5521
5887
  ],
5522
- "description": "Redirect target URL"
5888
+ "description": "Destination URL (for redirects and reverse proxy)"
5523
5889
  },
5524
5890
  "status": {
5525
5891
  "type": "string"
@@ -31,7 +31,7 @@ export interface CommandHooks {
31
31
  validate?: RegExp;
32
32
  };
33
33
  /** Transform the request body before sending (e.g., price conversion). */
34
- transformBody?: (body: Record<string, unknown>, opts: Record<string, unknown>) => Record<string, unknown>;
34
+ transformBody?: (body: Record<string, unknown>, opts: Record<string, unknown>) => Record<string, unknown> | Promise<Record<string, unknown>>;
35
35
  /** Register a --price <dollars> option for this command. */
36
36
  priceOption?: boolean;
37
37
  /** Show an operation-tracking hint after the API call completes. */
@@ -51,6 +51,14 @@ export interface CommandHooks {
51
51
  message?: string;
52
52
  abort?: boolean;
53
53
  } | void>;
54
+ /** Additional Commander options to register on the command (e.g., --html-file, --output-dir). */
55
+ additionalOptions?: Array<{
56
+ flags: string;
57
+ description: string;
58
+ }>;
59
+ /** Async post-action hook that runs after API call, before formatting.
60
+ * Can perform side effects (e.g., file writing) and return a modified result for display. */
61
+ postAction?: (result: unknown, opts: Record<string, unknown>) => Promise<unknown>;
54
62
  }
55
63
  export declare const VIEW_CART_HINT: string;
56
64
  export declare const CHECKOUT_HINT: string;
@@ -1 +1 @@
1
- {"version":3,"file":"command-hooks.d.ts","sourceRoot":"","sources":["../../src/lib/command-hooks.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,kEAAkE;AAClE,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACpF,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChF,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,cAAc,CAAC,EAAE;QACf,oGAAoG;QACpG,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,yCAAyC;QACzC,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,kFAAkF;IAClF,WAAW,CAAC,EAAE;QACZ,oDAAoD;QACpD,QAAQ,EAAE,MAAM,CAAC;QACjB,kDAAkD;QAClD,SAAS,EAAE,MAAM,CAAC;QAClB,wCAAwC;QACxC,MAAM,EAAE,MAAM,CAAC;QACf,oCAAoC;QACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,0EAA0E;IAC1E,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1G,4DAA4D;IAC5D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,oEAAoE;IACpE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,yEAAyE;IACzE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,6FAA6F;IAC7F,cAAc,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,CAAC,CAAC;IACxD,uFAAuF;IACvF,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,6EAA6E;IAC7E,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,CAAC;IAC3C,mFAAmF;IACnF,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;CAC9F;AAuDD,eAAO,MAAM,cAAc,QAAwD,CAAC;AACpF,eAAO,MAAM,aAAa,QAA0D,CAAC;AA4UrF;;GAEG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEnE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CA2B3D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAoC5E;AAED,uEAAuE;AACvE,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKrD,CAAC;AAEF;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CA2BtD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAW9D"}
1
+ {"version":3,"file":"command-hooks.d.ts","sourceRoot":"","sources":["../../src/lib/command-hooks.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,9 @@
3
3
  * beyond the standard API call (confirmations, OTP prompts, operation hints).
4
4
  */
5
5
  import chalk from 'chalk';
6
- import { openInBrowser, isMagicLinkUrl } from './magic-link.js';
6
+ import { readFile, mkdir, writeFile } from 'node:fs/promises';
7
+ import { join, basename } from 'node:path';
8
+ import { openInBrowser } from './magic-link.js';
7
9
  /**
8
10
  * Create a transformBody hook that converts --price (dollars) to priceInCents on each item.
9
11
  */
@@ -92,9 +94,7 @@ async function checkoutPreAction(ctx) {
92
94
  if (checkoutUrl) {
93
95
  const magicUrl = await ctx.createMagicLinkUrl(checkoutUrl);
94
96
  checkoutLine = `\n\n ${magicUrl}`;
95
- if (magicUrl !== checkoutUrl && isMagicLinkUrl(magicUrl)) {
96
- openInBrowser(magicUrl);
97
- }
97
+ openInBrowser(magicUrl);
98
98
  }
99
99
  }
100
100
  catch {
@@ -353,6 +353,88 @@ const HOOKS = {
353
353
  ud_offer_respond: { postActionHint: OFFERS_LIST_HINT },
354
354
  // Landers
355
355
  ud_domain_generate_lander: { postActionHint: formatLanderCheckHint },
356
+ ud_domain_upload_lander: {
357
+ additionalOptions: [
358
+ { flags: '--html-file <path>', description: 'Path to HTML file to upload as landing page' },
359
+ { flags: '--zip-file <path>', description: 'Path to ZIP file to upload as landing page (base64-encoded automatically)' },
360
+ ],
361
+ transformBody: async (body, opts) => {
362
+ const htmlFile = opts.htmlFile;
363
+ const zipFile = opts.zipFile;
364
+ if (htmlFile && zipFile) {
365
+ throw new Error('Cannot specify both --html-file and --zip-file. Use one or the other.');
366
+ }
367
+ if (!htmlFile && !zipFile)
368
+ return body;
369
+ const domains = body.domains;
370
+ if (!Array.isArray(domains))
371
+ return body;
372
+ if (htmlFile) {
373
+ const content = await readFile(htmlFile, 'utf-8');
374
+ for (const d of domains) {
375
+ if (!d.htmlContent)
376
+ d.htmlContent = content;
377
+ }
378
+ }
379
+ if (zipFile) {
380
+ const content = (await readFile(zipFile)).toString('base64');
381
+ for (const d of domains) {
382
+ if (!d.zipContent)
383
+ d.zipContent = content;
384
+ }
385
+ }
386
+ return body;
387
+ },
388
+ postActionHint: formatLanderCheckHint,
389
+ },
390
+ ud_domain_download_lander: {
391
+ additionalOptions: [
392
+ { flags: '--output-dir <path>', description: 'Directory to save downloaded files (default: current directory)' },
393
+ ],
394
+ postAction: async (result, opts) => {
395
+ if (!result || typeof result !== 'object')
396
+ return result;
397
+ const obj = result;
398
+ const results = obj.results;
399
+ if (!Array.isArray(results))
400
+ return result;
401
+ const outputDir = opts.outputDir || process.cwd();
402
+ await mkdir(outputDir, { recursive: true });
403
+ const summary = [];
404
+ for (const item of results) {
405
+ if (!item.success) {
406
+ summary.push({ domain: item.domain, success: false, error: item.error });
407
+ continue;
408
+ }
409
+ // Sanitize domain to prevent path traversal from server response
410
+ const rawDomain = item.domain;
411
+ if (typeof rawDomain !== 'string' || !rawDomain) {
412
+ summary.push({ domain: rawDomain, success: false, error: 'Missing domain name' });
413
+ continue;
414
+ }
415
+ const domain = basename(rawDomain);
416
+ let filename;
417
+ let content;
418
+ if (item.format === 'zip' && item.zipContent) {
419
+ filename = `${domain}.zip`;
420
+ content = Buffer.from(item.zipContent, 'base64');
421
+ }
422
+ else if (item.htmlContent) {
423
+ filename = `${domain}.html`;
424
+ content = item.htmlContent;
425
+ }
426
+ else {
427
+ summary.push({ domain, success: false, error: 'No content returned' });
428
+ continue;
429
+ }
430
+ const filePath = join(outputDir, filename);
431
+ await writeFile(filePath, content);
432
+ summary.push({ domain, success: true, format: item.format, file: filePath });
433
+ }
434
+ return { ...obj, results: summary };
435
+ },
436
+ postActionHint: formatLanderCheckHint,
437
+ },
356
438
  // Search & DNS ops
357
439
  ud_domains_search: { showCartHint: true },
358
440
  ud_dns_record_add: { showOperationHint: true, showFailureHints: true },