zapier-platform-cli 17.6.0 → 17.7.1

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.
@@ -652,6 +652,13 @@
652
652
  "multiple": false,
653
653
  "type": "option"
654
654
  },
655
+ "paging-token": {
656
+ "description": "Set bundle.meta.paging_token. Used for search pagination or bulk reads. When used in production, this indicates which page of items you should fetch.",
657
+ "name": "paging-token",
658
+ "hasDynamicHelp": false,
659
+ "multiple": false,
660
+ "type": "option"
661
+ },
655
662
  "debug": {
656
663
  "char": "d",
657
664
  "description": "Show extra debugging output.",
@@ -1150,7 +1157,7 @@
1150
1157
  "pull": {
1151
1158
  "aliases": [],
1152
1159
  "args": {},
1153
- "description": "Retrieve and update your local integration files with the latest version.\n\nThis command updates your local integration files with the latest version. You will be prompted with a confirmation dialog before continuing if there any destructive file changes.\n\nZapier may release new versions of your integration with bug fixes or new features. In the event this occurs, you will be unable to do the following until your local files are updated by running `zapier pull`:\n\n* push to the promoted version\n* promote a new version\n* migrate users from one version to another",
1160
+ "description": "Retrieve and update your local integration files with the promoted version (or latest version if not public).\n\nThis command updates your local integration files with the promoted version (or latest version if not public). You will be prompted with a confirmation dialog before continuing if there any destructive file changes.\n\nZapier may release new versions of your integration with bug fixes or new features. In the event this occurs, you will be unable to do the following until your local files are updated by running `zapier pull`:\n\n* push to the promoted version\n* promote a new version\n* migrate users from one version to another",
1154
1161
  "flags": {
1155
1162
  "debug": {
1156
1163
  "char": "d",
@@ -1542,6 +1549,7 @@
1542
1549
  "examples": [
1543
1550
  "zapier validate",
1544
1551
  "zapier validate --without-style",
1552
+ "zapier validate --skip-build",
1545
1553
  "zapier validate --format json"
1546
1554
  ],
1547
1555
  "flags": {
@@ -1551,6 +1559,12 @@
1551
1559
  "allowNo": false,
1552
1560
  "type": "boolean"
1553
1561
  },
1562
+ "skip-build": {
1563
+ "description": "Skip running the _zapier-build script before validation.",
1564
+ "name": "skip-build",
1565
+ "allowNo": false,
1566
+ "type": "boolean"
1567
+ },
1554
1568
  "debug": {
1555
1569
  "char": "d",
1556
1570
  "description": "Show extra debugging output.",
@@ -1705,88 +1719,6 @@
1705
1719
  "clear.js"
1706
1720
  ]
1707
1721
  },
1708
- "delete:integration": {
1709
- "aliases": [
1710
- "delete:app"
1711
- ],
1712
- "args": {},
1713
- "description": "Delete your integration (including all versions).\n\nThis only works if there are no active users or Zaps on any version. If you only want to delete certain versions, use the `zapier delete:version` command instead. It's unlikely that you'll be able to run this on an app that you've pushed publicly, since there are usually still users.",
1714
- "flags": {
1715
- "debug": {
1716
- "char": "d",
1717
- "description": "Show extra debugging output.",
1718
- "name": "debug",
1719
- "allowNo": false,
1720
- "type": "boolean"
1721
- },
1722
- "invokedFromAnotherCommand": {
1723
- "hidden": true,
1724
- "name": "invokedFromAnotherCommand",
1725
- "allowNo": false,
1726
- "type": "boolean"
1727
- }
1728
- },
1729
- "hasDynamicHelp": false,
1730
- "hiddenAliases": [],
1731
- "id": "delete:integration",
1732
- "pluginAlias": "zapier-platform-cli",
1733
- "pluginName": "zapier-platform-cli",
1734
- "pluginType": "core",
1735
- "strict": true,
1736
- "enableJsonFlag": false,
1737
- "skipValidInstallCheck": true,
1738
- "isESM": false,
1739
- "relativePath": [
1740
- "src",
1741
- "oclif",
1742
- "commands",
1743
- "delete",
1744
- "integration.js"
1745
- ]
1746
- },
1747
- "delete:version": {
1748
- "aliases": [],
1749
- "args": {
1750
- "version": {
1751
- "description": "Specify the version to delete. It must have no users or Zaps.",
1752
- "name": "version",
1753
- "required": true
1754
- }
1755
- },
1756
- "description": "Delete a specific version of your integration.\n\nThis only works if there are no users or Zaps on that version. You will probably need to have run `zapier migrate` and `zapier deprecate` before this command will work.",
1757
- "flags": {
1758
- "debug": {
1759
- "char": "d",
1760
- "description": "Show extra debugging output.",
1761
- "name": "debug",
1762
- "allowNo": false,
1763
- "type": "boolean"
1764
- },
1765
- "invokedFromAnotherCommand": {
1766
- "hidden": true,
1767
- "name": "invokedFromAnotherCommand",
1768
- "allowNo": false,
1769
- "type": "boolean"
1770
- }
1771
- },
1772
- "hasDynamicHelp": false,
1773
- "hiddenAliases": [],
1774
- "id": "delete:version",
1775
- "pluginAlias": "zapier-platform-cli",
1776
- "pluginName": "zapier-platform-cli",
1777
- "pluginType": "core",
1778
- "strict": true,
1779
- "enableJsonFlag": false,
1780
- "skipValidInstallCheck": true,
1781
- "isESM": false,
1782
- "relativePath": [
1783
- "src",
1784
- "oclif",
1785
- "commands",
1786
- "delete",
1787
- "version.js"
1788
- ]
1789
- },
1790
1722
  "canary:create": {
1791
1723
  "aliases": [],
1792
1724
  "args": {
@@ -1975,6 +1907,88 @@
1975
1907
  "list.js"
1976
1908
  ]
1977
1909
  },
1910
+ "delete:integration": {
1911
+ "aliases": [
1912
+ "delete:app"
1913
+ ],
1914
+ "args": {},
1915
+ "description": "Delete your integration (including all versions).\n\nThis only works if there are no active users or Zaps on any version. If you only want to delete certain versions, use the `zapier delete:version` command instead. It's unlikely that you'll be able to run this on an app that you've pushed publicly, since there are usually still users.",
1916
+ "flags": {
1917
+ "debug": {
1918
+ "char": "d",
1919
+ "description": "Show extra debugging output.",
1920
+ "name": "debug",
1921
+ "allowNo": false,
1922
+ "type": "boolean"
1923
+ },
1924
+ "invokedFromAnotherCommand": {
1925
+ "hidden": true,
1926
+ "name": "invokedFromAnotherCommand",
1927
+ "allowNo": false,
1928
+ "type": "boolean"
1929
+ }
1930
+ },
1931
+ "hasDynamicHelp": false,
1932
+ "hiddenAliases": [],
1933
+ "id": "delete:integration",
1934
+ "pluginAlias": "zapier-platform-cli",
1935
+ "pluginName": "zapier-platform-cli",
1936
+ "pluginType": "core",
1937
+ "strict": true,
1938
+ "enableJsonFlag": false,
1939
+ "skipValidInstallCheck": true,
1940
+ "isESM": false,
1941
+ "relativePath": [
1942
+ "src",
1943
+ "oclif",
1944
+ "commands",
1945
+ "delete",
1946
+ "integration.js"
1947
+ ]
1948
+ },
1949
+ "delete:version": {
1950
+ "aliases": [],
1951
+ "args": {
1952
+ "version": {
1953
+ "description": "Specify the version to delete. It must have no users or Zaps.",
1954
+ "name": "version",
1955
+ "required": true
1956
+ }
1957
+ },
1958
+ "description": "Delete a specific version of your integration.\n\nThis only works if there are no users or Zaps on that version. You will probably need to have run `zapier migrate` and `zapier deprecate` before this command will work.",
1959
+ "flags": {
1960
+ "debug": {
1961
+ "char": "d",
1962
+ "description": "Show extra debugging output.",
1963
+ "name": "debug",
1964
+ "allowNo": false,
1965
+ "type": "boolean"
1966
+ },
1967
+ "invokedFromAnotherCommand": {
1968
+ "hidden": true,
1969
+ "name": "invokedFromAnotherCommand",
1970
+ "allowNo": false,
1971
+ "type": "boolean"
1972
+ }
1973
+ },
1974
+ "hasDynamicHelp": false,
1975
+ "hiddenAliases": [],
1976
+ "id": "delete:version",
1977
+ "pluginAlias": "zapier-platform-cli",
1978
+ "pluginName": "zapier-platform-cli",
1979
+ "pluginType": "core",
1980
+ "strict": true,
1981
+ "enableJsonFlag": false,
1982
+ "skipValidInstallCheck": true,
1983
+ "isESM": false,
1984
+ "relativePath": [
1985
+ "src",
1986
+ "oclif",
1987
+ "commands",
1988
+ "delete",
1989
+ "version.js"
1990
+ ]
1991
+ },
1978
1992
  "env:get": {
1979
1993
  "aliases": [],
1980
1994
  "args": {
@@ -2151,9 +2165,9 @@
2151
2165
  "unset.js"
2152
2166
  ]
2153
2167
  },
2154
- "users:add": {
2168
+ "team:add": {
2155
2169
  "aliases": [
2156
- "users:invite"
2170
+ "team:invite"
2157
2171
  ],
2158
2172
  "args": {
2159
2173
  "email": {
@@ -2161,24 +2175,28 @@
2161
2175
  "name": "email",
2162
2176
  "required": true
2163
2177
  },
2164
- "version": {
2165
- "description": "A version string (like 1.2.3). Optional, used only if you want to invite a user to a specific version instead of all versions.",
2166
- "name": "version"
2178
+ "role": {
2179
+ "description": "The level the invited team member should be at. Admins can edit everything and get email updates. Collaborators have read-access to the app and get email updates. Subscribers only get email updates.",
2180
+ "name": "role",
2181
+ "options": [
2182
+ "admin",
2183
+ "collaborator",
2184
+ "subscriber"
2185
+ ],
2186
+ "required": true
2187
+ },
2188
+ "message": {
2189
+ "description": "A message sent in the email to your team member, if you need to provide context. Wrap the message in quotes to ensure spaces get saved.",
2190
+ "name": "message"
2167
2191
  }
2168
2192
  },
2169
- "description": "Add a user to some or all versions of your integration.\n\nWhen this command is run, we'll send an email to the user inviting them to try your integration. You can track the status of that invite using the `zapier users:get` command.\n\nInvited users will be able to see your integration's name, logo, and description. They'll also be able to create Zaps using any available triggers and actions.",
2193
+ "description": "Add a team member to your integration.\n\nThese users come in three levels:\n\n * `admin`, who can edit everything about the integration\n * `collaborator`, who has read-only access for the app, and will receive periodic email updates. These updates include quarterly health scores and more.\n * `subscriber`, who can't directly access the app, but will receive periodic email updates. These updates include quarterly health scores and more.\n\nTeam members can be freely added and removed.",
2170
2194
  "examples": [
2171
- "zapier users:add bruce@wayne.com",
2172
- "zapier users:add alfred@wayne.com 1.2.3"
2195
+ "zapier team:add bruce@wayne.com admin",
2196
+ "zapier team:add robin@wayne.com collaborator \"Hey Robin, check out this app.\"",
2197
+ "zapier team:add alfred@wayne.com subscriber \"Hey Alfred, check out this app.\""
2173
2198
  ],
2174
2199
  "flags": {
2175
- "force": {
2176
- "char": "f",
2177
- "description": "Skip confirmation. Useful for running programatically.",
2178
- "name": "force",
2179
- "allowNo": false,
2180
- "type": "boolean"
2181
- },
2182
2200
  "debug": {
2183
2201
  "char": "d",
2184
2202
  "description": "Show extra debugging output.",
@@ -2195,7 +2213,7 @@
2195
2213
  },
2196
2214
  "hasDynamicHelp": false,
2197
2215
  "hiddenAliases": [],
2198
- "id": "users:add",
2216
+ "id": "team:add",
2199
2217
  "pluginAlias": "zapier-platform-cli",
2200
2218
  "pluginName": "zapier-platform-cli",
2201
2219
  "pluginType": "core",
@@ -2207,16 +2225,16 @@
2207
2225
  "src",
2208
2226
  "oclif",
2209
2227
  "commands",
2210
- "users",
2228
+ "team",
2211
2229
  "add.js"
2212
2230
  ]
2213
2231
  },
2214
- "users:get": {
2232
+ "team:get": {
2215
2233
  "aliases": [
2216
- "users:list"
2234
+ "team:list"
2217
2235
  ],
2218
2236
  "args": {},
2219
- "description": "Get a list of users who have been invited to your integration.\n\nNote that this list of users is NOT a comprehensive list of everyone who is using your integration. It only includes users who were invited directly by email (using the `\u001b[36mzapier users:add\u001b[39m` command or the web UI). Users who joined by clicking links generated using the `\u001b[36mzapier user:links\u001b[39m` command won't show up here.",
2237
+ "description": "Get team members involved with your integration.\n\nThese users come in three levels:\n\n * `admin`, who can edit everything about the integration\n * `collaborator`, who has read-only access for the app, and will receive periodic email updates. These updates include quarterly health scores and more.\n * `subscriber`, who can't directly access the app, but will receive periodic email updates. These updates include quarterly health scores and more.\n\nUse the `zapier team:add` and `zapier team:remove` commands to modify your team.\n",
2220
2238
  "flags": {
2221
2239
  "debug": {
2222
2240
  "char": "d",
@@ -2250,7 +2268,7 @@
2250
2268
  },
2251
2269
  "hasDynamicHelp": false,
2252
2270
  "hiddenAliases": [],
2253
- "id": "users:get",
2271
+ "id": "team:get",
2254
2272
  "pluginAlias": "zapier-platform-cli",
2255
2273
  "pluginName": "zapier-platform-cli",
2256
2274
  "pluginType": "core",
@@ -2262,14 +2280,16 @@
2262
2280
  "src",
2263
2281
  "oclif",
2264
2282
  "commands",
2265
- "users",
2283
+ "team",
2266
2284
  "get.js"
2267
2285
  ]
2268
2286
  },
2269
- "users:links": {
2270
- "aliases": [],
2287
+ "team:remove": {
2288
+ "aliases": [
2289
+ "team:delete"
2290
+ ],
2271
2291
  "args": {},
2272
- "description": "Get a list of links that are used to invite users to your integration.",
2292
+ "description": "Remove a team member from all versions of your integration.\n\nAdmins will immediately lose write access to the integration.\nCollaborators will immediately lose read access to the integration.\nSubscribers won't receive future email updates.",
2273
2293
  "flags": {
2274
2294
  "debug": {
2275
2295
  "char": "d",
@@ -2278,22 +2298,6 @@
2278
2298
  "allowNo": false,
2279
2299
  "type": "boolean"
2280
2300
  },
2281
- "format": {
2282
- "char": "f",
2283
- "description": "Change the way structured data is presented. If \"json\" or \"raw\", you can pipe the output of the command into other tools, such as jq.",
2284
- "name": "format",
2285
- "default": "table",
2286
- "hasDynamicHelp": false,
2287
- "multiple": false,
2288
- "options": [
2289
- "plain",
2290
- "json",
2291
- "raw",
2292
- "row",
2293
- "table"
2294
- ],
2295
- "type": "option"
2296
- },
2297
2301
  "invokedFromAnotherCommand": {
2298
2302
  "hidden": true,
2299
2303
  "name": "invokedFromAnotherCommand",
@@ -2303,7 +2307,7 @@
2303
2307
  },
2304
2308
  "hasDynamicHelp": false,
2305
2309
  "hiddenAliases": [],
2306
- "id": "users:links",
2310
+ "id": "team:remove",
2307
2311
  "pluginAlias": "zapier-platform-cli",
2308
2312
  "pluginName": "zapier-platform-cli",
2309
2313
  "pluginType": "core",
@@ -2315,26 +2319,34 @@
2315
2319
  "src",
2316
2320
  "oclif",
2317
2321
  "commands",
2318
- "users",
2319
- "links.js"
2322
+ "team",
2323
+ "remove.js"
2320
2324
  ]
2321
2325
  },
2322
- "users:remove": {
2326
+ "users:add": {
2323
2327
  "aliases": [
2324
- "users:delete"
2328
+ "users:invite"
2325
2329
  ],
2326
2330
  "args": {
2327
2331
  "email": {
2328
- "description": "The user to be removed.",
2332
+ "description": "The user to be invited. If they don't have a Zapier account, they'll be prompted to create one.",
2329
2333
  "name": "email",
2330
2334
  "required": true
2335
+ },
2336
+ "version": {
2337
+ "description": "A version string (like 1.2.3). Optional, used only if you want to invite a user to a specific version instead of all versions.",
2338
+ "name": "version"
2331
2339
  }
2332
2340
  },
2333
- "description": "Remove a user from all versions of your integration.\n\nWhen this command is run, their Zaps will immediately turn off. They won't be able to use your app again until they're re-invited or it has gone public. In practice, this command isn't run often as it's very disruptive to users.",
2341
+ "description": "Add a user to some or all versions of your integration.\n\nWhen this command is run, we'll send an email to the user inviting them to try your integration. You can track the status of that invite using the `zapier users:get` command.\n\nInvited users will be able to see your integration's name, logo, and description. They'll also be able to create Zaps using any available triggers and actions.",
2342
+ "examples": [
2343
+ "zapier users:add bruce@wayne.com",
2344
+ "zapier users:add alfred@wayne.com 1.2.3"
2345
+ ],
2334
2346
  "flags": {
2335
2347
  "force": {
2336
2348
  "char": "f",
2337
- "description": "Skips confirmation. Useful for running programatically.",
2349
+ "description": "Skip confirmation. Useful for running programatically.",
2338
2350
  "name": "force",
2339
2351
  "allowNo": false,
2340
2352
  "type": "boolean"
@@ -2355,7 +2367,7 @@
2355
2367
  },
2356
2368
  "hasDynamicHelp": false,
2357
2369
  "hiddenAliases": [],
2358
- "id": "users:remove",
2370
+ "id": "users:add",
2359
2371
  "pluginAlias": "zapier-platform-cli",
2360
2372
  "pluginName": "zapier-platform-cli",
2361
2373
  "pluginType": "core",
@@ -2368,40 +2380,15 @@
2368
2380
  "oclif",
2369
2381
  "commands",
2370
2382
  "users",
2371
- "remove.js"
2383
+ "add.js"
2372
2384
  ]
2373
2385
  },
2374
- "team:add": {
2386
+ "users:get": {
2375
2387
  "aliases": [
2376
- "team:invite"
2377
- ],
2378
- "args": {
2379
- "email": {
2380
- "description": "The user to be invited. If they don't have a Zapier account, they'll be prompted to create one.",
2381
- "name": "email",
2382
- "required": true
2383
- },
2384
- "role": {
2385
- "description": "The level the invited team member should be at. Admins can edit everything and get email updates. Collaborators have read-access to the app and get email updates. Subscribers only get email updates.",
2386
- "name": "role",
2387
- "options": [
2388
- "admin",
2389
- "collaborator",
2390
- "subscriber"
2391
- ],
2392
- "required": true
2393
- },
2394
- "message": {
2395
- "description": "A message sent in the email to your team member, if you need to provide context. Wrap the message in quotes to ensure spaces get saved.",
2396
- "name": "message"
2397
- }
2398
- },
2399
- "description": "Add a team member to your integration.\n\nThese users come in three levels:\n\n * `admin`, who can edit everything about the integration\n * `collaborator`, who has read-only access for the app, and will receive periodic email updates. These updates include quarterly health scores and more.\n * `subscriber`, who can't directly access the app, but will receive periodic email updates. These updates include quarterly health scores and more.\n\nTeam members can be freely added and removed.",
2400
- "examples": [
2401
- "zapier team:add bruce@wayne.com admin",
2402
- "zapier team:add robin@wayne.com collaborator \"Hey Robin, check out this app.\"",
2403
- "zapier team:add alfred@wayne.com subscriber \"Hey Alfred, check out this app.\""
2388
+ "users:list"
2404
2389
  ],
2390
+ "args": {},
2391
+ "description": "Get a list of users who have been invited to your integration.\n\nNote that this list of users is NOT a comprehensive list of everyone who is using your integration. It only includes users who were invited directly by email (using the `\u001b[36mzapier users:add\u001b[39m` command or the web UI). Users who joined by clicking links generated using the `\u001b[36mzapier user:links\u001b[39m` command won't show up here.",
2405
2392
  "flags": {
2406
2393
  "debug": {
2407
2394
  "char": "d",
@@ -2410,6 +2397,22 @@
2410
2397
  "allowNo": false,
2411
2398
  "type": "boolean"
2412
2399
  },
2400
+ "format": {
2401
+ "char": "f",
2402
+ "description": "Change the way structured data is presented. If \"json\" or \"raw\", you can pipe the output of the command into other tools, such as jq.",
2403
+ "name": "format",
2404
+ "default": "table",
2405
+ "hasDynamicHelp": false,
2406
+ "multiple": false,
2407
+ "options": [
2408
+ "plain",
2409
+ "json",
2410
+ "raw",
2411
+ "row",
2412
+ "table"
2413
+ ],
2414
+ "type": "option"
2415
+ },
2413
2416
  "invokedFromAnotherCommand": {
2414
2417
  "hidden": true,
2415
2418
  "name": "invokedFromAnotherCommand",
@@ -2419,7 +2422,7 @@
2419
2422
  },
2420
2423
  "hasDynamicHelp": false,
2421
2424
  "hiddenAliases": [],
2422
- "id": "team:add",
2425
+ "id": "users:get",
2423
2426
  "pluginAlias": "zapier-platform-cli",
2424
2427
  "pluginName": "zapier-platform-cli",
2425
2428
  "pluginType": "core",
@@ -2431,16 +2434,14 @@
2431
2434
  "src",
2432
2435
  "oclif",
2433
2436
  "commands",
2434
- "team",
2435
- "add.js"
2437
+ "users",
2438
+ "get.js"
2436
2439
  ]
2437
2440
  },
2438
- "team:get": {
2439
- "aliases": [
2440
- "team:list"
2441
- ],
2441
+ "users:links": {
2442
+ "aliases": [],
2442
2443
  "args": {},
2443
- "description": "Get team members involved with your integration.\n\nThese users come in three levels:\n\n * `admin`, who can edit everything about the integration\n * `collaborator`, who has read-only access for the app, and will receive periodic email updates. These updates include quarterly health scores and more.\n * `subscriber`, who can't directly access the app, but will receive periodic email updates. These updates include quarterly health scores and more.\n\nUse the `zapier team:add` and `zapier team:remove` commands to modify your team.\n",
2444
+ "description": "Get a list of links that are used to invite users to your integration.",
2444
2445
  "flags": {
2445
2446
  "debug": {
2446
2447
  "char": "d",
@@ -2474,7 +2475,7 @@
2474
2475
  },
2475
2476
  "hasDynamicHelp": false,
2476
2477
  "hiddenAliases": [],
2477
- "id": "team:get",
2478
+ "id": "users:links",
2478
2479
  "pluginAlias": "zapier-platform-cli",
2479
2480
  "pluginName": "zapier-platform-cli",
2480
2481
  "pluginType": "core",
@@ -2486,17 +2487,30 @@
2486
2487
  "src",
2487
2488
  "oclif",
2488
2489
  "commands",
2489
- "team",
2490
- "get.js"
2490
+ "users",
2491
+ "links.js"
2491
2492
  ]
2492
2493
  },
2493
- "team:remove": {
2494
+ "users:remove": {
2494
2495
  "aliases": [
2495
- "team:delete"
2496
+ "users:delete"
2496
2497
  ],
2497
- "args": {},
2498
- "description": "Remove a team member from all versions of your integration.\n\nAdmins will immediately lose write access to the integration.\nCollaborators will immediately lose read access to the integration.\nSubscribers won't receive future email updates.",
2498
+ "args": {
2499
+ "email": {
2500
+ "description": "The user to be removed.",
2501
+ "name": "email",
2502
+ "required": true
2503
+ }
2504
+ },
2505
+ "description": "Remove a user from all versions of your integration.\n\nWhen this command is run, their Zaps will immediately turn off. They won't be able to use your app again until they're re-invited or it has gone public. In practice, this command isn't run often as it's very disruptive to users.",
2499
2506
  "flags": {
2507
+ "force": {
2508
+ "char": "f",
2509
+ "description": "Skips confirmation. Useful for running programatically.",
2510
+ "name": "force",
2511
+ "allowNo": false,
2512
+ "type": "boolean"
2513
+ },
2500
2514
  "debug": {
2501
2515
  "char": "d",
2502
2516
  "description": "Show extra debugging output.",
@@ -2513,7 +2527,7 @@
2513
2527
  },
2514
2528
  "hasDynamicHelp": false,
2515
2529
  "hiddenAliases": [],
2516
- "id": "team:remove",
2530
+ "id": "users:remove",
2517
2531
  "pluginAlias": "zapier-platform-cli",
2518
2532
  "pluginName": "zapier-platform-cli",
2519
2533
  "pluginType": "core",
@@ -2525,10 +2539,10 @@
2525
2539
  "src",
2526
2540
  "oclif",
2527
2541
  "commands",
2528
- "team",
2542
+ "users",
2529
2543
  "remove.js"
2530
2544
  ]
2531
2545
  }
2532
2546
  },
2533
- "version": "17.6.0"
2547
+ "version": "17.7.1"
2534
2548
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zapier-platform-cli",
3
- "version": "17.6.0",
3
+ "version": "17.7.1",
4
4
  "description": "The CLI for managing integrations in Zapier Developer Platform.",
5
5
  "repository": "zapier/zapier-platform",
6
6
  "homepage": "https://platform.zapier.com/",
@@ -25,16 +25,16 @@
25
25
  "docs": "ZAPIER_BASE_ENDPOINT='' node scripts/docs.js",
26
26
  "preversion": "git pull && yarn validate",
27
27
  "prepack": "oclif manifest",
28
- "postpack": "rm -f oclif.manifest.json",
28
+ "postpack": "rimraf oclif.manifest.json",
29
29
  "precommit": "yarn docs && git add docs",
30
30
  "version": "yarn docs && git add docs/*",
31
31
  "postversion": "git push && git push --tags",
32
32
  "lint": "eslint src",
33
33
  "lint:fix": "eslint --fix src",
34
- "test": "cross-env NODE_ENV=test mocha -t 50s --recursive src/tests --exit",
35
- "test:debug": "cross-env NODE_ENV=test node inspect ../../node_modules/.bin/mocha -t 50s --recursive src/tests --exit",
36
- "smoke-test": "cross-env NODE_ENV=test mocha -t 2m --recursive src/smoke-tests --exit",
37
- "smoke-test:debug": "cross-env NODE_ENV=test node inspect ../../node_modules/.bin/mocha -t 2m --recursive src/smoke-tests --exit",
34
+ "test": "cross-env NODE_ENV=test mocha -t 200s --recursive src/tests --exit",
35
+ "test:debug": "cross-env NODE_ENV=test node inspect ../../node_modules/.bin/mocha -t 200s --recursive src/tests --exit",
36
+ "smoke-test": "cross-env NODE_ENV=test mocha -t 6m --recursive src/smoke-tests --exit",
37
+ "smoke-test:debug": "cross-env NODE_ENV=test node inspect ../../node_modules/.bin/mocha -t 6m --recursive src/smoke-tests --exit",
38
38
  "validate-templates": "./scripts/validate-app-templates.js",
39
39
  "set-template-versions": "./scripts/set-app-template-versions.js",
40
40
  "validate": "yarn test && yarn smoke-test && yarn lint"
@@ -46,12 +46,12 @@
46
46
  "@oclif/plugin-not-found": "3.2.51",
47
47
  "@oclif/plugin-version": "2.2.28",
48
48
  "adm-zip": "0.5.16",
49
- "decompress": "4.2.1",
50
49
  "archiver": "7.0.1",
51
50
  "chrono-node": "2.8.0",
52
51
  "cli-table3": "0.6.5",
53
52
  "colors": "1.4.0",
54
53
  "debug": "4.4.0",
54
+ "decompress": "4.2.1",
55
55
  "dotenv": "16.5.0",
56
56
  "esbuild": "0.25.4",
57
57
  "fs-extra": "11.2.0",
@@ -73,7 +73,7 @@
73
73
  "semver": "7.7.1",
74
74
  "string-length": "4.0.2",
75
75
  "through2": "4.0.2",
76
- "tmp": "0.2.3",
76
+ "tmp": "0.2.4",
77
77
  "traverse": "0.6.11",
78
78
  "update-notifier": "5.1.0",
79
79
  "yeoman-environment": "3.19.3",
@@ -87,6 +87,7 @@
87
87
  "mock-fs": "^5.5.0",
88
88
  "nock": "^14.0.4",
89
89
  "oclif": "^4.17.46",
90
+ "rimraf": "^5.0.10",
90
91
  "typescript": "^5.8.3",
91
92
  "yamljs": "0.3.0"
92
93
  },
@@ -79,6 +79,7 @@ const writeGenericTypeScriptPackageJson = (gen, packageJsonExtension) => {
79
79
  test: 'npm run build && vitest --run',
80
80
  clean: 'rimraf ./dist ./build',
81
81
  build: 'npm run clean && tsc',
82
+ dev: 'npm run build -- --watch',
82
83
  '_zapier-build': 'npm run build',
83
84
  },
84
85
  dependencies: {
@@ -252,13 +253,26 @@ class ProjectGenerator extends Generator {
252
253
 
253
254
  async prompting() {
254
255
  if (!this.options.template) {
256
+ // Filter template choices based on language and module type
257
+ let templateChoices = TEMPLATE_CHOICES;
258
+ let defaultTemplate = 'minimal';
259
+
260
+ // TypeScript filtering takes precedence over ESM filtering
261
+ if (this.options.language === 'typescript') {
262
+ templateChoices = TS_SUPPORTED_TEMPLATES;
263
+ defaultTemplate = 'basic-auth';
264
+ } else if (this.options.module === 'esm') {
265
+ templateChoices = ESM_SUPPORTED_TEMPLATES;
266
+ defaultTemplate = 'minimal'; // minimal is the only ESM template
267
+ }
268
+
255
269
  this.answers = await this.prompt([
256
270
  {
257
271
  type: 'list',
258
272
  name: 'template',
259
- choices: TEMPLATE_CHOICES,
273
+ choices: templateChoices,
260
274
  message: 'Choose a project template to start with:',
261
- default: 'minimal',
275
+ default: defaultTemplate,
262
276
  },
263
277
  ]);
264
278
  this.options.template = this.answers.template;
@@ -320,6 +334,8 @@ class ProjectGenerator extends Generator {
320
334
 
321
335
  module.exports = {
322
336
  TEMPLATE_CHOICES,
337
+ ESM_SUPPORTED_TEMPLATES,
338
+ TS_SUPPORTED_TEMPLATES,
323
339
  PullGenerator,
324
340
  ProjectGenerator,
325
341
  };
@@ -90,9 +90,14 @@ class ZapierBaseCommand extends Command {
90
90
 
91
91
  // validate that user input looks like a semver version
92
92
  throwForInvalidVersion(version) {
93
- if (!version.match(/^\d+\.\d+\.\d+$/g)) {
93
+ if (
94
+ !version.match(
95
+ // this is mirrored in schemas/VersionSchema.js and developer_cli/constants.py
96
+ /^(?:0|[1-9]\d{0,2})\.(?:0|[1-9]\d{0,2})\.(?:0|[1-9]\d{0,2})(?:-(?=.{1,12}$)[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*)?$/g,
97
+ )
98
+ ) {
94
99
  throw new Error(
95
- `${version} is an invalid version str. Try something like \`1.2.3\``,
100
+ `${version} is an invalid version str. Try something like \`1.2.3\` or \`0.0.0-TICKET\``,
96
101
  );
97
102
  }
98
103
  }
@@ -59,7 +59,14 @@ const loadAuthDataFromEnv = () => {
59
59
  .filter(([k, v]) => k.startsWith(AUTH_FIELD_ENV_PREFIX))
60
60
  .reduce((authData, [k, v]) => {
61
61
  const fieldKey = k.substr(AUTH_FIELD_ENV_PREFIX.length);
62
- authData[fieldKey] = v;
62
+ // Try to parse as JSON if it looks like JSON, otherwise keep as string
63
+ try {
64
+ authData[fieldKey] =
65
+ v.startsWith('{') || v.startsWith('[') ? JSON.parse(v) : v;
66
+ } catch (e) {
67
+ // If JSON parsing fails, keep as string
68
+ authData[fieldKey] = v;
69
+ }
63
70
  return authData;
64
71
  }, {});
65
72
  };
@@ -233,12 +240,26 @@ const resolveInputDataTypes = (inputData, inputFields, timezone) => {
233
240
  };
234
241
 
235
242
  const appendEnv = async (vars, prefix = '') => {
236
- await fs.appendFile(
237
- '.env',
238
- Object.entries(vars)
239
- .filter(([k, v]) => v !== undefined)
240
- .map(([k, v]) => `${prefix}${k}='${v || ''}'\n`),
241
- );
243
+ const envFile = '.env';
244
+ let content = Object.entries(vars)
245
+ .filter(([k, v]) => v !== undefined)
246
+ .map(
247
+ ([k, v]) =>
248
+ `${prefix}${k}='${typeof v === 'object' && v !== null ? JSON.stringify(v) : v || ''}'\n`,
249
+ )
250
+ .join('');
251
+
252
+ // Check if .env file exists and doesn't end with newline
253
+ try {
254
+ const existingContent = await fs.readFile(envFile, 'utf8');
255
+ if (existingContent.length > 0 && !existingContent.endsWith('\n')) {
256
+ content = '\n' + content;
257
+ }
258
+ } catch (error) {
259
+ // File doesn't exist or can't be read, proceed as normal
260
+ }
261
+
262
+ await fs.appendFile(envFile, content);
242
263
  };
243
264
 
244
265
  const replaceDoubleCurlies = async (request) => {
@@ -1303,6 +1324,7 @@ class InvokeCommand extends BaseCommand {
1303
1324
  isPopulatingDedupe: this.flags.isPopulatingDedupe,
1304
1325
  limit: this.flags.limit,
1305
1326
  page: this.flags.page,
1327
+ paging_token: this.flags['paging-token'],
1306
1328
  isTestingAuth: false, // legacy property
1307
1329
  };
1308
1330
  const output = await this.invokeAction(
@@ -1382,6 +1404,10 @@ InvokeCommand.flags = buildFlags({
1382
1404
  description:
1383
1405
  'EXPERIMENTAL: Instead of using the local .env file, use the production authentication data with the given authentication ID (aka the "app connection" on Zapier). Find them at https://zapier.com/app/assets/connections (https://zpr.io/z8SjFTdnTFZ2 for instructions) or specify \'-\' to interactively select one from your available authentications. When specified, the code will still run locally, but all outgoing requests will be proxied through Zapier with the production auth data.',
1384
1406
  }),
1407
+ 'paging-token': Flags.string({
1408
+ description:
1409
+ 'Set bundle.meta.paging_token. Used for search pagination or bulk reads. When used in production, this indicates which page of items you should fetch.',
1410
+ }),
1385
1411
  },
1386
1412
  });
1387
1413
 
@@ -1,6 +1,7 @@
1
1
  const _ = require('lodash');
2
2
  const debug = require('debug')('zapier:migrate');
3
3
  const { Args, Flags } = require('@oclif/core');
4
+ const colors = require('colors/safe');
4
5
 
5
6
  const BaseCommand = require('../ZapierBaseCommand');
6
7
  const PromoteCommand = require('./promote');
@@ -118,17 +119,15 @@ class MigrateCommand extends BaseCommand {
118
119
 
119
120
  await this.run_require_confirmation_pre_checks(app, body);
120
121
 
122
+ let message;
121
123
  if (user || account) {
122
- this.startSpinner(
123
- `Starting migration from ${fromVersion} to ${toVersion} for ${
124
- user || account
125
- }`,
126
- );
124
+ message = `Requesting migration from ${fromVersion} to ${toVersion} for ${user || account}`;
127
125
  } else {
128
- this.startSpinner(
129
- `Starting migration from ${fromVersion} to ${toVersion} for ${percent}%`,
130
- );
126
+ message = `Requesting migration from ${fromVersion} to ${toVersion} for ${percent}%`;
131
127
  }
128
+
129
+ this.startSpinner(message);
130
+
132
131
  if (percent) {
133
132
  body.job.percent_human = percent;
134
133
  }
@@ -137,12 +136,14 @@ class MigrateCommand extends BaseCommand {
137
136
 
138
137
  try {
139
138
  await callAPI(url, { method: 'POST', body });
140
- } finally {
141
- this.stopSpinner();
139
+ } catch (err) {
140
+ this.stopSpinner({ success: false });
141
+ throw err;
142
142
  }
143
+ this.stopSpinner();
143
144
 
144
145
  this.log(
145
- '\nMigration successfully queued, please check `zapier jobs` to track the status. Migrations usually take between 5-10 minutes.',
146
+ `\nMigration successfully queued, check ${colors.bold.underline('zapier jobs')} to track the status. Migrations usually take between 5-10 minutes.`,
146
147
  );
147
148
  }
148
149
  }
@@ -6,10 +6,18 @@ const yeoman = require('yeoman-environment');
6
6
  const ZapierBaseCommand = require('../ZapierBaseCommand');
7
7
  const { downloadSourceZip } = require('../../utils/api');
8
8
  const { ensureDir, makeTempDir, removeDirSync } = require('../../utils/files');
9
- const { listFiles } = require('../../utils/build');
9
+ const { walkDirWithPresetBlocklist } = require('../../utils/build');
10
10
  const { buildFlags } = require('../buildFlags');
11
11
  const PullGenerator = require('../../generators/pull');
12
12
 
13
+ const listFiles = (dir) => {
14
+ const relPaths = [];
15
+ for (const entry of walkDirWithPresetBlocklist(dir)) {
16
+ relPaths.push(path.join(path.relative(dir, entry.parentPath), entry.name));
17
+ }
18
+ return relPaths;
19
+ };
20
+
13
21
  class PullCommand extends ZapierBaseCommand {
14
22
  async perform() {
15
23
  // Fetch the source zip from API
@@ -28,7 +36,7 @@ class PullCommand extends ZapierBaseCommand {
28
36
 
29
37
  // Prompt user to confirm overwrite
30
38
  const currentDir = process.cwd();
31
- const sourceFiles = await listFiles(srcDst);
39
+ const sourceFiles = listFiles(srcDst);
32
40
 
33
41
  const env = yeoman.createEnv();
34
42
  const namespace = 'zapier:pull';
@@ -45,9 +53,9 @@ class PullCommand extends ZapierBaseCommand {
45
53
  }
46
54
 
47
55
  PullCommand.flags = buildFlags();
48
- PullCommand.description = `Retrieve and update your local integration files with the latest version.
56
+ PullCommand.description = `Retrieve and update your local integration files with the promoted version (or latest version if not public).
49
57
 
50
- This command updates your local integration files with the latest version. You will be prompted with a confirmation dialog before continuing if there any destructive file changes.
58
+ This command updates your local integration files with the promoted version (or latest version if not public). You will be prompted with a confirmation dialog before continuing if there any destructive file changes.
51
59
 
52
60
  Zapier may release new versions of your integration with bug fixes or new features. In the event this occurs, you will be unable to do the following until your local files are updated by running \`zapier pull\`:
53
61
 
@@ -1,4 +1,3 @@
1
- /* eslint-disable camelcase */
2
1
  // @ts-check
3
2
 
4
3
  const path = require('path');
@@ -6,9 +6,14 @@ const { buildFlags } = require('../buildFlags');
6
6
  const { flattenCheckResult } = require('../../utils/display');
7
7
  const { localAppCommand } = require('../../utils/local');
8
8
  const { validateApp } = require('../../utils/api');
9
+ const { maybeRunBuildScript } = require('../../utils/build');
9
10
 
10
11
  class ValidateCommand extends BaseCommand {
11
12
  async perform() {
13
+ if (!this.flags['skip-build']) {
14
+ await maybeRunBuildScript({ printProgress: true });
15
+ }
16
+
12
17
  this.log('Validating project locally');
13
18
 
14
19
  const errors = await localAppCommand({ command: 'validate' });
@@ -121,6 +126,9 @@ ValidateCommand.flags = buildFlags({
121
126
  'without-style': Flags.boolean({
122
127
  description: 'Forgo pinging the Zapier server to run further checks.',
123
128
  }),
129
+ 'skip-build': Flags.boolean({
130
+ description: 'Skip running the _zapier-build script before validation.',
131
+ }),
124
132
  },
125
133
  opts: {
126
134
  format: true,
@@ -130,6 +138,7 @@ ValidateCommand.flags = buildFlags({
130
138
  ValidateCommand.examples = [
131
139
  'zapier validate',
132
140
  'zapier validate --without-style',
141
+ 'zapier validate --skip-build',
133
142
  'zapier validate --format json',
134
143
  ];
135
144
  ValidateCommand.description = `Validate your integration.
@@ -51,7 +51,7 @@ const recordAnalytics = async (command, isValidCommand, args, flags) => {
51
51
  numArgs: argKeys.length,
52
52
  appId: linkedAppId,
53
53
  argsKeys: argKeys,
54
- flagKeys: flagKeys,
54
+ flagKeys,
55
55
  cliVersion: pkg.version,
56
56
  os: shouldRecordAnonymously ? undefined : process.platform,
57
57
  };
package/src/utils/ast.js CHANGED
@@ -115,17 +115,23 @@ const registerActionInJsApp = (codeStr, property, varName) => {
115
115
 
116
116
  // check if this object already has the property at the top level
117
117
  const existingProp = objToModify.properties.find(
118
- (props) => props.key.name === property,
118
+ (props) => props.key && props.key.name === property,
119
119
  );
120
120
  if (existingProp) {
121
- // `triggers: myTriggers` means we shouldn't bother
122
121
  const value = existingProp.value;
123
- if (value.type !== 'ObjectExpression') {
122
+ if (value.type === 'Identifier') {
123
+ // Handle shorthand syntax like `creates` instead of `creates: { ... }`
124
+ // Transform it into an object with spread operator: `creates: { ...creates, [newAction.key]: newAction }`
125
+ const spreadProperty = j.spreadElement(j.identifier(value.name));
126
+ existingProp.value = j.objectExpression([spreadProperty, newProperty]);
127
+ existingProp.shorthand = false; // Disable shorthand since we're changing the value
128
+ } else if (value.type === 'ObjectExpression') {
129
+ value.properties.push(newProperty);
130
+ } else {
124
131
  throw new Error(
125
132
  `Tried to edit the ${property} key, but the value wasn't an object`,
126
133
  );
127
134
  }
128
- value.properties.push(newProperty);
129
135
  } else {
130
136
  objToModify.properties.push(
131
137
  j.property(
@@ -209,16 +215,23 @@ const registerActionInTsApp = (codeStr, actionTypePlural, identifierName) => {
209
215
 
210
216
  // Check if this object already has the actionType group inside it.
211
217
  const existingProp = appObj.properties.find(
212
- (props) => props.key.name === actionTypePlural,
218
+ (props) => props.key && props.key.name === actionTypePlural,
213
219
  );
214
220
  if (existingProp) {
215
221
  const value = existingProp.value;
216
- if (value.type !== 'ObjectExpression') {
222
+ if (value.type === 'Identifier') {
223
+ // Handle shorthand syntax like `creates` instead of `creates: { ... }`
224
+ // Transform it into an object with spread operator: `creates: { ...creates, [newAction.key]: newAction }`
225
+ const spreadProperty = j.spreadElement(j.identifier(value.name));
226
+ existingProp.value = j.objectExpression([spreadProperty, newProperty]);
227
+ existingProp.shorthand = false; // Disable shorthand since we're changing the value
228
+ } else if (value.type === 'ObjectExpression') {
229
+ value.properties.push(newProperty);
230
+ } else {
217
231
  throw new Error(
218
232
  `Tried to edit the ${actionTypePlural} key, but the value wasn't an object`,
219
233
  );
220
234
  }
221
- value.properties.push(newProperty);
222
235
  } else {
223
236
  appObj.properties.push(
224
237
  j.property(
@@ -272,13 +272,28 @@ const countLeadingDoubleDots = (relPath) => {
272
272
  // Join all relPaths with workingDir and return the common ancestor directory.
273
273
  const findCommonAncestor = (workingDir, relPaths) => {
274
274
  let maxLeadingDoubleDots = 0;
275
- for (const relPath of relPaths) {
276
- maxLeadingDoubleDots = Math.max(
277
- maxLeadingDoubleDots,
278
- countLeadingDoubleDots(relPath),
279
- );
280
- }
281
275
 
276
+ if (isWindows()) {
277
+ for (const relPath of relPaths) {
278
+ if (relPath.match(/^[a-zA-Z]:/)) {
279
+ // On Windows, relPath can be absolute if it starts with a different
280
+ // drive letter than workingDir.
281
+ return 'C:\\';
282
+ } else {
283
+ maxLeadingDoubleDots = Math.max(
284
+ maxLeadingDoubleDots,
285
+ countLeadingDoubleDots(relPath),
286
+ );
287
+ }
288
+ }
289
+ } else {
290
+ for (const relPath of relPaths) {
291
+ maxLeadingDoubleDots = Math.max(
292
+ maxLeadingDoubleDots,
293
+ countLeadingDoubleDots(relPath),
294
+ );
295
+ }
296
+ }
282
297
  let commonAncestor = workingDir;
283
298
  for (let i = 0; i < maxLeadingDoubleDots; i++) {
284
299
  commonAncestor = path.dirname(commonAncestor);
@@ -286,6 +301,10 @@ const findCommonAncestor = (workingDir, relPaths) => {
286
301
  return commonAncestor;
287
302
  };
288
303
 
304
+ const stripDriveLetterForZip = (pathStr) => {
305
+ return pathStr.replace(/^[cC]:\\/, '').replace(/^([a-zA-Z]):/, '$1');
306
+ };
307
+
289
308
  const writeBuildZipDumbly = async (workingDir, zip) => {
290
309
  for (const entry of walkDirWithPresetBlocklist(workingDir)) {
291
310
  const absPath = path.resolve(entry.parentPath, entry.name);
@@ -350,7 +369,7 @@ const writeBuildZipSmartly = async (workingDir, zip) => {
350
369
  // Write required files to the zip
351
370
  for (const relPath of relPaths) {
352
371
  const absPath = path.resolve(workingDir, relPath);
353
- const nameInZip = path.relative(zipRoot, absPath);
372
+ const nameInZip = stripDriveLetterForZip(path.relative(zipRoot, absPath));
354
373
  if (nameInZip === 'package.json' && zipRoot !== workingDir) {
355
374
  // Ignore workspace root's package.json
356
375
  continue;
@@ -388,10 +407,10 @@ const writeBuildZipSmartly = async (workingDir, zip) => {
388
407
  symlink.parentPath,
389
408
  symlink.name,
390
409
  );
391
- const nameInZip = path.relative(zipRoot, absPath);
410
+ const nameInZip = stripDriveLetterForZip(path.relative(zipRoot, absPath));
392
411
  const targetInZip = path.relative(
393
- symlink.parentPath,
394
- fs.realpathSync(absPath),
412
+ stripDriveLetterForZip(symlink.parentPath),
413
+ stripDriveLetterForZip(fs.realpathSync(absPath)),
395
414
  );
396
415
  zip.symlink(nameInZip, targetInZip, 0o644);
397
416
  }
@@ -126,6 +126,16 @@ const writeTemplateFile = async ({
126
126
  const getRelativeRequirePath = (entryFilePath, newFilePath) =>
127
127
  path.relative(path.dirname(entryFilePath), newFilePath);
128
128
 
129
+ /**
130
+ * Detect if a JavaScript file uses ES Module syntax (export default) vs CommonJS (module.exports)
131
+ * @param {string} codeStr - The JavaScript code to check
132
+ * @returns {boolean} - True if the file uses ESM syntax
133
+ */
134
+ const isEsmJavaScript = (codeStr) => {
135
+ // Look for export default statement
136
+ return /^\s*export\s+default\s/m.test(codeStr);
137
+ };
138
+
129
139
  const isValidEntryFileUpdate = (
130
140
  language,
131
141
  indexFileResolved,
@@ -193,16 +203,32 @@ const updateEntryFileJs = async ({
193
203
  let codeStr = (await readFile(indexFileResolved)).toString();
194
204
  const originalCodeStr = codeStr; // untouched copy in case we need to bail
195
205
 
196
- codeStr = importActionInJsApp(
197
- codeStr,
198
- actionImportName,
199
- actionRelativeImportPath,
200
- );
201
- codeStr = registerActionInJsApp(
202
- codeStr,
203
- plural(actionType),
204
- actionImportName,
205
- );
206
+ // Check if this JavaScript file uses ESM syntax (export default)
207
+ // If so, use the TypeScript functions which handle ESM correctly
208
+ if (isEsmJavaScript(codeStr)) {
209
+ codeStr = importActionInTsApp(
210
+ codeStr,
211
+ actionImportName,
212
+ actionRelativeImportPath,
213
+ );
214
+ codeStr = registerActionInTsApp(
215
+ codeStr,
216
+ plural(actionType),
217
+ actionImportName,
218
+ );
219
+ } else {
220
+ // Use traditional CommonJS functions for module.exports
221
+ codeStr = importActionInJsApp(
222
+ codeStr,
223
+ actionImportName,
224
+ actionRelativeImportPath,
225
+ );
226
+ codeStr = registerActionInJsApp(
227
+ codeStr,
228
+ plural(actionType),
229
+ actionImportName,
230
+ );
231
+ }
206
232
  await writeFile(indexFileResolved, codeStr);
207
233
  return originalCodeStr;
208
234
  };
@@ -283,11 +309,22 @@ const createScaffoldingContext = ({
283
309
  )}.test.${language}`;
284
310
  const testFileLocal = `${path.join(testDirLocal, key)}.${language}`;
285
311
  const testFileLocalStem = path.join(testDirLocal, key);
286
- const actionRelativeImportPath = `./${getRelativeRequirePath(
312
+
313
+ // Generate the relative import path
314
+ let actionRelativeImportPath = `./${getRelativeRequirePath(
287
315
  indexFileResolved,
288
316
  actionFileResolvedStem,
289
317
  )}`;
290
318
 
319
+ // Normalize path separators to forward slashes for import statements
320
+ // (ES modules always use forward slashes, regardless of OS)
321
+ actionRelativeImportPath = actionRelativeImportPath.replace(/\\/g, '/');
322
+
323
+ // For TypeScript with ESM, imports must use .js extension
324
+ if (language === 'ts') {
325
+ actionRelativeImportPath += '.js';
326
+ }
327
+
291
328
  return {
292
329
  actionType,
293
330
  actionTypePlural: plural(actionType),
@@ -324,6 +361,7 @@ module.exports = {
324
361
  updateEntryFile,
325
362
  isValidEntryFileUpdate,
326
363
  writeTemplateFile,
364
+ isEsmJavaScript,
327
365
  };
328
366
 
329
367
  /**