Repository: cloudflare/cloudflare-go
Pull request #1490 (2024-01-30 12:04:54)

ZRZ-1097 deprecate neoEvents array on Zaraz config tools
Per new Zaraz api & docs, `neoEvents` array is being replaced with the more semantic `Actions` object on configured Zaraz tools.

All existing Zaraz configs will be automatically migrated to the new schema; similarly, any new config imports / updates containing deprecated neoEvents will be migrated before saving. I.e. old config schema in --> newer config schema out.

## Has your change been tested? ✅

## Types of changes

What sort of change does your code introduce/modify?

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)

## Checklist:

- [x] My code follows the code style of this project.
- [x] My change requires a change to the documentation.
- [x] I have updated the documentation accordingly.
- [x] I have added tests to cover my changes.
- [x] All new and existing tests passed.
- [x] This change is using publicly documented in [cloudflare/api-schemas](https://github.com/cloudflare/api-schemas) 
      and relies on stable APIs.

[1]: https://help.github.com/articles/closing-issues-using-keywords/



Patch:
diff --git a/.changelog/1386.txt b/.changelog/1386.txt
deleted file mode 100644
index 64d0db476..000000000
--- a/.changelog/1386.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-```release-note:enhancement
-streams: adds support for stream create parameters for tus upload initiate
-```
diff --git a/.changelog/1468.txt b/.changelog/1468.txt
deleted file mode 100644
index 3c91f6401..000000000
--- a/.changelog/1468.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-```release-note:enhancement
-logpush: Add support for Output Options
-```
diff --git a/.changelog/1482.txt b/.changelog/1482.txt
deleted file mode 100644
index 54712fef4..000000000
--- a/.changelog/1482.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-```release-note:bug
-access_users: ListAccessUsers was returning wrong values in pointer fields due to variable missused in loop
-```
diff --git a/.changelog/1486.txt b/.changelog/1486.txt
deleted file mode 100644
index b1da4b5a8..000000000
--- a/.changelog/1486.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-```release-note:enhancement
-teams_accounts: add support for extended email matching
-```
diff --git a/.changelog/1490.txt b/.changelog/1490.txt
new file mode 100644
index 000000000..20f833089
--- /dev/null
+++ b/.changelog/1490.txt
@@ -0,0 +1,3 @@
+```release-note:note
+zaraz: replace deprecated neoEvents with Actions on Zaraz Config tools schema
+```
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
new file mode 100644
index 000000000..39f43fba4
--- /dev/null
+++ b/.github/workflows/coverage.yml
@@ -0,0 +1,19 @@
+on: [pull_request]
+name: Coverage
+jobs:
+  coverage:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v4
+      - uses: actions/setup-go@v5
+        with:
+          go-version-file: 'go.mod'
+      - uses: actions/cache@v4
+        with:
+          path: ~/go/pkg/mod
+          key: ${{ runner.os }}-go-${{ hashFiles('**/go.mod') }}-${{ hashFiles('**/go.sum') }}
+      - name: Run coverage
+        run: go test ./... -coverprofile=coverage.txt -covermode=atomic
+      - name: Upload coverage to Codecov
+        uses: codecov/codecov-action@v4.0.0-beta.3
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 25f604c81..31cd7c6da 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,13 +3,9 @@
 ENHANCEMENTS:
 
 * dlp: add support for EDM and CWL datasets ([#1485](https://github.com/cloudflare/cloudflare-go/issues/1485))
-* logpush: Add support for Output Options ([#1468](https://github.com/cloudflare/cloudflare-go/issues/1468))
-* streams: adds support for stream create parameters for tus upload initiate ([#1386](https://github.com/cloudflare/cloudflare-go/issues/1386))
-* teams_accounts: add support for extended email matching ([#1486](https://github.com/cloudflare/cloudflare-go/issues/1486))
 
 BUG FIXES:
 
-* access_users: ListAccessUsers was returning wrong values in pointer fields due to variable missused in loop ([#1482](https://github.com/cloudflare/cloudflare-go/issues/1482))
 * flarectl: alias zone certs to "ct" instead of duplicating the "c" alias ([#1484](https://github.com/cloudflare/cloudflare-go/issues/1484))
 
 DEPENDENCIES:
diff --git a/access_users.go b/access_users.go
index 233ceb2bb..690bc446e 100644
--- a/access_users.go
+++ b/access_users.go
@@ -223,7 +223,7 @@ func (api *API) ListAccessUsers(ctx context.Context, rc *ResourceContainer, para
 	}
 
 	var accessUsers []AccessUser
-	var resultInfo *ResultInfo = nil
+	var r AccessUserListResponse
 
 	for {
 		uri := buildURI(baseURL, params)
@@ -231,8 +231,6 @@ func (api *API) ListAccessUsers(ctx context.Context, rc *ResourceContainer, para
 		if err != nil {
 			return []AccessUser{}, &ResultInfo{}, fmt.Errorf("%s: %w", errMakeRequestError, err)
 		}
-		var r AccessUserListResponse
-		resultInfo = &r.ResultInfo
 
 		err = json.Unmarshal(res, &r)
 		if err != nil {
@@ -245,7 +243,7 @@ func (api *API) ListAccessUsers(ctx context.Context, rc *ResourceContainer, para
 		}
 	}
 
-	return accessUsers, resultInfo, nil
+	return accessUsers, &r.ResultInfo, nil
 }
 
 // GetAccessUserActiveSessions returns a list of active sessions for an user.
diff --git a/docs/conventions.md b/docs/conventions.md
index acbe2fabb..7cd018949 100644
--- a/docs/conventions.md
+++ b/docs/conventions.md
@@ -5,7 +5,7 @@ making changes the Go SDK.
 
 ## Methods
 
-- All methods should take a maximum of 3 parameter. See examples in [experimental](./experimental.md)
+- All methods should take a maxium of 3 parameter. See examples in [experimental](./experimental.md)
 - The first parameter is always `context.Context`.
 - The second is a `*ResourceContainer`.
 - The final is a struct of available parameters for the method. 
diff --git a/logpush.go b/logpush.go
index 34e32e9cb..3fbb1af50 100644
--- a/logpush.go
+++ b/logpush.go
@@ -12,23 +12,22 @@ import (
 
 // LogpushJob describes a Logpush job.
 type LogpushJob struct {
-	ID                       int                   `json:"id,omitempty"`
-	Dataset                  string                `json:"dataset"`
-	Enabled                  bool                  `json:"enabled"`
-	Kind                     string                `json:"kind,omitempty"`
-	Name                     string                `json:"name"`
-	LogpullOptions           string                `json:"logpull_options,omitempty"`
-	OutputOptions            *LogpushOutputOptions `json:"output_options,omitempty"`
-	DestinationConf          string                `json:"destination_conf"`
-	OwnershipChallenge       string                `json:"ownership_challenge,omitempty"`
-	LastComplete             *time.Time            `json:"last_complete,omitempty"`
-	LastError                *time.Time            `json:"last_error,omitempty"`
-	ErrorMessage             string                `json:"error_message,omitempty"`
-	Frequency                string                `json:"frequency,omitempty"`
-	Filter                   *LogpushJobFilters    `json:"filter,omitempty"`
-	MaxUploadBytes           int                   `json:"max_upload_bytes,omitempty"`
-	MaxUploadRecords         int                   `json:"max_upload_records,omitempty"`
-	MaxUploadIntervalSeconds int                   `json:"max_upload_interval_seconds,omitempty"`
+	ID                       int                `json:"id,omitempty"`
+	Dataset                  string             `json:"dataset"`
+	Enabled                  bool               `json:"enabled"`
+	Kind                     string             `json:"kind,omitempty"`
+	Name                     string             `json:"name"`
+	LogpullOptions           string             `json:"logpull_options"`
+	DestinationConf          string             `json:"destination_conf"`
+	OwnershipChallenge       string             `json:"ownership_challenge,omitempty"`
+	LastComplete             *time.Time         `json:"last_complete,omitempty"`
+	LastError                *time.Time         `json:"last_error,omitempty"`
+	ErrorMessage             string             `json:"error_message,omitempty"`
+	Frequency                string             `json:"frequency,omitempty"`
+	Filter                   *LogpushJobFilters `json:"filter,omitempty"`
+	MaxUploadBytes           int                `json:"max_upload_bytes,omitempty"`
+	MaxUploadRecords         int                `json:"max_upload_records,omitempty"`
+	MaxUploadIntervalSeconds int                `json:"max_upload_interval_seconds,omitempty"`
 }
 
 type LogpushJobFilters struct {
@@ -64,21 +63,6 @@ type LogpushJobFilter struct {
 	Value    interface{} `json:"value,omitempty"`
 }
 
-type LogpushOutputOptions struct {
-	FieldNames      []string `json:"field_names"`
-	OutputType      string   `json:"output_type,omitempty"`
-	BatchPrefix     string   `json:"batch_prefix,omitempty"`
-	BatchSuffix     string   `json:"batch_suffix,omitempty"`
-	RecordPrefix    string   `json:"record_prefix,omitempty"`
-	RecordSuffix    string   `json:"record_suffix,omitempty"`
-	RecordTemplate  string   `json:"record_template,omitempty"`
-	RecordDelimiter string   `json:"record_delimiter,omitempty"`
-	FieldDelimiter  string   `json:"field_delimiter,omitempty"`
-	TimestampFormat string   `json:"timestamp_format,omitempty"`
-	SampleRate      float64  `json:"sample_rate,omitempty"`
-	CVE202144228    *bool    `json:"CVE-2021-44228,omitempty"`
-}
-
 // LogpushJobsResponse is the API response, containing an array of Logpush Jobs.
 type LogpushJobsResponse struct {
 	Response
@@ -339,20 +323,19 @@ func (filter *LogpushJobFilter) Validate() error {
 }
 
 type CreateLogpushJobParams struct {
-	Dataset                  string                `json:"dataset"`
-	Enabled                  bool                  `json:"enabled"`
-	Kind                     string                `json:"kind,omitempty"`
-	Name                     string                `json:"name"`
-	LogpullOptions           string                `json:"logpull_options,omitempty"`
-	OutputOptions            *LogpushOutputOptions `json:"output_options,omitempty"`
-	DestinationConf          string                `json:"destination_conf"`
-	OwnershipChallenge       string                `json:"ownership_challenge,omitempty"`
-	ErrorMessage             string                `json:"error_message,omitempty"`
-	Frequency                string                `json:"frequency,omitempty"`
-	Filter                   *LogpushJobFilters    `json:"filter,omitempty"`
-	MaxUploadBytes           int                   `json:"max_upload_bytes,omitempty"`
-	MaxUploadRecords         int                   `json:"max_upload_records,omitempty"`
-	MaxUploadIntervalSeconds int                   `json:"max_upload_interval_seconds,omitempty"`
+	Dataset                  string             `json:"dataset"`
+	Enabled                  bool               `json:"enabled"`
+	Kind                     string             `json:"kind,omitempty"`
+	Name                     string             `json:"name"`
+	LogpullOptions           string             `json:"logpull_options"`
+	DestinationConf          string             `json:"destination_conf"`
+	OwnershipChallenge       string             `json:"ownership_challenge,omitempty"`
+	ErrorMessage             string             `json:"error_message,omitempty"`
+	Frequency                string             `json:"frequency,omitempty"`
+	Filter                   *LogpushJobFilters `json:"filter,omitempty"`
+	MaxUploadBytes           int                `json:"max_upload_bytes,omitempty"`
+	MaxUploadRecords         int                `json:"max_upload_records,omitempty"`
+	MaxUploadIntervalSeconds int                `json:"max_upload_interval_seconds,omitempty"`
 }
 
 type ListLogpushJobsParams struct{}
@@ -366,23 +349,22 @@ type GetLogpushFieldsParams struct {
 }
 
 type UpdateLogpushJobParams struct {
-	ID                       int                   `json:"-"`
-	Dataset                  string                `json:"dataset"`
-	Enabled                  bool                  `json:"enabled"`
-	Kind                     string                `json:"kind,omitempty"`
-	Name                     string                `json:"name"`
-	LogpullOptions           string                `json:"logpull_options,omitempty"`
-	OutputOptions            *LogpushOutputOptions `json:"output_options,omitempty"`
-	DestinationConf          string                `json:"destination_conf"`
-	OwnershipChallenge       string                `json:"ownership_challenge,omitempty"`
-	LastComplete             *time.Time            `json:"last_complete,omitempty"`
-	LastError                *time.Time            `json:"last_error,omitempty"`
-	ErrorMessage             string                `json:"error_message,omitempty"`
-	Frequency                string                `json:"frequency,omitempty"`
-	Filter                   *LogpushJobFilters    `json:"filter,omitempty"`
-	MaxUploadBytes           int                   `json:"max_upload_bytes,omitempty"`
-	MaxUploadRecords         int                   `json:"max_upload_records,omitempty"`
-	MaxUploadIntervalSeconds int                   `json:"max_upload_interval_seconds,omitempty"`
+	ID                       int                `json:"-"`
+	Dataset                  string             `json:"dataset"`
+	Enabled                  bool               `json:"enabled"`
+	Kind                     string             `json:"kind,omitempty"`
+	Name                     string             `json:"name"`
+	LogpullOptions           string             `json:"logpull_options"`
+	DestinationConf          string             `json:"destination_conf"`
+	OwnershipChallenge       string             `json:"ownership_challenge,omitempty"`
+	LastComplete             *time.Time         `json:"last_complete,omitempty"`
+	LastError                *time.Time         `json:"last_error,omitempty"`
+	ErrorMessage             string             `json:"error_message,omitempty"`
+	Frequency                string             `json:"frequency,omitempty"`
+	Filter                   *LogpushJobFilters `json:"filter,omitempty"`
+	MaxUploadBytes           int                `json:"max_upload_bytes,omitempty"`
+	MaxUploadRecords         int                `json:"max_upload_records,omitempty"`
+	MaxUploadIntervalSeconds int                `json:"max_upload_interval_seconds,omitempty"`
 }
 
 type ValidateLogpushOwnershipChallengeParams struct {
diff --git a/stream.go b/stream.go
index 388064996..ebb175cb8 100644
--- a/stream.go
+++ b/stream.go
@@ -209,12 +209,10 @@ type StreamInitiateTUSUploadResponse struct {
 
 type TUSUploadMetadata struct {
 	Name                  string     `json:"name,omitempty"`
-	MaxDurationSeconds    int        `json:"maxDurationSeconds,omitempty"`
 	RequireSignedURLs     bool       `json:"requiresignedurls,omitempty"`
 	AllowedOrigins        string     `json:"allowedorigins,omitempty"`
 	ThumbnailTimestampPct float64    `json:"thumbnailtimestamppct,omitempty"`
 	ScheduledDeletion     *time.Time `json:"scheduledDeletion,omitempty"`
-	Expiry                *time.Time `json:"expiry,omitempty"`
 	Watermark             string     `json:"watermark,omitempty"`
 }
 
@@ -223,9 +221,6 @@ func (t TUSUploadMetadata) ToTUSCsv() (string, error) {
 	if t.Name != "" {
 		metadataValues = append(metadataValues, fmt.Sprintf("%s %s", "name", base64.StdEncoding.EncodeToString([]byte(t.Name))))
 	}
-	if t.MaxDurationSeconds != 0 {
-		metadataValues = append(metadataValues, fmt.Sprintf("%s %s", "maxDurationSeconds", base64.StdEncoding.EncodeToString([]byte(strconv.Itoa(t.MaxDurationSeconds)))))
-	}
 	if t.RequireSignedURLs {
 		metadataValues = append(metadataValues, "requiresignedurls")
 	}
@@ -238,9 +233,6 @@ func (t TUSUploadMetadata) ToTUSCsv() (string, error) {
 	if t.ScheduledDeletion != nil {
 		metadataValues = append(metadataValues, fmt.Sprintf("%s %s", "scheduledDeletion", base64.StdEncoding.EncodeToString([]byte(t.ScheduledDeletion.Format(time.RFC3339)))))
 	}
-	if t.Expiry != nil {
-		metadataValues = append(metadataValues, fmt.Sprintf("%s %s", "expiry", base64.StdEncoding.EncodeToString([]byte(t.Expiry.Format(time.RFC3339)))))
-	}
 	if t.Watermark != "" {
 		metadataValues = append(metadataValues, fmt.Sprintf("%s %s", "watermark", base64.StdEncoding.EncodeToString([]byte(t.Watermark))))
 	}
diff --git a/teams_accounts.go b/teams_accounts.go
index 90ae7d347..15665e04f 100644
--- a/teams_accounts.go
+++ b/teams_accounts.go
@@ -37,15 +37,14 @@ type TeamsConfiguration struct {
 }
 
 type TeamsAccountSettings struct {
-	Antivirus             *TeamsAntivirus             `json:"antivirus,omitempty"`
-	TLSDecrypt            *TeamsTLSDecrypt            `json:"tls_decrypt,omitempty"`
-	ActivityLog           *TeamsActivityLog           `json:"activity_log,omitempty"`
-	BlockPage             *TeamsBlockPage             `json:"block_page,omitempty"`
-	BrowserIsolation      *BrowserIsolation           `json:"browser_isolation,omitempty"`
-	FIPS                  *TeamsFIPS                  `json:"fips,omitempty"`
-	ProtocolDetection     *TeamsProtocolDetection     `json:"protocol_detection,omitempty"`
-	BodyScanning          *TeamsBodyScanning          `json:"body_scanning,omitempty"`
-	ExtendedEmailMatching *TeamsExtendedEmailMatching `json:"extended_email_matching,omitempty"`
+	Antivirus         *TeamsAntivirus         `json:"antivirus,omitempty"`
+	TLSDecrypt        *TeamsTLSDecrypt        `json:"tls_decrypt,omitempty"`
+	ActivityLog       *TeamsActivityLog       `json:"activity_log,omitempty"`
+	BlockPage         *TeamsBlockPage         `json:"block_page,omitempty"`
+	BrowserIsolation  *BrowserIsolation       `json:"browser_isolation,omitempty"`
+	FIPS              *TeamsFIPS              `json:"fips,omitempty"`
+	ProtocolDetection *TeamsProtocolDetection `json:"protocol_detection,omitempty"`
+	BodyScanning      *TeamsBodyScanning      `json:"body_scanning,omitempty"`
 }
 
 type BrowserIsolation struct {
@@ -98,10 +97,6 @@ type TeamsBodyScanning struct {
 	InspectionMode TeamsInspectionMode `json:"inspection_mode,omitempty"`
 }
 
-type TeamsExtendedEmailMatching struct {
-	Enabled *bool `json:"enabled,omitempty"`
-}
-
 type TeamsRuleType = string
 
 const (
diff --git a/zaraz.go b/zaraz.go
index dedfdc4c9..3ffc4f5ed 100644
--- a/zaraz.go
+++ b/zaraz.go
@@ -44,6 +44,7 @@ type ZarazConfigSettings struct {
 	ContextEnricher     ZarazWorker `json:"contextEnricher,omitempty"`
 }
 
+// Deprecated: To be removed pending migration of existing configs.
 type ZarazNeoEvent struct {
 	BlockingTriggers []string       `json:"blockingTriggers"`
 	FiringTriggers   []string       `json:"firingTriggers"`
@@ -51,6 +52,13 @@ type ZarazNeoEvent struct {
 	ActionType       string         `json:"actionType,omitempty"`
 }
 
+type ZarazAction struct {
+	BlockingTriggers []string       `json:"blockingTriggers"`
+	FiringTriggers   []string       `json:"firingTriggers"`
+	Data             map[string]any `json:"data"`
+	ActionType       string         `json:"actionType,omitempty"`
+}
+
 type ZarazToolType string
 
 const (
@@ -60,18 +68,19 @@ const (
 )
 
 type ZarazTool struct {
-	BlockingTriggers []string        `json:"blockingTriggers"`
-	Enabled          *bool           `json:"enabled"`
-	DefaultFields    map[string]any  `json:"defaultFields"`
-	Name             string          `json:"name"`
-	NeoEvents        []ZarazNeoEvent `json:"neoEvents"`
-	Type             ZarazToolType   `json:"type"`
-	DefaultPurpose   string          `json:"defaultPurpose,omitempty"`
-	Library          string          `json:"library,omitempty"`
-	Component        string          `json:"component,omitempty"`
-	Permissions      []string        `json:"permissions,omitempty"`
-	Settings         map[string]any  `json:"settings,omitempty"`
-	Worker           ZarazWorker     `json:"worker,omitempty"`
+	BlockingTriggers []string               `json:"blockingTriggers"`
+	Enabled          *bool                  `json:"enabled"`
+	DefaultFields    map[string]any         `json:"defaultFields"`
+	Name             string                 `json:"name"`
+	NeoEvents        []ZarazNeoEvent        `json:"neoEvents"`
+	Actions          map[string]ZarazAction `json:"actions"`
+	Type             ZarazToolType          `json:"type"`
+	DefaultPurpose   string                 `json:"defaultPurpose,omitempty"`
+	Library          string                 `json:"library,omitempty"`
+	Component        string                 `json:"component,omitempty"`
+	Permissions      []string               `json:"permissions"`
+	Settings         map[string]any         `json:"settings"`
+	Worker           ZarazWorker            `json:"worker,omitempty"`
 }
 
 type ZarazTriggerSystem string


Test patch:
diff --git a/access_users_test.go b/access_users_test.go
index dd24d3f1f..0d2e4bee0 100644
--- a/access_users_test.go
+++ b/access_users_test.go
@@ -2,7 +2,6 @@ package cloudflare
 
 import (
 	"context"
-	"encoding/json"
 	"fmt"
 	"net/http"
 	"testing"
@@ -14,33 +13,18 @@ var (
 	testAccessUserID        = "access-user-id"
 	testAccessUserSessionID = "access-user-session-id"
 
-	expectedListAccessUserResult = []AccessUser{
-		{
-			AccessSeat:          BoolPtr(false),
-			ActiveDeviceCount:   2,
-			CreatedAt:           "2014-01-01T05:20:00.12345Z",
-			Email:               "jdoe@example.com",
-			GatewaySeat:         BoolPtr(false),
-			ID:                  "f3b12456-80dd-4e89-9f5f-ba3dfff12365",
-			LastSuccessfulLogin: "2020-07-01T05:20:00Z",
-			Name:                "Jane Doe",
-			SeatUID:             "",
-			UID:                 "",
-			UpdatedAt:           "2014-01-01T05:20:00.12345Z",
-		},
-		{
-			AccessSeat:          BoolPtr(true),
-			ActiveDeviceCount:   2,
-			CreatedAt:           "2024-01-01T05:20:00.12345Z",
-			Email:               "jhondoe@example.com",
-			GatewaySeat:         BoolPtr(true),
-			ID:                  "c3b12456-80dd-4e89-9f5f-ba3dfff12367",
-			LastSuccessfulLogin: "2020-07-01T05:20:00Z",
-			Name:                "Jhon Doe",
-			SeatUID:             "",
-			UID:                 "",
-			UpdatedAt:           "2014-01-01T05:20:00.12345Z",
-		},
+	expectedListAccessUserResult = AccessUser{
+		AccessSeat:          BoolPtr(false),
+		ActiveDeviceCount:   2,
+		CreatedAt:           "2014-01-01T05:20:00.12345Z",
+		Email:               "jdoe@example.com",
+		GatewaySeat:         BoolPtr(false),
+		ID:                  "f3b12456-80dd-4e89-9f5f-ba3dfff12365",
+		LastSuccessfulLogin: "2020-07-01T05:20:00Z",
+		Name:                "Jane Doe",
+		SeatUID:             "",
+		UID:                 "",
+		UpdatedAt:           "2014-01-01T05:20:00.12345Z",
 	}
 
 	expectedGetAccessUserActiveSessionsResult = AccessUserActiveSessionResult{
@@ -233,68 +217,41 @@ func TestListAccessUsers(t *testing.T) {
 	handler := func(w http.ResponseWriter, r *http.Request) {
 		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
 		w.Header().Set("content-type", "application/json")
-		userList, err := json.Marshal(expectedListAccessUserResult)
-		assert.NoError(t, err, "Error marshaling expectedListAccessUserResult")
-
 		fmt.Fprintf(w, `{
 			"errors": [],
 			"messages": [],
-			"result": %s,
+			"result": [
+			  {
+				"access_seat": false,
+				"active_device_count": 2,
+				"created_at": "2014-01-01T05:20:00.12345Z",
+				"email": "jdoe@example.com",
+				"gateway_seat": false,
+				"id": "f3b12456-80dd-4e89-9f5f-ba3dfff12365",
+				"last_successful_login": "2020-07-01T05:20:00Z",
+				"name": "Jane Doe",
+				"seat_uid": null,
+				"uid": null,
+				"updated_at": "2014-01-01T05:20:00.12345Z"
+			  }
+			],
 			"success": true,
 			"result_info": {
-			  "count": 2,
+			  "count": 1,
 			  "page": 1,
 			  "per_page": 100,
-			  "total_count": 2
+			  "total_count": 1
 			}
-		  }`, string(userList))
-	}
-	mux.HandleFunc("/accounts/"+testAccountID+"/access/users", handler)
-
-	actual, _, err := client.ListAccessUsers(context.Background(), testAccountRC, AccessUserParams{})
-
-	if assert.NoError(t, err) {
-		assert.Equal(t, expectedListAccessUserResult, actual)
+		  }
+		`)
 	}
-}
 
-func TestListAccessUsersWithPagination(t *testing.T) {
-	setup()
-	defer teardown()
-	// page 1 of 2
-	page := 1
-
-	handler := func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-
-		userList, err := json.Marshal(expectedListAccessUserResult)
-		assert.NoError(t, err, "Error marshaling expectedListAccessUserResult")
-
-		fmt.Fprintf(w, `{
-			"errors": [],
-			"messages": [],
-			"result": %s,
-			"success": true,
-			"result_info": {
-			  "count": 2,
-			  "page": %d,
-			  "per_page": 2,
-			  "total_count": 4
-			}
-		  }`, string(userList), page)
-		// increment page for the next call
-		page++
-	}
 	mux.HandleFunc("/accounts/"+testAccountID+"/access/users", handler)
 
 	actual, _, err := client.ListAccessUsers(context.Background(), testAccountRC, AccessUserParams{})
-	expected := []AccessUser{}
-	// two pages of the same expectedResult
-	expected = append(expected, expectedListAccessUserResult...)
-	expected = append(expected, expectedListAccessUserResult...)
+
 	if assert.NoError(t, err) {
-		assert.Equal(t, expected, actual)
+		assert.Equal(t, []AccessUser{expectedListAccessUserResult}, actual)
 	}
 }
 
diff --git a/logpush_test.go b/logpush_test.go
index f0872c624..72d97578e 100644
--- a/logpush_test.go
+++ b/logpush_test.go
@@ -32,28 +32,6 @@ const (
 	"frequency": "high",
 	"max_upload_bytes": 5000000
   }
-`
-	serverLogpushJobWithOutputOptionsDescription = `{
-	"id": %d,
-	"dataset": "http_requests",
-	"kind": "",
-	"enabled": false,
-	"name": "example.com",
-	"output_options": {
-		"field_names":[
-			"RayID",
-			"ClientIP",
-			"EdgeStartTimestamp"
-		],
-		"timestamp_format": "rfc3339"
-	},
-	"destination_conf": "s3://mybucket/logs?region=us-west-2",
-	"last_complete": "%[2]s",
-	"last_error": "%[2]s",
-	"error_message": "test",
-	"frequency": "high",
-	"max_upload_bytes": 5000000
-  }
 `
 	serverEdgeLogpushJobDescription = `{
 	"id": %d,
@@ -98,26 +76,6 @@ var (
 		Frequency:       "high",
 		MaxUploadBytes:  5000000,
 	}
-	expectedLogpushJobWithOutputOptionsStruct = LogpushJob{
-		ID:      jobID,
-		Dataset: "http_requests",
-		Enabled: false,
-		Name:    "example.com",
-		OutputOptions: &LogpushOutputOptions{
-			FieldNames: []string{
-				"RayID",
-				"ClientIP",
-				"EdgeStartTimestamp",
-			},
-			TimestampFormat: "rfc3339",
-		},
-		DestinationConf: "s3://mybucket/logs?region=us-west-2",
-		LastComplete:    &testLogpushTimestamp,
-		LastError:       &testLogpushTimestamp,
-		ErrorMessage:    "test",
-		Frequency:       "high",
-		MaxUploadBytes:  5000000,
-	}
 	expectedEdgeLogpushJobStruct = LogpushJob{
 		ID:              jobID,
 		Dataset:         "http_requests",
@@ -180,10 +138,6 @@ func TestGetLogpushJob(t *testing.T) {
 			result: serverLogpushJobDescription,
 			want:   expectedLogpushJobStruct,
 		},
-		"core logpush job with output options": {
-			result: serverLogpushJobWithOutputOptionsDescription,
-			want:   expectedLogpushJobWithOutputOptionsStruct,
-		},
 		"edge logpush job": {
 			result: serverEdgeLogpushJobDescription,
 			want:   expectedEdgeLogpushJobStruct,
@@ -244,40 +198,6 @@ func TestCreateLogpushJob(t *testing.T) {
 			result: serverLogpushJobDescription,
 			want:   expectedLogpushJobStruct,
 		},
-		"core logpush job with output options": {
-			newJob: CreateLogpushJobParams{
-				Dataset: "http_requests",
-				Enabled: false,
-				Name:    "example.com",
-				OutputOptions: &LogpushOutputOptions{
-					FieldNames: []string{
-						"RayID",
-						"ClientIP",
-						"EdgeStartTimestamp",
-					},
-					TimestampFormat: "rfc3339",
-				},
-				DestinationConf:  "s3://mybucket/logs?region=us-west-2",
-				MaxUploadRecords: 1000,
-			},
-			payload: `{
-				"dataset": "http_requests",
-				"enabled":false,
-				"name":"example.com",
-				"output_options": {
-					"field_names":[
-						"RayID",
-						"ClientIP",
-						"EdgeStartTimestamp"
-					],
-					"timestamp_format": "rfc3339"
-				},
-				"destination_conf":"s3://mybucket/logs?region=us-west-2",
-				"max_upload_records": 1000
-			}`,
-			result: serverLogpushJobWithOutputOptionsDescription,
-			want:   expectedLogpushJobWithOutputOptionsStruct,
-		},
 		"edge logpush job": {
 			newJob: CreateLogpushJobParams{
 				Dataset:         "http_requests",
diff --git a/stream_test.go b/stream_test.go
index 510e2bb5a..fec0d4cc0 100644
--- a/stream_test.go
+++ b/stream_test.go
@@ -581,21 +581,10 @@ func TestStream_TUSUploadMetadataToTUSCsv(t *testing.T) {
 	assert.NoError(t, err)
 	assert.Equal(t, "name dGVzdC5tcDQ=,requiresignedurls,allowedorigins ZXhhbXBsZS5jb20=,thumbnailtimestamppct MC41,scheduledDeletion MjAyMy0xMC0wMVQwMjoyMDowMFo=", csv)
 
-	expiry, _ := time.Parse(time.RFC3339, "2023-09-25T02:45:00Z")
-	md.Expiry = &expiry
-	csv, err = md.ToTUSCsv()
-	assert.NoError(t, err)
-	assert.Equal(t, "name dGVzdC5tcDQ=,requiresignedurls,allowedorigins ZXhhbXBsZS5jb20=,thumbnailtimestamppct MC41,scheduledDeletion MjAyMy0xMC0wMVQwMjoyMDowMFo=,expiry MjAyMy0wOS0yNVQwMjo0NTowMFo=", csv)
-
 	md.Watermark = "watermark-profile-uid"
 	csv, err = md.ToTUSCsv()
 	assert.NoError(t, err)
-	assert.Equal(t, "name dGVzdC5tcDQ=,requiresignedurls,allowedorigins ZXhhbXBsZS5jb20=,thumbnailtimestamppct MC41,scheduledDeletion MjAyMy0xMC0wMVQwMjoyMDowMFo=,expiry MjAyMy0wOS0yNVQwMjo0NTowMFo=,watermark d2F0ZXJtYXJrLXByb2ZpbGUtdWlk", csv)
-
-	md.MaxDurationSeconds = 300
-	csv, err = md.ToTUSCsv()
-	assert.NoError(t, err)
-	assert.Equal(t, "name dGVzdC5tcDQ=,maxDurationSeconds MzAw,requiresignedurls,allowedorigins ZXhhbXBsZS5jb20=,thumbnailtimestamppct MC41,scheduledDeletion MjAyMy0xMC0wMVQwMjoyMDowMFo=,expiry MjAyMy0wOS0yNVQwMjo0NTowMFo=,watermark d2F0ZXJtYXJrLXByb2ZpbGUtdWlk", csv)
+	assert.Equal(t, "name dGVzdC5tcDQ=,requiresignedurls,allowedorigins ZXhhbXBsZS5jb20=,thumbnailtimestamppct MC41,scheduledDeletion MjAyMy0xMC0wMVQwMjoyMDowMFo=,watermark d2F0ZXJtYXJrLXByb2ZpbGUtdWlk", csv)
 
 	// empty metadata should return empty string
 	md = TUSUploadMetadata{}
diff --git a/teams_accounts_test.go b/teams_accounts_test.go
index 010e0059e..dfd236d3e 100644
--- a/teams_accounts_test.go
+++ b/teams_accounts_test.go
@@ -85,9 +85,6 @@ func TestTeamsAccountConfiguration(t *testing.T) {
           				},
 					"body_scanning": {
 						"inspection_mode": "deep"
-					},
-					"extended_email_matching": {
-						"enabled": true
 					}
 				}
 			}
@@ -123,9 +120,6 @@ func TestTeamsAccountConfiguration(t *testing.T) {
 				UrlBrowserIsolationEnabled: BoolPtr(true),
 				NonIdentityEnabled:         BoolPtr(true),
 			},
-			ExtendedEmailMatching: &TeamsExtendedEmailMatching{
-				Enabled: BoolPtr(true),
-			},
 		})
 	}
 }
@@ -154,9 +148,6 @@ func TestTeamsAccountUpdateConfiguration(t *testing.T) {
 					},
 					"protocol_detection": {
 						"enabled": true
-					},
-					"extended_email_matching": {
-						"enabled": true
 					}
 				}
 			}
@@ -169,9 +160,6 @@ func TestTeamsAccountUpdateConfiguration(t *testing.T) {
 		ActivityLog:       &TeamsActivityLog{Enabled: true},
 		TLSDecrypt:        &TeamsTLSDecrypt{Enabled: true},
 		ProtocolDetection: &TeamsProtocolDetection{Enabled: true},
-		ExtendedEmailMatching: &TeamsExtendedEmailMatching{
-			Enabled: BoolPtr(true),
-		},
 	}
 
 	mux.HandleFunc("/accounts/"+testAccountID+"/gateway/configuration", handler)
diff --git a/zaraz_test.go b/zaraz_test.go
index a59115e3e..0087c9334 100644
--- a/zaraz_test.go
+++ b/zaraz_test.go
@@ -30,8 +30,8 @@ var expectedConfig ZarazConfig = ZarazConfig{
 			Enabled:          &trueValue,
 			DefaultFields:    map[string]any{},
 			Name:             "Custom HTML",
-			NeoEvents: []ZarazNeoEvent{
-				{
+			Actions: map[string]ZarazAction{
+				"7ccae28d-5e00-4f0b-a491-519ecde998c8": {
 					ActionType:       "event",
 					BlockingTriggers: []string{},
 					Data: map[string]any{
@@ -179,19 +179,19 @@ func TestGetZarazConfig(t *testing.T) {
 					  "trigger": "pageload"
 					},
 					"name": "Custom HTML",
-					"neoEvents": [
-					  {
-						"actionType": "event",
-						"blockingTriggers": [],
-						"data": {
-						  "__zaraz_setting_name": "pageview1",
-						  "htmlCode": "<script>console.log('pageview')</script>"
-						},
-						"firingTriggers": [
-						  "Pageview"
-						]
+					"actions": {
+					  "7ccae28d-5e00-4f0b-a491-519ecde998c8": {
+							"actionType": "event",
+							"blockingTriggers": [],
+							"data": {
+								"__zaraz_setting_name": "pageview1",
+								"htmlCode": "<script>console.log('pageview')</script>"
+							},
+							"firingTriggers": [
+								"Pageview"
+							]
 					  }
-					],
+					},
 					"permissions": [
 					  "execute_unsafe_scripts"
 					],
@@ -340,19 +340,274 @@ func TestUpdateZarazConfig(t *testing.T) {
 					  "trigger": "pageload"
 					},
 					"name": "Custom HTML",
-					"neoEvents": [
+					"actions": {
+					  "7ccae28d-5e00-4f0b-a491-519ecde998c8": {
+							"actionType": "event",
+							"blockingTriggers": [],
+							"data": {
+								"__zaraz_setting_name": "pageview1",
+								"htmlCode": "<script>console.log('pageview')</script>"
+							},
+							"firingTriggers": [
+								"Pageview"
+							]
+					  }
+					},
+					"permissions": [
+					  "execute_unsafe_scripts"
+					],
+					"settings": {},
+					"type": "component"
+				  }
+				},
+				"triggers": {
+				  "Pageview": {
+					"clientRules": [],
+					"description": "All page loads",
+					"excludeRules": [],
+					"loadRules": [
 					  {
-						"actionType": "event",
-						"blockingTriggers": [],
-						"data": {
-						  "__zaraz_setting_name": "pageview1",
-						  "htmlCode": "<script>console.log('pageview')</script>"
-						},
-						"firingTriggers": [
-						  "Pageview"
-						]
+						"match": "{{ client.__zarazTrack }}",
+						"op": "EQUALS",
+						"value": "Pageview"
+					  }
+					],
+					"name": "Pageview",
+					"system": "pageload"
+				  },
+				  "TFOl": {
+					"description": "",
+					"excludeRules": [],
+					"loadRules": [
+					  {
+						"id": "Kqsc",
+						"match": "test",
+						"op": "CONTAINS",
+						"value": "test"
+					  },
+					  {
+						"action": "clickListener",
+						"id": "EDnV",
+						"settings": {
+						  "selector": "test",
+						  "type": "css",
+						  "waitForTags": 0
+						}
 					  }
 					],
+					"name": "test"
+				  }
+				},
+				"variables": {
+				  "jwIx": {
+					"name": "test",
+					"type": "string",
+					"value": "sss"
+				  },
+				  "pAuL": {
+					"name": "test-worker-var",
+					"type": "worker",
+					"value": {
+					  "escapedWorkerName": "worker-var-example",
+					  "mutableId": "m.zpt3q__WyW-61WM2qwgGoBl4Nxg-sfBsaMhu9NayjwU",
+					  "workerTag": "68aba570db9d4ec5b159624e2f7ad8bf"
+					}
+				  }
+				},
+				"zarazVersion": 44
+			  }
+		}`)
+	}
+
+	mux.HandleFunc("/zones/"+testZoneID+"/settings/zaraz/v2/config", handler)
+	payload := UpdateZarazConfigParams{
+		DebugKey:      "cheese",
+		ZarazVersion:  44,
+		DataLayer:     &trueValue,
+		Dlp:           []any{},
+		HistoryChange: &trueValue,
+		Settings: ZarazConfigSettings{
+			AutoInjectScript: &trueValue,
+		},
+		Tools: map[string]ZarazTool{
+			"PBQr": {
+				BlockingTriggers: []string{},
+				Enabled:          &trueValue,
+				DefaultFields:    map[string]any{},
+				Name:             "Custom HTML",
+				Actions: map[string]ZarazAction{
+					"7ccae28d-5e00-4f0b-a491-519ecde998c8": {
+						ActionType:       "event",
+						BlockingTriggers: []string{},
+						Data: map[string]any{
+							"__zaraz_setting_name": "pageview1",
+							"htmlCode":             "<script>console.log('pageview')</script>",
+						},
+						FiringTriggers: []string{"Pageview"},
+					},
+				},
+				Type:           ZarazToolComponent,
+				DefaultPurpose: "rJJC",
+				Component:      "html",
+				Permissions:    []string{"execute_unsafe_scripts"},
+				Settings:       map[string]any{},
+			},
+		},
+		Triggers: map[string]ZarazTrigger{
+			"Pageview": {
+				Name:         "Pageview",
+				Description:  "All page loads",
+				LoadRules:    []ZarazTriggerRule{{Match: "{{ client.__zarazTrack }}", Op: "EQUALS", Value: "Pageview"}},
+				ExcludeRules: []ZarazTriggerRule{},
+				ClientRules:  []any{},
+				System:       ZarazPageload,
+			},
+			"TFOl": {
+				Name:         "test",
+				Description:  "",
+				LoadRules:    []ZarazTriggerRule{{Id: "Kqsc", Match: "test", Op: "CONTAINS", Value: "test"}, {Id: "EDnV", Action: ZarazClickListener, Settings: ZarazRuleSettings{Selector: "test", Type: ZarazCSS}}},
+				ExcludeRules: []ZarazTriggerRule{},
+			},
+		},
+		Variables: map[string]ZarazVariable{
+			"jwIx": {
+				Name:  "test",
+				Type:  ZarazVarString,
+				Value: "sss",
+			},
+			"pAuL": {
+				Name: "test-worker-var",
+				Type: ZarazVarWorker,
+				Value: map[string]interface{}{
+					"escapedWorkerName": "worker-var-example",
+					"mutableId":         "m.zpt3q__WyW-61WM2qwgGoBl4Nxg-sfBsaMhu9NayjwU",
+					"workerTag":         "68aba570db9d4ec5b159624e2f7ad8bf",
+				},
+			},
+		},
+		Consent: ZarazConsent{
+			Enabled: &trueValue,
+			ButtonTextTranslations: ZarazButtonTextTranslations{
+				AcceptAll:        map[string]string{"en": "Accept ALL"},
+				ConfirmMyChoices: map[string]string{"en": "YES!"},
+				RejectAll:        map[string]string{"en": "Reject ALL"},
+			},
+			CompanyEmail:                          "email@example.com",
+			ConsentModalIntroHTMLWithTranslations: map[string]string{"en": "Lorem ipsum dolar set Amet?"},
+			CookieName:                            "zaraz-consent",
+			CustomCSS:                             ".test {\n    color: red;\n}",
+			CustomIntroDisclaimerDismissed:        &trueValue,
+			DefaultLanguage:                       "en",
+			HideModal:                             &falseValue,
+			PurposesWithTranslations: map[string]ZarazPurposeWithTranslations{
+				"rJJC": {
+					Description: map[string]string{"en": "Blah blah"},
+					Name:        map[string]string{"en": "Analytics"},
+					Order:       0,
+				},
+			},
+		},
+	}
+	payload.DebugKey = "butter" // Updating config
+	modifiedConfig := expectedConfig
+	modifiedConfig.DebugKey = "butter" // Updating config
+	expected := ZarazConfigResponse{
+		Result: modifiedConfig,
+	}
+
+	actual, err := client.UpdateZarazConfig(context.Background(), ZoneIdentifier(testZoneID), payload)
+	require.NoError(t, err)
+
+	assert.Equal(t, expected.Result, actual.Result)
+}
+
+func TestUpdateDeprecatedZarazConfig(t *testing.T) {
+	setup()
+	defer teardown()
+
+	handler := func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method)
+
+		w.Header().Set("content-type", "application/json")
+		fmt.Fprint(w, `{
+			"errors": [],
+			"messages": [],
+			"success": true,
+			"result": {
+				"consent": {
+				  "buttonTextTranslations": {
+					"accept_all": {
+					  "en": "Accept ALL"
+					},
+					"confirm_my_choices": {
+					  "en": "YES!"
+					},
+					"reject_all": {
+					  "en": "Reject ALL"
+					}
+				  },
+				  "companyEmail": "email@example.com",
+				  "consentModalIntroHTMLWithTranslations": {
+					"en": "Lorem ipsum dolar set Amet?"
+				  },
+				  "cookieName": "zaraz-consent",
+				  "customCSS": ".test {\n    color: red;\n}",
+				  "customIntroDisclaimerDismissed": true,
+				  "defaultLanguage": "en",
+				  "enabled": true,
+				  "hideModal": false,
+				  "purposesWithTranslations": {
+					"rJJC": {
+					  "description": {
+						"en": "Blah blah"
+					  },
+					  "name": {
+						"en": "Analytics"
+					  },
+					  "order": 0
+					}
+				  }
+				},
+				"dataLayer": true,
+				"debugKey": "butter",
+				"dlp": [],
+				"historyChange": true,
+				"invalidKey": "cheese",
+				"settings": {
+				  "autoInjectScript": true
+				},
+				"tools": {
+				  "PBQr": {
+					"blockingTriggers": [],
+					"component": "html",
+					"defaultFields": {},
+					"defaultPurpose": "rJJC",
+					"enabled": true,
+					"mode": {
+					  "cloud": false,
+					  "ignoreSPA": true,
+					  "light": false,
+					  "sample": false,
+					  "segment": {
+						"end": 100,
+						"start": 0
+					  },
+					  "trigger": "pageload"
+					},
+					"name": "Custom HTML",
+					"actions": {
+					  "7ccae28d-5e00-4f0b-a491-519ecde998c8": {
+							"actionType": "event",
+							"blockingTriggers": [],
+							"data": {
+								"__zaraz_setting_name": "pageview1",
+								"htmlCode": "<script>console.log('pageview')</script>"
+							},
+							"firingTriggers": [
+								"Pageview"
+							]
+					  }
+					},
 					"permissions": [
 					  "execute_unsafe_scripts"
 					],
@@ -435,8 +690,8 @@ func TestUpdateZarazConfig(t *testing.T) {
 				Enabled:          &trueValue,
 				DefaultFields:    map[string]any{},
 				Name:             "Custom HTML",
-				NeoEvents: []ZarazNeoEvent{
-					{
+				Actions: map[string]ZarazAction{
+					"7ccae28d-5e00-4f0b-a491-519ecde998c8": {
 						ActionType:       "event",
 						BlockingTriggers: []string{},
 						Data: map[string]any{